fix: multiple adjustments to rendering and updating fields

typescript_changes
flop 3 weeks ago
parent 4e03152676
commit 0db0e11815
  1. 138
      ts/src/browser.ts

@ -6,7 +6,6 @@
import * as MonoDisplay from "./index"; import * as MonoDisplay from "./index";
import { MonoDisplayFile } from "./file"; import { MonoDisplayFile } from "./file";
import { cycleTheme } from "./themes"; import { cycleTheme } from "./themes";
import { ElementType } from "./types";
// Expose on globalThis (= window in browser, globalThis elsewhere) // Expose on globalThis (= window in browser, globalThis elsewhere)
(globalThis as typeof globalThis & { MonoDisplay: typeof MonoDisplay }).MonoDisplay = MonoDisplay; (globalThis as typeof globalThis & { MonoDisplay: typeof MonoDisplay }).MonoDisplay = MonoDisplay;
@ -20,8 +19,8 @@ let isDirty = false;
// --- Element type definitions ------------------------------------------------ // --- Element type definitions ------------------------------------------------
type ElFieldMeta = { key: string; label: string; type: string; default: any; full?: boolean }; type ElFieldMeta = { key: string; label: string; type: string; default: any; full?: boolean };
type ElFlagMeta = { key: string; label: string }; type ElFlagMeta = { key: string; label: string, default?: boolean; };
const EL_FIELDS: Partial<Record<keyof typeof ElementType, ElFieldMeta[]>> = { const EL_FIELDS: Partial<Record<MonoDisplay.ElementTypeName, ElFieldMeta[]>> = {
Image2D: [ Image2D: [
{ key: 'xOffset', label: 'X offset', type: 'number', default: 0 }, { key: 'yOffset', label: 'Y offset', type: 'number', default: 0 }, { 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 }, { 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' }, { 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' }], 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 = [ const DEFAULT_FONTS = [
"Font 1", "Font 1",
@ -129,20 +128,28 @@ function newSec() {
flags: {}, flags: {},
}; };
} }
function newEl(type: MonoDisplay.ElementType) { function createNewElement(type: MonoDisplay.ElementType) : MonoDisplay.MonoFormatElement {
const fields = {}; const fields:Record<string,any> = {};
(EL_FIELDS[type] || []).forEach(f => fields[f.k] = f.d); (EL_FIELDS[MonoDisplay.ElementTypeToString[type]] as any[] || [])
const flags = {}; .forEach((f: ElFieldMeta) => fields[f.key] = f.default);
(EL_FLAGS[type] || []).forEach(f => flags[f.k] = false); const flags:Record<string,any> = {};
return { type, fields, flags }; (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) return file.sections.find((s,index) => index === sectionIndex)
} }
function getEl(sectionIndex: number, elementIndex: number) { function getElementByIndex(sectionIndex: number, elementIndex: number): MonoDisplay.MonoFormatElement | undefined {
const section = getSec(sectionIndex); const section = getSectionByIndex(sectionIndex);
return section && "elements" in section && section.elements.find((e, index) => index == elementIndex) if(section && "elements" in section)
return section.elements.find((e, index) => index == elementIndex)
return undefined;
} }
// --- Mutations ---------------------------------------------------------------- // --- Mutations ----------------------------------------------------------------
@ -159,27 +166,43 @@ function removeSection(sectionIndex:number) {
} }
markDirty(); renderHTML(); triggerPreview(); markDirty(); renderHTML(); triggerPreview();
} }
function toggleSection(id) { function toggleSection(sectionIndex: number): void {
const s = getSec(id); if (!s) return; const s = getSectionByIndex(sectionIndex);
s.open = !s.open; activeSecIndex = id; renderHTML(); updateMeta(); if (!s) return;
activeSecIndex = sectionIndex;
renderHTML();
updateMeta();
} }
function setSectionFlag(flag, val) { function setSectionFlag(flag, val) {
if (!activeSecIndex) return; if (!activeSecIndex) return;
const s = getSec(activeSecIndex); if (!s) return; const s = getSectionByIndex(activeSecIndex);
s.flags[flag] = val; markDirty(); triggerPreview(); if (!s) return;
s.flags[flag] = val;
markDirty();
triggerPreview();
} }
function addElement(sectionIndex: number) { function addElement(sectionIndex: number) {
const s = getSec(secId); if (!s) return; const s = getSectionByIndex(sectionIndex);
const el = newEl(EL_TYPES[0]); s.elements.push(el); if (!s) return;
activeSecIndex = secId; activeElIndex = { secId, elId: el.id }; if (!("elements" in s)) return;
markDirty(); renderHTML(); triggerPreview(); s.elements.push(createNewElement(MonoDisplay.ElementType.HScrollText));
activeElIndex = s.elements.length;
activeSecIndex = sectionIndex;
markDirty();
renderHTML();
triggerPreview();
} }
function removeElement(sectionIndex:number, elementIndex:number) { function removeElement(sectionIndex:number, elementIndex:number) {
const s = getSec(sectionIndex); if (!s) return; const s = getSectionByIndex(sectionIndex);
s.elements = s.elements.filter(e => e.id !== elId); if (!s) return;
if (activeElIndex && activeElIndex.secId === secId && activeElIndex.elId === elId) activeElIndex = null; if (!("elements" in s)) return;
markDirty(); renderHTML(); triggerPreview(); s.elements = s.elements.filter((e,i) => i != elementIndex);
if (activeElIndex)
activeElIndex = null;
markDirty();
renderHTML();
triggerPreview();
} }
function selectElement(sectionIndex:number, elementIndex:number) { function selectElement(sectionIndex:number, elementIndex:number) {
activeSecIndex = sectionIndex; activeSecIndex = sectionIndex;
@ -189,25 +212,33 @@ function selectElement(sectionIndex:number, elementIndex:number) {
null : elementIndex; null : elementIndex;
renderHTML(); renderHTML();
} }
function changeElType(sectionIndex:number, elementIndex:number, typeString: string) { function changeElType(sectionIndex:number, elementIndex:number, typeString: MonoDisplay.ElementTypeName) {
const el = getEl(sectionIndex, elementIndex); if (!el) return; const el = getElementByIndex(sectionIndex, elementIndex); if (!el) return;
const type = MonoDisplay.StringToElementType[typeString as MonoDisplay.ElementTypeName]; const fresh = createNewElement(MonoDisplay.StringToElementType[typeString]);
const fresh = newEl(type); setElementByElement(el, fresh);
el.type = type; el.fields = fresh.fields; el.flags = fresh.flags;
markDirty(); renderHTML(); triggerPreview(); 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) { 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; el[key] = val;
markDirty(); triggerPreview(); markDirty(); triggerPreview();
} }
function setElFlag(sectionIndex:number, elementIndex:number, key:string, val:any) { 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; el.flags[key] = val;
markDirty(); triggerPreview(); markDirty(); triggerPreview();
} }
function setSectionType(sectionIndex: number, sectionType: string) { function setSectionType(sectionIndex: number, sectionType: string) {
const sec = getSec(sectionIndex); const sec = getSectionByIndex(sectionIndex);
if (sec) { if (sec) {
sec.sectionType = MonoDisplay.StringToSectionType[sectionType as MonoDisplay.SectionTypeName]; sec.sectionType = MonoDisplay.StringToSectionType[sectionType as MonoDisplay.SectionTypeName];
if (sec.sectionType == MonoDisplay.SectionType.CustomFont) { if (sec.sectionType == MonoDisplay.SectionType.CustomFont) {
@ -404,22 +435,31 @@ function renderHTMLSection(sectionIndex: number) {
case MonoDisplay.SectionType.ElementsTimespan: case MonoDisplay.SectionType.ElementsTimespan:
return ` return `
<div class="sec-card${isActive ? ' active' : ''}${isOpen ? ' open' : ''}" id="${sectionId}"> <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-arrow"></span>
<span class="sec-label">${MonoDisplay.SectionTypeToString[section.sectionType]}</span> <span class="sec-label">${MonoDisplay.SectionTypeToString[section.sectionType]}</span>
<span class="sec-badge">${section.elements.length} el</span> <span class="sec-badge">${section.elements.length} el</span>
<button class="x-btn" title="Remove section" onclick="event.stopPropagation();removeSection(${sectionIndex})">X</button> <button class="x-btn" title="Remove section" onclick="event.stopPropagation();removeSection(${sectionIndex})">X</button>
</div> </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 ? ` ${isOpen ? `
<div class="el-list"> <div class="el-list">
${section.elements.map((el: MonoDisplay.MonoFormatElement, index:number) => renderHTMLElement(sectionIndex, index, el)).join('')} ${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>`: ''}
</div>`; </div>`;
case MonoDisplay.SectionType.CustomFont: { case MonoDisplay.SectionType.CustomFont: {
return ` return `
<div class="sec-card${isActive ? ' active' : ''}${isOpen ? ' open' : ''}" id="${sectionId}"> <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-arrow"></span>
<span class="sec-label">Custom Font</span> <span class="sec-label">Custom Font</span>
<span class="sec-badge">1 el</span> <span class="sec-badge">1 el</span>
@ -528,18 +568,18 @@ ${isActive ? activeRender : ``}
function elSummary(el: MonoDisplay.MonoFormatElement) { function elSummary(el: MonoDisplay.MonoFormatElement) {
switch (el.type) { switch (el.type) {
case ElementType.ClippedText: case MonoDisplay.ElementType.ClippedText:
case ElementType.HScrollText: case MonoDisplay.ElementType.HScrollText:
// case ElementType.VScrollText: // case ElementType.VScrollText:
return esc(el.text.slice(0, 24) + (el.text.length > 24 ? '...' : '')); return esc(el.text.slice(0, 24) + (el.text.length > 24 ? '...' : ''));
case ElementType.CurrentTime: case MonoDisplay.ElementType.CurrentTime:
case ElementType.Image2D: case MonoDisplay.ElementType.Image2D:
case ElementType.HorizontalScroll: case MonoDisplay.ElementType.HorizontalScroll:
case ElementType.VerticalScroll: case MonoDisplay.ElementType.VerticalScroll:
return `${el.xOffset ?? 0}, ${el.yOffset ?? 0}`; return `${el.xOffset ?? 0}, ${el.yOffset ?? 0}`;
case ElementType.Animation: case MonoDisplay.ElementType.Animation:
case ElementType.Line: case MonoDisplay.ElementType.Line:
return `${el.type.toString()}`; return `${el.type.toString()}`;
default: default:
return "?"; 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 esc(s) { return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') }
function updateMeta() { function updateMeta() {
const section = getSec(activeSecIndex); const section = getSectionByIndex(activeSecIndex);
const sectionSelection = document.getElementById('meta-name'); const sectionSelection = document.getElementById('meta-name');
if (sectionSelection) { if (sectionSelection) {
if (section) { if (section) {

Loading…
Cancel
Save