Split monolithic 1400-line comfy_shared.js into focused TypeScript modules in web_source/src/comfy_shared/: - api.ts: server API utilities (runAction, getServerInfo, setServerInfo) - colors.ts: color brightness utilities - documentation.ts: node documentation widget system - dom.ts: DOM and HTML utilities - dynamic-connections.ts: dynamic input/output management - logger.ts: logging utilities with toast notifications - node-extensions.ts: node type extension helpers - storage.ts: namespaced localStorage management - types.ts: comprehensive type definitions - utils.ts: base utilities (UUID, debounce, deep merge) - widgets.ts: LiteGraph widget utilities Benefits: - ~200 LOC reduction through proper typing and elimination of redundant code - Better code organization with single-responsibility modules - Full TypeScript type safety with proper generics - Improved documentation and maintainability - Easier to tree-shake unused utilities Updated vite.config.ts to build comfy_shared as separate entry point and marked external dependencies (/mtb_async modules). Modified InspectorItem.svelte to use extracted item.value instead of always pulling from widgets[0]. Renamed panel.ts to panel.svelte.ts to enable Svelte 5 runes and made APIPanel reactive using $state instead of $$set.
79 lines
1.8 KiB
TypeScript
79 lines
1.8 KiB
TypeScript
/**
|
|
* DOM and HTML utilities
|
|
*/
|
|
|
|
import { infoLogger } from './logger'
|
|
|
|
/**
|
|
* Calculate total height of DOM element children
|
|
*/
|
|
export function calculateTotalChildrenHeight(parentElement: HTMLElement | null): number {
|
|
let totalHeight = 0
|
|
|
|
if (!parentElement || !parentElement.children) {
|
|
return 0
|
|
}
|
|
|
|
for (const child of parentElement.children) {
|
|
const style = window.getComputedStyle(child)
|
|
|
|
const height = Number.parseFloat(style.height)
|
|
const marginTop = Number.parseFloat(style.marginTop)
|
|
const marginBottom = Number.parseFloat(style.marginBottom)
|
|
|
|
totalHeight += height + marginTop + marginBottom
|
|
}
|
|
|
|
return Math.ceil(totalHeight)
|
|
}
|
|
|
|
interface LoadScriptResult {
|
|
status: boolean
|
|
message?: string
|
|
}
|
|
|
|
/**
|
|
* Dynamically load a script
|
|
*/
|
|
export const loadScript = (
|
|
FILE_URL: string,
|
|
async = true,
|
|
type = 'text/javascript',
|
|
): Promise<LoadScriptResult> => {
|
|
return new Promise((resolve, reject) => {
|
|
try {
|
|
// Check if the script already exists
|
|
let scriptEle = document.querySelector(`script[src="${FILE_URL}"]`) as HTMLScriptElement | null
|
|
|
|
if (scriptEle) {
|
|
scriptEle.addEventListener('load', () => {
|
|
resolve({ status: true })
|
|
})
|
|
return
|
|
}
|
|
|
|
scriptEle = document.createElement('script')
|
|
scriptEle.type = type
|
|
scriptEle.async = async
|
|
scriptEle.src = FILE_URL
|
|
|
|
scriptEle.addEventListener('load', () => {
|
|
resolve({ status: true })
|
|
})
|
|
|
|
scriptEle.addEventListener('error', () => {
|
|
reject({
|
|
status: false,
|
|
message: `Failed to load the script ${FILE_URL}`,
|
|
})
|
|
})
|
|
|
|
document.body.appendChild(scriptEle)
|
|
} catch (error) {
|
|
reject(error)
|
|
} finally {
|
|
infoLogger(`Finally loaded script: ${FILE_URL}`)
|
|
}
|
|
})
|
|
}
|