mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-08-08 15:00:15 -03:00
feat(recipes): wire recipes layout switch event and rebuild
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
import { showToast } from '../utils/uiHelpers.js';
|
import { showToast } from '../utils/uiHelpers.js';
|
||||||
import { RecipeCard } from './RecipeCard.js';
|
import { RecipeCard } from './RecipeCard.js';
|
||||||
import { state, getCurrentPageState } from '../state/index.js';
|
import { state, getCurrentPageState } from '../state/index.js';
|
||||||
|
import { recreateVirtualScroll } from '../utils/infiniteScroll.js';
|
||||||
|
|
||||||
export class DuplicatesManager {
|
export class DuplicatesManager {
|
||||||
constructor(recipeManager) {
|
constructor(recipeManager) {
|
||||||
@@ -96,6 +97,12 @@ export class DuplicatesManager {
|
|||||||
|
|
||||||
// Re-enable virtual scrolling
|
// Re-enable virtual scrolling
|
||||||
state.virtualScroller.enable();
|
state.virtualScroller.enable();
|
||||||
|
|
||||||
|
// Apply a layout switch that was deferred while duplicates mode was active
|
||||||
|
if (state.pendingLayoutRecreate) {
|
||||||
|
state.pendingLayoutRecreate = false;
|
||||||
|
recreateVirtualScroll('recipes');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderDuplicateGroups() {
|
renderDuplicateGroups() {
|
||||||
|
|||||||
@@ -1017,6 +1017,12 @@ export class SettingsManager {
|
|||||||
displayDensitySelect.value = state.global.settings.display_density || 'default';
|
displayDensitySelect.value = state.global.settings.display_density || 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set recipes layout setting
|
||||||
|
const recipesLayoutSelect = document.getElementById('recipesLayout');
|
||||||
|
if (recipesLayoutSelect) {
|
||||||
|
recipesLayoutSelect.value = state.global.settings.recipes_layout || 'grid';
|
||||||
|
}
|
||||||
|
|
||||||
// Set card info display setting
|
// Set card info display setting
|
||||||
const cardInfoDisplaySelect = document.getElementById('cardInfoDisplay');
|
const cardInfoDisplaySelect = document.getElementById('cardInfoDisplay');
|
||||||
if (cardInfoDisplaySelect) {
|
if (cardInfoDisplaySelect) {
|
||||||
@@ -2288,6 +2294,13 @@ export class SettingsManager {
|
|||||||
// Apply frontend settings immediately
|
// Apply frontend settings immediately
|
||||||
this.applyFrontendSettings();
|
this.applyFrontendSettings();
|
||||||
|
|
||||||
|
// Dispatch layout change event; the scroller instance is about to be rebuilt,
|
||||||
|
// so calculateLayout() must NOT run on the old instance here
|
||||||
|
if (settingKey === 'recipes_layout') {
|
||||||
|
window.dispatchEvent(new CustomEvent('lm:recipes-layout-changed'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Recalculate layout when display density changes
|
// Recalculate layout when display density changes
|
||||||
if (settingKey === 'display_density' && state.virtualScroller) {
|
if (settingKey === 'display_density' && state.virtualScroller) {
|
||||||
state.virtualScroller.calculateLayout();
|
state.virtualScroller.calculateLayout();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { state, getCurrentPageState } from './state/index.js';
|
|||||||
import { getStorageItem, setStorageItem, getSessionItem, removeSessionItem } from './utils/storageHelpers.js';
|
import { getStorageItem, setStorageItem, getSessionItem, removeSessionItem } from './utils/storageHelpers.js';
|
||||||
import { RecipeContextMenu } from './components/ContextMenu/index.js';
|
import { RecipeContextMenu } from './components/ContextMenu/index.js';
|
||||||
import { DuplicatesManager } from './components/DuplicatesManager.js';
|
import { DuplicatesManager } from './components/DuplicatesManager.js';
|
||||||
import { refreshVirtualScroll } from './utils/infiniteScroll.js';
|
import { refreshVirtualScroll, recreateVirtualScroll } from './utils/infiniteScroll.js';
|
||||||
import { refreshRecipes, RecipeSidebarApiClient } from './api/recipeApi.js';
|
import { refreshRecipes, RecipeSidebarApiClient } from './api/recipeApi.js';
|
||||||
import { sidebarManager } from './components/SidebarManager.js';
|
import { sidebarManager } from './components/SidebarManager.js';
|
||||||
import { initSortDropdown } from './components/controls/SortDropdown.js';
|
import { initSortDropdown } from './components/controls/SortDropdown.js';
|
||||||
@@ -272,6 +272,20 @@ class RecipeManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rebuild the scroller on layout switch; in duplicates mode defer until
|
||||||
|
// exitDuplicateMode re-enables the scroller (direct recreation would dispose
|
||||||
|
// the old instance while initializeVirtualScroll skips duplicates mode)
|
||||||
|
window.addEventListener('lm:recipes-layout-changed', () => {
|
||||||
|
const pageState = getCurrentPageState();
|
||||||
|
if (pageState.duplicatesMode) {
|
||||||
|
state.pendingLayoutRecreate = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (typeof recreateVirtualScroll === 'function') {
|
||||||
|
recreateVirtualScroll('recipes');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Initialize dropdown functionality for refresh button
|
// Initialize dropdown functionality for refresh button
|
||||||
this.initDropdowns();
|
this.initDropdowns();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -501,3 +501,33 @@ describe('SettingsManager library controls', () => {
|
|||||||
expect(document.getElementById('exampleImagesUriTemplateSetting').style.display).toBe('none');
|
expect(document.getElementById('exampleImagesUriTemplateSetting').style.display).toBe('none');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('SettingsManager recipes layout switch', () => {
|
||||||
|
it('dispatches lm:recipes-layout-changed without recalculating the old scroller', async () => {
|
||||||
|
const manager = createManager();
|
||||||
|
const select = document.createElement('select');
|
||||||
|
select.id = 'recipesLayout';
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = 'masonry';
|
||||||
|
select.appendChild(option);
|
||||||
|
select.value = 'masonry';
|
||||||
|
document.body.appendChild(select);
|
||||||
|
|
||||||
|
const calculateLayout = vi.fn();
|
||||||
|
state.virtualScroller = { calculateLayout };
|
||||||
|
|
||||||
|
const dispatchSpy = vi.spyOn(window, 'dispatchEvent');
|
||||||
|
|
||||||
|
await manager.saveSelectSetting('recipesLayout', 'recipes_layout');
|
||||||
|
|
||||||
|
const layoutEvent = dispatchSpy.mock.calls
|
||||||
|
.map(([event]) => event)
|
||||||
|
.find(event => event.type === 'lm:recipes-layout-changed');
|
||||||
|
expect(layoutEvent).toBeInstanceOf(CustomEvent);
|
||||||
|
expect(calculateLayout).not.toHaveBeenCalled();
|
||||||
|
expect(showToast).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
dispatchSpy.mockRestore();
|
||||||
|
delete state.virtualScroller;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user