diff --git a/config/current.ver b/config/current.ver index 66472fc..3689edd 100644 --- a/config/current.ver +++ b/config/current.ver @@ -1 +1 @@ -1.2.54 \ No newline at end of file +1.2.55 \ No newline at end of file diff --git a/public/assets/js/bridge/blocks-api.js b/public/assets/js/bridge/blocks-api.js index 9969d86..a06c088 100644 --- a/public/assets/js/bridge/blocks-api.js +++ b/public/assets/js/bridge/blocks-api.js @@ -480,19 +480,23 @@ return; } - // Kein aktives Sync mehr vor dem Speichern, nur Logging + // Minimaler Sync vor dem Speichern + Logging (nur echte Text-Components) try { const doc = editor.Canvas && editor.Canvas.getDocument ? editor.Canvas.getDocument() : null; const active = doc && doc.activeElement; const selectionNode = doc && doc.getSelection ? (doc.getSelection().focusNode || doc.getSelection().anchorNode) : null; const selectionEl = selectionNode ? (selectionNode.nodeType === 1 ? selectionNode : selectionNode.parentElement) : null; const selected = editor.getSelected && editor.getSelected(); -<<<<<<< ours + const win = doc && doc.defaultView; + const lastEl = win && win.__bridgeLastEditableEl; + const lastCompId = win && win.__bridgeLastEditableCompId; let syncResult = null; let syncReason = 'no-editable-selection'; const syncFromElement = (comp, el, reason) => { if (!comp || !comp.set || !el) return false; + const type = comp.get ? comp.get('type') : null; + if (type && type !== 'text' && type !== 'textnode') return false; const html = el.innerHTML || ''; const before = typeof comp.get === 'function' ? (comp.get('content') || '') : ''; if (html.trim() || !String(before || '').trim()) { @@ -510,52 +514,53 @@ return false; }; -<<<<<<< ours -<<<<<<< ours -<<<<<<< ours - // 1) Selection im DOM suchen (bevorzugt) -======= -======= ->>>>>>> theirs - // 1) Bevorzugt: ausgewähltes Component-Element aus der View - if (selected) { + // 1) Selection im DOM (bevorzugt) + if (!syncResult && doc && selectionEl && (selectionEl.isContentEditable || (selectionEl.getAttribute && selectionEl.getAttribute('contenteditable') === 'true'))) { + const root = selectionEl.closest ? selectionEl.closest('[data-gjs-type="text"]') : null; + if (root) { + const id = root.getAttribute ? root.getAttribute('id') : null; + const wrapper = editor.getWrapper && editor.getWrapper(); + if (id && wrapper && wrapper.find) { + const found = wrapper.find(`#${id}`); + const comp = found && found[0]; + syncFromElement(comp, root, 'selection:root'); + } + } + } + // 2) zuletzt fokussiertes Element + if (!syncResult && lastEl && (lastEl.isContentEditable || (lastEl.getAttribute && lastEl.getAttribute('contenteditable') === 'true'))) { + const root = lastEl.closest ? lastEl.closest('[data-gjs-type="text"]') : null; + if (root) { + const id = root.getAttribute ? root.getAttribute('id') : null; + const wrapper = editor.getWrapper && editor.getWrapper(); + if (id && wrapper && wrapper.find) { + const found = wrapper.find(`#${id}`); + const comp = found && found[0]; + syncFromElement(comp, root, 'last:element'); + } + } + } + if (!syncResult && lastCompId) { + const wrapper = editor.getWrapper && editor.getWrapper(); + if (wrapper && wrapper.find) { + const found = wrapper.find(`#${lastCompId}`); + const comp = found && found[0]; + const el = comp && comp.view && comp.view.el; + if (el && (el.isContentEditable || (el.getAttribute && el.getAttribute('contenteditable') === 'true'))) { + syncFromElement(comp, el, 'last:compId'); + } + } + } + // 3) Fallback: ausgewähltes Component-Element + if (!syncResult && selected) { const selEl = (selected.getEl && selected.getEl()) || (selected.view && selected.view.el); if (selEl && (selEl.isContentEditable || (selEl.getAttribute && selEl.getAttribute('contenteditable') === 'true'))) { syncFromElement(selected, selEl, 'selected:view'); } -<<<<<<< ours } - // 2) Fallback: Selection im DOM suchen ->>>>>>> theirs -======= - // 1) Wenn ein ContentEditable aktiv ist, Blur auslösen, damit GrapesJS den Model-Content übernimmt - if (active && (active.isContentEditable || (active.getAttribute && active.getAttribute('contenteditable') === 'true'))) { - try { - active.dispatchEvent(new Event('blur', { bubbles: true })); - syncReason = 'blur:dispatched'; - } catch {} -======= ->>>>>>> theirs - } - - // 2) Fallback: Selection im DOM suchen ->>>>>>> theirs - if (!syncResult && doc && selectionEl && (selectionEl.isContentEditable || (selectionEl.getAttribute && selectionEl.getAttribute('contenteditable') === 'true'))) { - const root = (selectionEl.closest && selectionEl.closest('[data-gjs-type="text"]')) || selectionEl; - const id = root && root.getAttribute ? root.getAttribute('id') : null; - const wrapper = editor.getWrapper && editor.getWrapper(); - if (id && wrapper && wrapper.find) { - const found = wrapper.find(`#${id}`); - const comp = found && found[0]; - syncFromElement(comp, root, 'selection:root'); - } - } - -======= ->>>>>>> theirs writeDebugLog({ - event: 'save:sync:skipped', + event: 'save:sync:minimal', entityId: CURRENT_ENTITY_ID, sectionId: SECTION_ID || null, active: active ? { @@ -571,6 +576,8 @@ type: selected.get ? selected.get('type') : null, contentLen: selected.get ? String(selected.get('content') || '').length : 0, } : null, + syncResult, + syncReason, editorHtmlLen: (editor.getHtml && String(editor.getHtml() || '').length) || 0, editorHtmlPreview: (editor.getHtml && String(editor.getHtml() || '').slice(0, 300)) || '', });