fix: multiple adjustments to rendering and updating fields

backup
flop 3 weeks ago
parent 96d9123f19
commit d74eed81b3
  1. 140
      ts/src/browser.ts

@ -6,7 +6,6 @@
import * as MonoDisplay from "./index";
import { MonoDisplayFile } from "./file";
import { cycleTheme } from "./themes";
import { ElementType } from "./types";
// Expose on globalThis (= window in browser, globalThis elsewhere)
(globalThis as typeof globalThis & { MonoDisplay: typeof MonoDisplay }).MonoDisplay = MonoDisplay;
@ -20,8 +19,8 @@ let isDirty = false;
// --- Element type definitions ------------------------------------------------
type ElFieldMeta = { key: string; label: string; type: string; default: any; full?: boolean };
type ElFlagMeta = { key: string; label: string };
const EL_FIELDS: Partial<Record<keyof typeof ElementType, ElFieldMeta[]>> = {
type ElFlagMeta = { key: string; label: string, default?: boolean; };
const EL_FIELDS: Partial<Record<MonoDisplay.ElementTypeName, ElFieldMeta[]>> = {
Image2D: [
{ key: 'xOffset', label: 'X offset', type: 'number', default: 0 }, { key: 'yOffset', label: 'Y offset', type: 'number', default: 0 },
{ key: 'width', label: 'Width', type: 'number', default: W }, { key: 'height', label: 'Height', type: 'number', default: H },
@ -59,11 +58,11 @@ const EL_FIELDS: Partial<Record<keyof typeof ElementType, ElFieldMeta[]>> = {
{ key: 'fontIndex', label: 'Font', type: 'font', default: 'Font 0' },
],
};
const EL_FLAGS: Partial<Record<keyof typeof ElementType, ElFlagMeta[]>> = {
const EL_FLAGS: Partial<Record<MonoDisplay.ElementTypeName, ElFlagMeta[]>> = {
HScrollText: [{ key: 'endless', label: 'Endless' }, { key: 'invertDirection', label: 'Invert direction' }],
CurrentTime: [{ key: 'clock12h', label: '12h mode' }, { key: 'showHours', label: 'Show hours' }, { key: 'showSeconds', label: 'Show seconds' }],
CurrentTime: [{ key: 'clock12h', label: '12h mode' , default: false}, { key: 'showHours', label: 'Show hours', default:true}, { key: 'showSeconds', label: 'Show seconds' , default:true}],
};
const EL_TYPES: ElementType[] = Object.keys(EL_FIELDS).map((x: string) => MonoDisplay.StringToElementType[x as MonoDisplay.ElementTypeName]);
const EL_TYPES: MonoDisplay.ElementType[] = Object.keys(EL_FIELDS).map((x: string) => MonoDisplay.StringToElementType[x as MonoDisplay.ElementTypeName]);
const DEFAULT_FONTS = [
"Font 1",
@ -129,20 +128,28 @@ function newSec() {
flags: {},
};
}
function newEl(type: MonoDisplay.ElementType) {
const fields = {};
(EL_FIELDS[type] || []).forEach(f => fields[f.k] = f.d);
const flags = {};
(EL_FLAGS[type] || []).forEach(f => flags[f.k] = false);
return { type, fields, flags };
function createNewElement(type: MonoDisplay.ElementType) : MonoDisplay.MonoFormatElement {
const fields:Record<string,any> = {};
(EL_FIELDS[MonoDisplay.ElementTypeToString[type]] as any[] || [])
.forEach((f: ElFieldMeta) => fields[f.key] = f.default);
const flags:Record<string,any> = {};
(EL_FLAGS[MonoDisplay.ElementTypeToString[type]] as any[] || [])
.forEach((f: ElFlagMeta) => flags[f.key] = f.default || false);
return {
type,
...fields,
flags,
} as MonoDisplay.MonoFormatElement;
}
function getSec(sectionIndex: number | null) {
function getSectionByIndex(sectionIndex: number | null): MonoDisplay.MonoFormatSection | undefined {
return file.sections.find((s,index) => index === sectionIndex)
}
function getEl(sectionIndex: number, elementIndex: number) {
const section = getSec(sectionIndex);
return section && "elements" in section && section.elements.find((e, index) => index == elementIndex)
function getElementByIndex(sectionIndex: number, elementIndex: number): MonoDisplay.MonoFormatElement | undefined {
const section = getSectionByIndex(sectionIndex);
if(section && "elements" in section)
return section.elements.find((e, index) => index == elementIndex)
return undefined;
}
// --- Mutations ----------------------------------------------------------------
@ -159,27 +166,43 @@ function removeSection(sectionIndex:number) {
}
markDirty(); renderHTML(); triggerPreview();
}
function toggleSection(id) {
const s = getSec(id); if (!s) return;
s.open = !s.open; activeSecIndex = id; renderHTML(); updateMeta();
function toggleSection(sectionIndex: number): void {
const s = getSectionByIndex(sectionIndex);
if (!s) return;
activeSecIndex = sectionIndex;
renderHTML();
updateMeta();
}
function setSectionFlag(flag, val) {
if (!activeSecIndex) return;
const s = getSec(activeSecIndex); if (!s) return;
s.flags[flag] = val; markDirty(); triggerPreview();
const s = getSectionByIndex(activeSecIndex);
if (!s) return;
s.flags[flag] = val;
markDirty();
triggerPreview();
}
function addElement(sectionIndex:number) {
const s = getSec(secId); if (!s) return;
const el = newEl(EL_TYPES[0]); s.elements.push(el);
activeSecIndex = secId; activeElIndex = { secId, elId: el.id };
markDirty(); renderHTML(); triggerPreview();
function addElement(sectionIndex: number) {
const s = getSectionByIndex(sectionIndex);
if (!s) return;
if (!("elements" in s)) return;
s.elements.push(createNewElement(MonoDisplay.ElementType.HScrollText));
activeElIndex = s.elements.length;
activeSecIndex = sectionIndex;
markDirty();
renderHTML();
triggerPreview();
}
function removeElement(sectionIndex:number, elementIndex:number) {
const s = getSec(sectionIndex); if (!s) return;
s.elements = s.elements.filter(e => e.id !== elId);
if (activeElIndex && activeElIndex.secId === secId && activeElIndex.elId === elId) activeElIndex = null;
markDirty(); renderHTML(); triggerPreview();
const s = getSectionByIndex(sectionIndex);
if (!s) return;
if (!("elements" in s)) return;
s.elements = s.elements.filter((e,i) => i != elementIndex);
if (activeElIndex)
activeElIndex = null;
markDirty();
renderHTML();
triggerPreview();
}
function selectElement(sectionIndex:number, elementIndex:number) {
activeSecIndex = sectionIndex;
@ -189,25 +212,33 @@ function selectElement(sectionIndex:number, elementIndex:number) {
null : elementIndex;
renderHTML();
}
function changeElType(sectionIndex:number, elementIndex:number, typeString: string) {
const el = getEl(sectionIndex, elementIndex); if (!el) return;
const type = MonoDisplay.StringToElementType[typeString as MonoDisplay.ElementTypeName];
const fresh = newEl(type);
el.type = type; el.fields = fresh.fields; el.flags = fresh.flags;
function changeElType(sectionIndex:number, elementIndex:number, typeString: MonoDisplay.ElementTypeName) {
const el = getElementByIndex(sectionIndex, elementIndex); if (!el) return;
const fresh = createNewElement(MonoDisplay.StringToElementType[typeString]);
setElementByElement(el, fresh);
markDirty(); renderHTML(); triggerPreview();
}
function setElementByElement(el: MonoDisplay.MonoFormatElement, source:MonoDisplay.MonoFormatElement ) {
el.type = source.type;
for (const [key, value] of Object.entries(source)) {
(el as any)[key as any] = value;
}
return el;
}
function setElField(sectionIndex:number, elementIndex:number, key:string, val:any) {
const el = getEl(sectionIndex, elementIndex); if (!el) return;
const el = getElementByIndex(sectionIndex, elementIndex); if (!el) return;
el[key] = val;
markDirty(); triggerPreview();
}
function setElFlag(sectionIndex:number, elementIndex:number, key:string, val:any) {
const el = getEl(sectionIndex, elementIndex); if (!el) return;
const el = getElementByIndex(sectionIndex, elementIndex); if (!el) return;
el.flags[key] = val;
markDirty(); triggerPreview();
}
function setSectionType(sectionIndex: number, sectionType: string) {
const sec = getSec(sectionIndex);
const sec = getSectionByIndex(sectionIndex);
if (sec) {
sec.sectionType = MonoDisplay.StringToSectionType[sectionType as MonoDisplay.SectionTypeName];
if (sec.sectionType == MonoDisplay.SectionType.CustomFont) {
@ -404,22 +435,31 @@ function renderHTMLSection(sectionIndex: number) {
case MonoDisplay.SectionType.ElementsTimespan:
return `
<div class="sec-card${isActive ? ' active' : ''}${isOpen ? ' open' : ''}" id="${sectionId}">
<div class="sec-hdr${isActive ? ' active' : ''}" onclick="toggleSection('${sectionId}')">
<div class="sec-hdr${isActive ? ' active' : ''}" onclick="toggleSection(${sectionIndex})">
<span class="sec-arrow"></span>
<span class="sec-label">${MonoDisplay.SectionTypeToString[section.sectionType]}</span>
<span class="sec-badge">${section.elements.length} el</span>
<button class="x-btn" title="Remove section" onclick="event.stopPropagation();removeSection(${sectionIndex})">X</button>
</div>
${section.sectionType == MonoDisplay.SectionType.ElementsTimespan ? `
<div class="el-list">${
Object.entries({ "Start Time": "startTimestamp", "Stop Time":"endTimestamp"}).map(([label, key]) => {
return `<div class="field id="timespan">
<label>${label}</label>
<input type="datetime-local" value="${(section as any)[key]}" onchange="setSectionField(${sectionIndex}, '${key}',this.value)" />
</div>`;
}).join("")
}</div>`: ``}
${isOpen ? `
<div class="el-list">
${section.elements.map((el: MonoDisplay.MonoFormatElement, index:number) => renderHTMLElement(sectionIndex, index, el)).join('')}
<button class="add-el" onclick="addElement('${sectionId}')">+ add element</button>
<button class="add-el" onclick="addElement(${sectionIndex})">+ add element</button>
</div>`: ''}
</div>`;
case MonoDisplay.SectionType.CustomFont: {
return `
<div class="sec-card${isActive ? ' active' : ''}${isOpen ? ' open' : ''}" id="${sectionId}">
<div class="sec-hdr${isActive ? ' active' : ''}" onclick="toggleSection('${sectionId}')">
<div class="sec-hdr${isActive ? ' active' : ''}" onclick="toggleSection(${sectionIndex})">
<span class="sec-arrow"></span>
<span class="sec-label">Custom Font</span>
<span class="sec-badge">1 el</span>
@ -528,18 +568,18 @@ ${isActive ? activeRender : ``}
function elSummary(el: MonoDisplay.MonoFormatElement) {
switch (el.type) {
case ElementType.ClippedText:
case ElementType.HScrollText:
case MonoDisplay.ElementType.ClippedText:
case MonoDisplay.ElementType.HScrollText:
// case ElementType.VScrollText:
return esc(el.text.slice(0, 24) + (el.text.length > 24 ? '...' : ''));
case ElementType.CurrentTime:
case ElementType.Image2D:
case ElementType.HorizontalScroll:
case ElementType.VerticalScroll:
case MonoDisplay.ElementType.CurrentTime:
case MonoDisplay.ElementType.Image2D:
case MonoDisplay.ElementType.HorizontalScroll:
case MonoDisplay.ElementType.VerticalScroll:
return `${el.xOffset ?? 0}, ${el.yOffset ?? 0}`;
case ElementType.Animation:
case ElementType.Line:
case MonoDisplay.ElementType.Animation:
case MonoDisplay.ElementType.Line:
return `${el.type.toString()}`;
default:
return "?";
@ -548,7 +588,7 @@ function elSummary(el: MonoDisplay.MonoFormatElement) {
function esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') }
function updateMeta() {
const section = getSec(activeSecIndex);
const section = getSectionByIndex(activeSecIndex);
const sectionSelection = document.getElementById('meta-name');
if (sectionSelection) {
if (section) {

Loading…
Cancel
Save