Files
ComfyUI-Lora-Manager/static/js/core.js
T
Will Miao d5139500f9 fix(settings): stop clipping help tooltips in the settings pane
Help tooltips were CSS pseudo-elements on the info icon, so they were
descendants of the scrollable settings pane (.settings-content uses
overflow-y: auto) and got clipped at its top edge. The Active Library
deprecation notice made this obvious: the text grew to ~10 lines while
only ~5 fit above the icon, so the tooltip started mid-sentence at
"page. Deprecated:".

Render the tooltip once into <body> with position: fixed instead, so no
overflow ancestor can clip it, and position it from JS: above the trigger
when it fits, below otherwise, clamped to the viewport. It follows the
trigger on scroll/resize and hides on mouseout, Escape or touch. The
delegated listeners also cover help icons rendered later by the settings
manager, and the box may now use 320px instead of 220px, which keeps long
help texts to fewer lines.
2026-10-11 11:34:52 +08:00

158 lines
6.2 KiB
JavaScript

// Core application functionality
import { state } from './state/index.js';
import { LoadingManager } from './managers/LoadingManager.js';
import { modalManager } from './managers/ModalManager.js';
import { updateService } from './managers/UpdateService.js';
import { HeaderManager } from './components/Header.js';
import { settingsManager } from './managers/SettingsManager.js';
import { moveManager } from './managers/MoveManager.js';
import { bulkManager } from './managers/BulkManager.js';
import { rematchModalManager } from './managers/RematchModalManager.js';
import { ExampleImagesManager } from './managers/ExampleImagesManager.js';
import { helpManager } from './managers/HelpManager.js';
import { doctorManager } from './managers/DoctorManager.js';
import { bannerService } from './managers/BannerService.js';
import { initTheme, initBackToTop } from './utils/uiHelpers.js';
import { initTooltips } from './utils/tooltip.js';
import { applyModalBackdropBlurPolicy } from './utils/renderingCapability.js';
import { initializeInfiniteScroll } from './utils/infiniteScroll.js';
import { i18n } from './i18n/index.js';
import { onboardingManager } from './managers/OnboardingManager.js';
import './components/Combobox.js';
import { BulkContextMenu } from './components/ContextMenu/BulkContextMenu.js';
import { createPageContextMenu, createGlobalContextMenu } from './components/ContextMenu/index.js';
import { initializeEventManagement } from './utils/eventManagementInit.js';
import { civitaiBaseModelApi } from './api/civitaiBaseModelApi.js';
import { setDynamicBaseModels, BASE_MODELS_UPDATED_EVENT } from './utils/constants.js';
// Core application class
export class AppCore {
constructor() {
this.initialized = false;
}
// Initialize core functionality
async initialize() {
if (this.initialized) return;
console.log('AppCore: Initializing...');
// Disable full-viewport backdrop blur under software rendering before
// anything can open a modal (issue #1092)
applyModalBackdropBlurPolicy();
// Initialize i18n first
window.i18n = i18n;
// Wait for i18n to be ready
await window.i18n.waitForReady();
console.log(`AppCore: Language set: ${i18n.getCurrentLocale()}`);
// Initialize settings manager and wait for it to sync from backend
console.log('AppCore: Initializing settings...');
await settingsManager.waitForInitialization();
console.log('AppCore: Settings initialized');
// Initialize dynamic base models (async, non-blocking)
console.log('AppCore: Initializing dynamic base models...');
this.initializeDynamicBaseModels();
// Initialize managers
state.loadingManager = new LoadingManager();
modalManager.initialize();
updateService.initialize();
await bannerService.initialize();
window.modalManager = modalManager;
window.settingsManager = settingsManager;
const exampleImagesManager = new ExampleImagesManager();
window.exampleImagesManager = exampleImagesManager;
window.helpManager = helpManager;
window.doctorManager = doctorManager;
window.moveManager = moveManager;
window.bulkManager = bulkManager;
window.rematchModalManager = rematchModalManager;
// Initialize UI components
window.headerManager = new HeaderManager();
initTheme();
initBackToTop();
initTooltips();
// Initialize the bulk manager and context menu
bulkManager.initialize();
// Initialize bulk context menu
const bulkContextMenu = new BulkContextMenu();
bulkManager.setBulkContextMenu(bulkContextMenu);
// Initialize the example images manager
exampleImagesManager.initialize();
// Initialize the help manager
helpManager.initialize();
doctorManager.initialize();
const cardInfoDisplay = state.global.settings.card_info_display || 'always';
document.body.classList.toggle('hover-reveal', cardInfoDisplay === 'hover');
initializeEventManagement();
// Mark as initialized
this.initialized = true;
// Start onboarding if needed (after everything is initialized)
setTimeout(async () => {
await onboardingManager.start();
}, 1000); // Small delay to ensure all elements are rendered
// Return the core instance for chaining
return this;
}
// Get the current page type
getPageType() {
const body = document.body;
return body.dataset.page || 'unknown';
}
// Initialize common UI features based on page type
initializePageFeatures() {
const pageType = this.getPageType();
if (['loras', 'recipes', 'checkpoints', 'embeddings', 'other'].includes(pageType)) {
this.initializeContextMenus(pageType);
initializeInfiniteScroll(pageType);
}
return this;
}
// Initialize context menus for the current page
initializeContextMenus(pageType) {
// Create page-specific context menu
window.pageContextMenu = createPageContextMenu(pageType);
if (!window.globalContextMenuInstance) {
window.globalContextMenuInstance = createGlobalContextMenu();
}
}
// Initialize dynamic base models from Civitai API
// This is non-blocking - runs in background
async initializeDynamicBaseModels() {
try {
const result = await civitaiBaseModelApi.getBaseModels();
if (result && result.models) {
setDynamicBaseModels(result.models, result.last_updated);
window.dispatchEvent(new CustomEvent(BASE_MODELS_UPDATED_EVENT));
console.log(`AppCore: Loaded ${result.merged_count} base models (${result.hardcoded_count} hardcoded + ${result.remote_count} remote)`);
}
} catch (error) {
console.warn('AppCore: Failed to load dynamic base models:', error);
// Non-critical error - app continues with hardcoded models
}
}
}
// Create and export a singleton instance
export const appCore = new AppCore();