初始化奇妙小屏幕控制器项目
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
const bootstrap = globalThis.__UI_COPY_EDITOR_BUILD__ || null;
|
||||
const placeholderPattern = /\{([a-zA-Z][a-zA-Z0-9_]*)\}/g;
|
||||
const targetRegistry = new Map();
|
||||
const accessibleNameState = new WeakMap();
|
||||
let activeDraft = bootstrap?.initial_draft || { overrides: {} };
|
||||
|
||||
function formatTemplate(text, values = {}) {
|
||||
return String(text).replace(placeholderPattern, (_match, name) => values[name] ?? `{${name}}`);
|
||||
}
|
||||
|
||||
function preserveAccessibleName(record, text) {
|
||||
const host = record.host;
|
||||
if (!host) return;
|
||||
if (!accessibleNameState.has(host)) accessibleNameState.set(host, host.getAttribute("aria-label"));
|
||||
host.setAttribute("aria-label", text || record.defaultText);
|
||||
}
|
||||
|
||||
function restoreAccessibleName(record) {
|
||||
if (!record.host || !accessibleNameState.has(record.host)) return;
|
||||
const original = accessibleNameState.get(record.host);
|
||||
if (original === null) record.host.removeAttribute("aria-label");
|
||||
else record.host.setAttribute("aria-label", original);
|
||||
accessibleNameState.delete(record.host);
|
||||
}
|
||||
|
||||
function applyRecord(record) {
|
||||
if (!record.target.isConnected) return;
|
||||
const override = activeDraft.overrides?.[record.copyId] || {};
|
||||
const sourceText = override.text ?? record.defaultText;
|
||||
const renderedText = formatTemplate(sourceText, record.values);
|
||||
if (record.attribute) {
|
||||
record.target.setAttribute(record.attribute, renderedText);
|
||||
return;
|
||||
}
|
||||
const hidden = Object.hasOwn(override, "hidden") ? override.hidden : Boolean(record.defaultHidden);
|
||||
record.target.textContent = hidden ? "" : renderedText;
|
||||
if (hidden) preserveAccessibleName(record, renderedText);
|
||||
else restoreAccessibleName(record);
|
||||
if (override.font_size_px) {
|
||||
if (!record.fontCaptured) {
|
||||
record.originalFontSize = record.target.style.fontSize;
|
||||
record.fontCaptured = true;
|
||||
}
|
||||
record.target.style.fontSize = `${override.font_size_px}px`;
|
||||
} else if (record.fontCaptured) {
|
||||
record.target.style.fontSize = record.originalFontSize;
|
||||
record.fontCaptured = false;
|
||||
}
|
||||
record.target.classList.toggle("ui-copy-has-override", Boolean(activeDraft.overrides?.[record.copyId]));
|
||||
}
|
||||
|
||||
function registerRecord(record) {
|
||||
const previous = targetRegistry.get(record.target);
|
||||
if (previous) {
|
||||
record.originalFontSize = previous.originalFontSize;
|
||||
record.fontCaptured = previous.fontCaptured;
|
||||
}
|
||||
targetRegistry.set(record.target, record);
|
||||
if (bootstrap) record.target.dataset.uiCopyId = record.copyId;
|
||||
applyRecord(record);
|
||||
return record;
|
||||
}
|
||||
|
||||
export function renderUiCopy(copyId, element, defaultText, values = {}, options = {}) {
|
||||
if (!(element instanceof Element)) return;
|
||||
if (!bootstrap) {
|
||||
const renderedText = formatTemplate(defaultText, values);
|
||||
const record = { host: element, defaultText };
|
||||
element.textContent = options.defaultHidden ? "" : renderedText;
|
||||
if (options.defaultHidden) preserveAccessibleName(record, renderedText);
|
||||
else restoreAccessibleName(record);
|
||||
return;
|
||||
}
|
||||
registerRecord({
|
||||
copyId,
|
||||
target: element,
|
||||
host: element,
|
||||
defaultText,
|
||||
values,
|
||||
kind: "dynamic_template",
|
||||
attribute: null,
|
||||
defaultHidden: Boolean(options.defaultHidden),
|
||||
});
|
||||
}
|
||||
|
||||
export function renderUiValue(element, value) {
|
||||
if (!(element instanceof Element)) return;
|
||||
const priorRecord = targetRegistry.get(element);
|
||||
restoreAccessibleName(priorRecord || { host: element });
|
||||
targetRegistry.delete(element);
|
||||
delete element.dataset.uiCopyId;
|
||||
element.textContent = String(value ?? "");
|
||||
}
|
||||
|
||||
export function registerStaticUiCopy(copyId, target, host, defaultText, kind, attribute = null, defaultHidden = false) {
|
||||
if (!bootstrap || !(target instanceof Element)) return null;
|
||||
return registerRecord({
|
||||
copyId,
|
||||
target,
|
||||
host: host || target,
|
||||
defaultText,
|
||||
values: {},
|
||||
kind,
|
||||
attribute,
|
||||
defaultHidden: Boolean(defaultHidden),
|
||||
});
|
||||
}
|
||||
|
||||
export function setUiCopyDraft(nextDraft) {
|
||||
activeDraft = nextDraft;
|
||||
for (const record of targetRegistry.values()) applyRecord(record);
|
||||
}
|
||||
|
||||
export function applyUiCopyId(copyId) {
|
||||
for (const record of targetRegistry.values()) {
|
||||
if (record.copyId === copyId) applyRecord(record);
|
||||
}
|
||||
}
|
||||
|
||||
export function uiCopyRecords(copyId = null) {
|
||||
const records = Array.from(targetRegistry.values()).filter((record) => record.target.isConnected);
|
||||
return copyId === null ? records : records.filter((record) => record.copyId === copyId);
|
||||
}
|
||||
|
||||
export function unregisterUiCopySubtree(root) {
|
||||
for (const [target] of targetRegistry) {
|
||||
if (!target.isConnected || target === root || root?.contains?.(target)) targetRegistry.delete(target);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user