diff --git a/inventory/static/js/components/grid/widget-core.js b/inventory/static/js/components/grid/widget-core.js index b28be2b..21cd761 100644 --- a/inventory/static/js/components/grid/widget-core.js +++ b/inventory/static/js/components/grid/widget-core.js @@ -32,8 +32,15 @@ export function createWidgetCore(env) { // Document and shape lifecycle function loadDoc() { - try { return JSON.parse(localStorage.getItem(storageKey)) || structuredClone(DEFAULT_DOC); } - catch { return structuredClone(DEFAULT_DOC); } + try { + const raw = env.loadRaw + ? env.loadRaw() + : localStorage.getItem(storageKey); + + return raw ? JSON.parse(raw) : structuredClone(DEFAULT_DOC); + } catch { + return structuredClone(DEFAULT_DOC); + } } function saveDoc(nextDoc = doc) { @@ -42,7 +49,13 @@ export function createWidgetCore(env) { shapes: stripCaches(Array.isArray(nextDoc.shapes) ? nextDoc.shapes : []) }; doc = safeDoc; - try { localStorage.setItem(storageKey, JSON.stringify(safeDoc)); } catch { } + + const raw = JSON.stringify(safeDoc); + + try { + if (env.saveRaw) env.saveRaw(raw); + else localStorage.setItem(storageKey, raw); + } catch { } } function setDoc(nextDoc) { diff --git a/inventory/static/js/components/grid/widget-init.js b/inventory/static/js/components/grid/widget-init.js index 71dca5d..69218ba 100644 --- a/inventory/static/js/components/grid/widget-init.js +++ b/inventory/static/js/components/grid/widget-init.js @@ -1,5 +1,23 @@ +import { encode, decode } from './encode-decode.js'; import { createWidgetCore, DEFAULT_DOC } from "./widget-core.js"; import { initWidgetEditor } from "./widget-editor.js"; +import { initWidgetViewer } from "./widget-viewer.js"; + +function readEmbeddedDoc(root, toastMessage) { + const el = root.querySelector('[data-grid-doc]'); + if (!el) return null; + + const raw = (el.textContent || '').trim(); + if (!raw) return null; + + try { + const parsed = JSON.parse(raw); + return decode(parsed); + } catch (err) { + toastMessage?.(`Failed to parse embedded grid JSON: ${err?.message || err}`, 'danger'); + return null; + } +} export function initGridWidget(root, opts = {}) { const mode = opts.mode || 'editor'; @@ -15,6 +33,12 @@ export function initGridWidget(root, opts = {}) { const toastMessage = opts.toastMessage || (() => { }); + let initialDoc = opts.doc ?? null; + + if (!initialDoc && mode !== 'editor') { + initialDoc = readEmbeddedDoc(root, toastMessage); + } + const core = createWidgetCore({ root, mode, @@ -22,18 +46,67 @@ export function initGridWidget(root, opts = {}) { gridEl, canvasEl, viewerOffset: opts.viewerOffset || { x: 0, y: 0 }, - doc: opts.doc, + doc: initialDoc, cellSize: opts.cellSize, - shapes: opts.shapes + shapes: opts.shapes, + + loadRaw() { + if (mode !== 'editor') return null; + return localStorage.getItem(storageKey); + }, + saveRaw(_rawInternalDoc) { + if (mode !== 'editor') return; + + const payload = encode({ + cellSize: core.cellSize, + shapes: core.shapes, + stripCaches: core.stripCaches, + SHAPE_DEFAULTS: core.SHAPE_DEFAULTS + }); + + localStorage.setItem(storageKey, JSON.stringify(payload)); + } }); const env = { root, gridEl, gridWrapEl, toastMessage, storageKey }; + if (mode === 'editor') { + const raw = localStorage.getItem(storageKey); + if (raw) { + try { + const decoded = decode(JSON.parse(raw)); + core.setDoc(decoded); + } catch { + core.setDoc(DEFAULT_DOC); + } + } else { + const raw = root.dataset.doc; + if (raw) { + try { + const decoded = decode(JSON.parse(raw)); + core.setDoc(decoded); + } catch { + core.setDoc(DEFAULT_DOC); + } + } else { + core.setDoc(DEFAULT_DOC); + } + } + } else { + const embedded = initialDoc ?? readEmbeddedDoc(root, toastMessage); + if (embedded) core.setDoc(embedded); + } + let editorApi = null; if (mode === 'editor') { editorApi = initWidgetEditor(core, env); } + let viewerApi = null; + if (mode !== 'editor') { + viewerApi = initWidgetViewer(core, { core, gridEl, gridWrapEl }); + } + const api = { core, mode, @@ -46,11 +119,18 @@ export function initGridWidget(root, opts = {}) { get cellSize() { return core.cellSize; }, }; - if(editorApi) { + if (editorApi) { api.handleKeyDown = editorApi.handleKeyDown; api.handleGlobalPointerUp = editorApi.handleGlobalPointerUp; api.cancelStroke = editorApi.cancelStroke; } + if (viewerApi) { + api.setDoc = viewerApi.setDoc; + api.redraw = viewerApi.redraw; + api.destroy = viewerApi.destroy; + api.decode = viewerApi.decode; + } + return api; }