Files
ComfyAssets-ComfyUI-KikoTools/web/views/node-dimensions.js
T

75 lines
3.2 KiB
JavaScript

import { createButton, createField } from '../ui/core.js';
import { createDialog } from '../ui/dialog.js';
const activeDialogs = new WeakMap();
export function resolveNodeSize(values, minimum) {
const size = values.map(Number);
if (values.some(value => String(value).trim() === '') || size.some(value => !Number.isSafeInteger(value) || value <= 0)) return null;
return size.map((value, index) => Math.max(value, minimum[index]));
}
export function showNodeDimensionsDialog(node, app) {
const existing = activeDialogs.get(node);
if (existing) {
existing.querySelector('.width').focus();
return existing;
}
const dialog = createDialog({ title: 'Node Dimensions', settings: app.ui.settings, fallbackFocus: app.canvas.canvas });
const form = document.createElement('form');
form.id = `${dialog.element.id}-form`;
form.noValidate = true;
const hint = document.createElement('p');
hint.id = `${form.id}-hint`;
hint.textContent = 'Minimum size is enforced based on node content.';
hint.className = 'ca-dialog-hint';
const fields = document.createElement('div');
fields.className = 'ca-dimension-fields';
const error = document.createElement('p');
error.id = `${form.id}-error`;
error.className = 'ca-dialog-error';
error.setAttribute('aria-live', 'polite');
const inputs = ['Width', 'Height'].map((name, index) => {
const input = document.createElement('input');
Object.assign(input, { type: 'number', min: '1', step: '1', required: true, value: String(Math.round(node.size[index])), className: name.toLowerCase() });
input.setAttribute('aria-describedby', `${hint.id} ${error.id}`);
fields.append(createField(`${name} (px)`, input, `${form.id}-${name.toLowerCase()}`));
return input;
});
form.append(hint, fields, error);
dialog.body.append(form);
const cancel = createButton('Cancel');
const apply = createButton('Apply', 'ca-primary');
apply.type = 'submit';
apply.setAttribute('form', form.id);
dialog.actions.append(cancel, apply);
dialog.scope.listen(cancel, 'click', () => dialog.close('cancel'));
dialog.scope.listen(form, 'submit', event => {
event.preventDefault();
const size = resolveNodeSize(inputs.map(input => input.value), node.computeSize());
if (!size) {
error.textContent = 'Enter positive whole numbers for width and height.';
for (const input of inputs) input.setAttribute('aria-invalid', String(!resolveNodeSize([input.value], [1])));
inputs.find(input => input.getAttribute('aria-invalid') === 'true').focus();
return;
}
node.setSize(size);
node.setDirtyCanvas(true, true);
dialog.close('apply');
});
const original = node.onRemoved;
const onRemoved = function (...args) {
dialog.close('removed');
return original?.apply(this, args);
};
node.onRemoved = onRemoved;
activeDialogs.set(node, dialog.element);
dialog.scope.cleanup(() => {
activeDialogs.delete(node);
if (node.onRemoved === onRemoved) node.onRemoved = original;
});
dialog.open(inputs[0]);
inputs[0].select();
return dialog.element;
}