mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-27 03:19:56 +00:00
* [Beta Menu] Shows unsaved state on browser tab title * Proper state management * Add playwright test * Fix browser tests
171 lines
4.2 KiB
TypeScript
171 lines
4.2 KiB
TypeScript
import { api } from './api'
|
|
import type { ComfyApp } from './app'
|
|
import { $el } from './ui'
|
|
|
|
// Simple date formatter
|
|
const parts = {
|
|
d: (d) => d.getDate(),
|
|
M: (d) => d.getMonth() + 1,
|
|
h: (d) => d.getHours(),
|
|
m: (d) => d.getMinutes(),
|
|
s: (d) => d.getSeconds()
|
|
}
|
|
const format =
|
|
Object.keys(parts)
|
|
.map((k) => k + k + '?')
|
|
.join('|') + '|yyy?y?'
|
|
|
|
function formatDate(text: string, date: Date) {
|
|
return text.replace(new RegExp(format, 'g'), (text: string): string => {
|
|
if (text === 'yy') return (date.getFullYear() + '').substring(2)
|
|
if (text === 'yyyy') return date.getFullYear().toString()
|
|
if (text[0] in parts) {
|
|
const p = parts[text[0]](date)
|
|
return (p + '').padStart(text.length, '0')
|
|
}
|
|
return text
|
|
})
|
|
}
|
|
|
|
export function clone(obj) {
|
|
try {
|
|
if (typeof structuredClone !== 'undefined') {
|
|
return structuredClone(obj)
|
|
}
|
|
} catch (error) {
|
|
// structuredClone is stricter than using JSON.parse/stringify so fallback to that
|
|
}
|
|
|
|
return JSON.parse(JSON.stringify(obj))
|
|
}
|
|
|
|
export function applyTextReplacements(app: ComfyApp, value: string): string {
|
|
return value.replace(/%([^%]+)%/g, function (match, text) {
|
|
const split = text.split('.')
|
|
if (split.length !== 2) {
|
|
// Special handling for dates
|
|
if (split[0].startsWith('date:')) {
|
|
return formatDate(split[0].substring(5), new Date())
|
|
}
|
|
|
|
if (text !== 'width' && text !== 'height') {
|
|
// Dont warn on standard replacements
|
|
console.warn('Invalid replacement pattern', text)
|
|
}
|
|
return match
|
|
}
|
|
|
|
// Find node with matching S&R property name
|
|
let nodes = app.graph.nodes.filter(
|
|
(n) => n.properties?.['Node name for S&R'] === split[0]
|
|
)
|
|
// If we cant, see if there is a node with that title
|
|
if (!nodes.length) {
|
|
nodes = app.graph.nodes.filter((n) => n.title === split[0])
|
|
}
|
|
if (!nodes.length) {
|
|
console.warn('Unable to find node', split[0])
|
|
return match
|
|
}
|
|
|
|
if (nodes.length > 1) {
|
|
console.warn('Multiple nodes matched', split[0], 'using first match')
|
|
}
|
|
|
|
const node = nodes[0]
|
|
|
|
const widget = node.widgets?.find((w) => w.name === split[1])
|
|
if (!widget) {
|
|
console.warn('Unable to find widget', split[1], 'on node', split[0], node)
|
|
return match
|
|
}
|
|
|
|
return ((widget.value ?? '') + '').replaceAll(/\/|\\/g, '_')
|
|
})
|
|
}
|
|
|
|
export async function addStylesheet(
|
|
urlOrFile: string,
|
|
relativeTo?: string
|
|
): Promise<void> {
|
|
return new Promise((res, rej) => {
|
|
let url
|
|
if (urlOrFile.endsWith('.js')) {
|
|
url = urlOrFile.substr(0, urlOrFile.length - 2) + 'css'
|
|
} else {
|
|
url = new URL(
|
|
urlOrFile,
|
|
relativeTo ?? `${window.location.protocol}//${window.location.host}`
|
|
).toString()
|
|
}
|
|
$el('link', {
|
|
parent: document.head,
|
|
rel: 'stylesheet',
|
|
type: 'text/css',
|
|
href: url,
|
|
onload: res,
|
|
onerror: rej
|
|
})
|
|
})
|
|
}
|
|
|
|
/**
|
|
* @param { string } filename
|
|
* @param { Blob } blob
|
|
*/
|
|
export function downloadBlob(filename, blob) {
|
|
const url = URL.createObjectURL(blob)
|
|
const a = $el('a', {
|
|
href: url,
|
|
download: filename,
|
|
style: { display: 'none' },
|
|
parent: document.body
|
|
})
|
|
a.click()
|
|
setTimeout(function () {
|
|
a.remove()
|
|
window.URL.revokeObjectURL(url)
|
|
}, 0)
|
|
}
|
|
|
|
export function prop<T>(
|
|
target: object,
|
|
name: string,
|
|
defaultValue: T,
|
|
onChanged?: (
|
|
currentValue: T,
|
|
previousValue: T,
|
|
target: object,
|
|
name: string
|
|
) => void
|
|
): T {
|
|
let currentValue
|
|
Object.defineProperty(target, name, {
|
|
get() {
|
|
return currentValue
|
|
},
|
|
set(newValue) {
|
|
const prevValue = currentValue
|
|
currentValue = newValue
|
|
onChanged?.(currentValue, prevValue, target, name)
|
|
}
|
|
})
|
|
return defaultValue
|
|
}
|
|
|
|
export function getStorageValue(id: string) {
|
|
const clientId = api.clientId ?? api.initialClientId
|
|
return (
|
|
(clientId && sessionStorage.getItem(`${id}:${clientId}`)) ??
|
|
localStorage.getItem(id)
|
|
)
|
|
}
|
|
|
|
export function setStorageValue(id: string, value: string) {
|
|
const clientId = api.clientId ?? api.initialClientId
|
|
if (clientId) {
|
|
sessionStorage.setItem(`${id}:${clientId}`, value)
|
|
}
|
|
localStorage.setItem(id, value)
|
|
}
|