12670d39fSLORTET(function () { 22670d39fSLORTET function initExtranetProsemirror() { 32670d39fSLORTET if (window.__extranetProsemirrorInitialized) return; 42670d39fSLORTET if (!window.Prosemirror || !window.Prosemirror.classes) return; 52670d39fSLORTET window.__extranetProsemirrorInitialized = true; 62670d39fSLORTET 72670d39fSLORTET const {classes: {MenuItem, AbstractMenuItemDispatcher}} = window.Prosemirror; 82670d39fSLORTET const polyfill = window.DokuWikiProsemirrorFileStatePolyfill || null; 92670d39fSLORTET let localMacroState = {noextranet: null, extranet: null}; 102670d39fSLORTET 112670d39fSLORTET const defaultMode = window.JSINFO && JSINFO.plugin_extranet_default_mode 122670d39fSLORTET ? String(JSINFO.plugin_extranet_default_mode).toLowerCase() 132670d39fSLORTET : 'allow'; 142670d39fSLORTET 15*ef5bb1f3SLORTET function isFixedMode() { 16*ef5bb1f3SLORTET return defaultMode === 'force_allow' || defaultMode === 'force_block'; 17*ef5bb1f3SLORTET } 18*ef5bb1f3SLORTET 192670d39fSLORTET function hiddenMenuItem() { 202670d39fSLORTET return new MenuItem({ 212670d39fSLORTET label: '', 222670d39fSLORTET render: () => { 232670d39fSLORTET const el = document.createElement('span'); 242670d39fSLORTET el.style.display = 'none'; 252670d39fSLORTET return el; 262670d39fSLORTET }, 272670d39fSLORTET command: () => false 282670d39fSLORTET }); 292670d39fSLORTET } 302670d39fSLORTET 312670d39fSLORTET function getNoExtranetLabel() { 322670d39fSLORTET return ( 332670d39fSLORTET (window.LANG && 342670d39fSLORTET LANG.plugins && 352670d39fSLORTET LANG.plugins.prosemirror && 362670d39fSLORTET LANG.plugins.prosemirror['label:noextranet']) || 372670d39fSLORTET (window.JSINFO && JSINFO.plugin_extranet_label_noextranet) || 382670d39fSLORTET 'Blocked from Extranet' 392670d39fSLORTET ); 402670d39fSLORTET } 412670d39fSLORTET 422670d39fSLORTET function getExtranetLabel() { 432670d39fSLORTET return ( 442670d39fSLORTET (window.JSINFO && JSINFO.plugin_extranet_label_extranet) || 452670d39fSLORTET 'Allowed from Extranet' 462670d39fSLORTET ); 472670d39fSLORTET } 482670d39fSLORTET 492670d39fSLORTET function getManagedMacroKey() { 50*ef5bb1f3SLORTET if (isFixedMode()) return null; 512670d39fSLORTET return defaultMode === 'block' ? 'extranet' : 'noextranet'; 522670d39fSLORTET } 532670d39fSLORTET 542670d39fSLORTET function getManagedMacroLabel() { 552670d39fSLORTET return getManagedMacroKey() === 'extranet' ? getExtranetLabel() : getNoExtranetLabel(); 562670d39fSLORTET } 572670d39fSLORTET 582670d39fSLORTET function getSettingsLabel() { 592670d39fSLORTET return ( 602670d39fSLORTET (window.LANG && 612670d39fSLORTET LANG.plugins && 622670d39fSLORTET LANG.plugins.prosemirror && 632670d39fSLORTET LANG.plugins.prosemirror['label:settings']) || 642670d39fSLORTET 'Page Settings' 652670d39fSLORTET ); 662670d39fSLORTET } 672670d39fSLORTET 682670d39fSLORTET function getSettingsChildLabels() { 692670d39fSLORTET const labels = []; 702670d39fSLORTET const fromLang = window.LANG && 712670d39fSLORTET LANG.plugins && 722670d39fSLORTET LANG.plugins.prosemirror 732670d39fSLORTET ? LANG.plugins.prosemirror 742670d39fSLORTET : {}; 752670d39fSLORTET 762670d39fSLORTET labels.push(fromLang['label:nocache'] || 'Deactivate Cache'); 772670d39fSLORTET labels.push(fromLang['label:notoc'] || 'Hide Table of Contents'); 782670d39fSLORTET labels.push('NOCACHE'); 792670d39fSLORTET labels.push('NOTOC'); 802670d39fSLORTET 812670d39fSLORTET return labels 822670d39fSLORTET .filter(Boolean) 832670d39fSLORTET .map((s) => String(s).trim().toLowerCase()); 842670d39fSLORTET } 852670d39fSLORTET 862670d39fSLORTET function findSettingsDropdown(menubar) { 872670d39fSLORTET const settingsLabel = getSettingsLabel(); 882670d39fSLORTET const knownChildLabels = getSettingsChildLabels(); 892670d39fSLORTET const dropdowns = menubar.querySelectorAll('.menuitem.dropdown'); 902670d39fSLORTET let found = null; 912670d39fSLORTET 922670d39fSLORTET dropdowns.forEach((dropdown) => { 932670d39fSLORTET if (found) return; 942670d39fSLORTET const labelEl = dropdown.querySelector(':scope > .menulabel'); 952670d39fSLORTET const dropdownLabelText = String((labelEl && labelEl.textContent) || '').trim(); 962670d39fSLORTET const dropdownLabelTitle = String((labelEl && labelEl.getAttribute('title')) || '').trim(); 972670d39fSLORTET 982670d39fSLORTET const looksLikeSettings = 992670d39fSLORTET dropdownLabelText === settingsLabel || 1002670d39fSLORTET dropdownLabelTitle === settingsLabel; 1012670d39fSLORTET 1022670d39fSLORTET const dropdownContent = dropdown.querySelector('.dropdown_content'); 1032670d39fSLORTET const childTexts = dropdownContent 1042670d39fSLORTET ? Array.from(dropdownContent.querySelectorAll('.menuitem .menulabel')) 1052670d39fSLORTET .map((el) => ( 1062670d39fSLORTET String(el.textContent || el.getAttribute('title') || '') 1072670d39fSLORTET .trim() 1082670d39fSLORTET .toLowerCase() 1092670d39fSLORTET )) 1102670d39fSLORTET : []; 1112670d39fSLORTET 1122670d39fSLORTET const hasKnownSettingsChildren = childTexts.some((txt) => knownChildLabels.includes(txt)); 1132670d39fSLORTET 1142670d39fSLORTET if (looksLikeSettings || hasKnownSettingsChildren) { 1152670d39fSLORTET found = dropdown; 1162670d39fSLORTET } 1172670d39fSLORTET }); 1182670d39fSLORTET 1192670d39fSLORTET return found; 1202670d39fSLORTET } 1212670d39fSLORTET 1222670d39fSLORTET 1232670d39fSLORTET window.Prosemirror.pluginSchemas.push((nodes, marks) => { 1242670d39fSLORTET const doc = nodes.get('doc'); 1252670d39fSLORTET if (!doc) return {nodes, marks}; 1262670d39fSLORTET 1272670d39fSLORTET const attrs = {...(doc.attrs || {})}; 1282670d39fSLORTET let changed = false; 1292670d39fSLORTET 1302670d39fSLORTET if (typeof attrs.noextranet === 'undefined') { 1312670d39fSLORTET attrs.noextranet = {default: false}; 1322670d39fSLORTET changed = true; 1332670d39fSLORTET } 1342670d39fSLORTET if (typeof attrs.extranet === 'undefined') { 1352670d39fSLORTET attrs.extranet = {default: false}; 1362670d39fSLORTET changed = true; 1372670d39fSLORTET } 1382670d39fSLORTET 1392670d39fSLORTET if (!changed) return {nodes, marks}; 1402670d39fSLORTET 1412670d39fSLORTET const updatedDoc = { 1422670d39fSLORTET ...doc, 1432670d39fSLORTET attrs 1442670d39fSLORTET }; 1452670d39fSLORTET nodes = nodes.update('doc', updatedDoc); 1462670d39fSLORTET return {nodes, marks}; 1472670d39fSLORTET }); 1482670d39fSLORTET 1492670d39fSLORTET function readMacroStateFromDoc(doc) { 1502670d39fSLORTET if (!doc) return null; 1512670d39fSLORTET 1522670d39fSLORTET if (doc.attrs && (typeof doc.attrs.noextranet !== 'undefined' || typeof doc.attrs.extranet !== 'undefined')) { 1532670d39fSLORTET return { 1542670d39fSLORTET noextranet: !!doc.attrs.noextranet, 1552670d39fSLORTET extranet: !!doc.attrs.extranet 1562670d39fSLORTET }; 1572670d39fSLORTET } 1582670d39fSLORTET 1592670d39fSLORTET try { 1602670d39fSLORTET const raw = doc.textBetween(0, doc.content.size, '\n', '\n'); 1612670d39fSLORTET return { 1622670d39fSLORTET noextranet: /~~\s*NOEXTRANET\s*~~/i.test(raw), 1632670d39fSLORTET extranet: /~~\s*EXTRANET\s*~~/i.test(raw) 1642670d39fSLORTET }; 1652670d39fSLORTET } catch (e) { 1662670d39fSLORTET return null; 1672670d39fSLORTET } 1682670d39fSLORTET } 1692670d39fSLORTET 1702670d39fSLORTET function readMacroStateFromJsonField() { 1712670d39fSLORTET const input = document.querySelector('#dw__editform [name="prosemirror_json"]'); 1722670d39fSLORTET if (!input || !input.value) return null; 1732670d39fSLORTET 1742670d39fSLORTET try { 1752670d39fSLORTET const json = JSON.parse(input.value); 1762670d39fSLORTET if (json && json.attrs) { 1772670d39fSLORTET if (typeof json.attrs.noextranet !== 'undefined' || typeof json.attrs.extranet !== 'undefined') { 1782670d39fSLORTET return { 1792670d39fSLORTET noextranet: !!json.attrs.noextranet, 1802670d39fSLORTET extranet: !!json.attrs.extranet 1812670d39fSLORTET }; 1822670d39fSLORTET } 1832670d39fSLORTET } 1842670d39fSLORTET } catch (e) { 1852670d39fSLORTET // fallback below 1862670d39fSLORTET } 1872670d39fSLORTET 1882670d39fSLORTET const raw = String(input.value || ''); 1892670d39fSLORTET return { 1902670d39fSLORTET noextranet: /~~\s*NOEXTRANET\s*~~/i.test(raw), 1912670d39fSLORTET extranet: /~~\s*EXTRANET\s*~~/i.test(raw) 1922670d39fSLORTET }; 1932670d39fSLORTET } 1942670d39fSLORTET 1952670d39fSLORTET function readMacroStateFromWikiTextarea() { 1962670d39fSLORTET const textarea = document.querySelector('#dw__editform textarea[name="wikitext"], #dw__editform #wiki__text'); 1972670d39fSLORTET if (!textarea) return null; 1982670d39fSLORTET const raw = String(textarea.value || ''); 1992670d39fSLORTET return { 2002670d39fSLORTET noextranet: /~~\s*NOEXTRANET\s*~~/i.test(raw), 2012670d39fSLORTET extranet: /~~\s*EXTRANET\s*~~/i.test(raw) 2022670d39fSLORTET }; 2032670d39fSLORTET } 2042670d39fSLORTET 2052670d39fSLORTET function persistMacroStateInJsonField(state, macroState) { 2062670d39fSLORTET const input = document.querySelector('#dw__editform [name="prosemirror_json"]'); 2072670d39fSLORTET if (!input || !state || !state.doc) return false; 2082670d39fSLORTET 2092670d39fSLORTET try { 2102670d39fSLORTET const json = polyfill && typeof polyfill.mergeAttrsFromHiddenJson === 'function' 2112670d39fSLORTET ? polyfill.mergeAttrsFromHiddenJson(state, input, { 2122670d39fSLORTET noextranet: !!macroState.noextranet, 2132670d39fSLORTET extranet: !!macroState.extranet 2142670d39fSLORTET }) 2152670d39fSLORTET : state.doc.toJSON(); 2162670d39fSLORTET 2172670d39fSLORTET if (!json) return false; 2182670d39fSLORTET if (!(polyfill && typeof polyfill.mergeAttrsFromHiddenJson === 'function')) { 2192670d39fSLORTET json.attrs = { 2202670d39fSLORTET ...(json.attrs || {}), 2212670d39fSLORTET noextranet: !!macroState.noextranet, 2222670d39fSLORTET extranet: !!macroState.extranet 2232670d39fSLORTET }; 2242670d39fSLORTET input.value = JSON.stringify(json); 2252670d39fSLORTET } 2262670d39fSLORTET return true; 2272670d39fSLORTET } catch (e) { 2282670d39fSLORTET return false; 2292670d39fSLORTET } 2302670d39fSLORTET } 2312670d39fSLORTET 2322670d39fSLORTET function getCurrentEditorView() { 2332670d39fSLORTET return window.Prosemirror && window.Prosemirror.view ? window.Prosemirror.view : null; 2342670d39fSLORTET } 2352670d39fSLORTET 2362670d39fSLORTET function syncCurrentMacroStateToJsonField() { 2372670d39fSLORTET const view = getCurrentEditorView(); 2382670d39fSLORTET if (!view || !view.state) return false; 2392670d39fSLORTET const macroState = getMacroState(view.state); 2402670d39fSLORTET return persistMacroStateInJsonField(view.state, macroState); 2412670d39fSLORTET } 2422670d39fSLORTET 2432670d39fSLORTET function getMacroState(state) { 2442670d39fSLORTET // Prefer local state right after interactions to avoid one-tick lag from editor state. 2452670d39fSLORTET if (localMacroState.noextranet !== null || localMacroState.extranet !== null) { 2462670d39fSLORTET return { 2472670d39fSLORTET noextranet: !!localMacroState.noextranet, 2482670d39fSLORTET extranet: !!localMacroState.extranet 2492670d39fSLORTET }; 2502670d39fSLORTET } 2512670d39fSLORTET 2522670d39fSLORTET const fromDoc = state && state.doc ? readMacroStateFromDoc(state.doc) : null; 2532670d39fSLORTET if (fromDoc) { 2542670d39fSLORTET return fromDoc; 2552670d39fSLORTET } 2562670d39fSLORTET 2572670d39fSLORTET const fromJson = readMacroStateFromJsonField(); 2582670d39fSLORTET if (fromJson) return fromJson; 2592670d39fSLORTET 2602670d39fSLORTET return {noextranet: false, extranet: false}; 2612670d39fSLORTET } 2622670d39fSLORTET 2632670d39fSLORTET function applyMacroStateToText(text, macroState) { 2642670d39fSLORTET const cleaned = String(text || '').replace(/^[\t ]*~~[\t ]*(NOEXTRANET|EXTRANET)[\t ]*~~[\t ]*(\r?\n)?/gimu, '').replace(/\s+$/, ''); 2652670d39fSLORTET 2662670d39fSLORTET if (macroState && macroState.noextranet) { 2672670d39fSLORTET return cleaned ? `${cleaned}\n\n~~NOEXTRANET~~\n` : '~~NOEXTRANET~~\n'; 2682670d39fSLORTET } 2692670d39fSLORTET 2702670d39fSLORTET if (macroState && macroState.extranet) { 2712670d39fSLORTET return cleaned ? `${cleaned}\n\n~~EXTRANET~~\n` : '~~EXTRANET~~\n'; 2722670d39fSLORTET } 2732670d39fSLORTET 2742670d39fSLORTET return cleaned ? `${cleaned}\n` : ''; 2752670d39fSLORTET } 2762670d39fSLORTET 2772670d39fSLORTET function ensureShowDefaultEditorWrapped() { 2782670d39fSLORTET if (window.__extranetWrappedShowDefaultEditor) return true; 2792670d39fSLORTET if (typeof window.showDefaultEditor !== 'function') return false; 2802670d39fSLORTET 2812670d39fSLORTET const originalShowDefaultEditor = window.showDefaultEditor; 2822670d39fSLORTET window.showDefaultEditor = function extranetShowDefaultEditor(text) { 2832670d39fSLORTET const view = getCurrentEditorView(); 2842670d39fSLORTET const nextText = applyMacroStateToText(text, getMacroState(view && view.state)); 2852670d39fSLORTET return originalShowDefaultEditor.call(this, nextText); 2862670d39fSLORTET }; 2872670d39fSLORTET window.__extranetWrappedShowDefaultEditor = true; 2882670d39fSLORTET return true; 2892670d39fSLORTET } 2902670d39fSLORTET 2912670d39fSLORTET function renderCheckboxIcon(checked) { 2922670d39fSLORTET const ns = 'http://www.w3.org/2000/svg'; 2932670d39fSLORTET const svg = document.createElementNS(ns, 'svg'); 2942670d39fSLORTET svg.setAttribute('viewBox', '0 0 24 24'); 2952670d39fSLORTET 2962670d39fSLORTET const path = document.createElementNS(ns, 'path'); 2972670d39fSLORTET if (checked) { 2982670d39fSLORTET path.setAttribute('d', 'M19,19H5V5H15V3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V11H19M7.91,10.08L6.5,11.5L11,16L21,6L19.59,4.58L11,13.17L7.91,10.08Z'); 2992670d39fSLORTET } else { 3002670d39fSLORTET path.setAttribute('d', 'M19,3H5C3.89,3 3,3.89 3,5V19A2,2 0 0,0 5,21H19A2,2 0 0,0 21,19V5C21,3.89 20.1,3 19,3M19,5V19H5V5H19Z'); 3012670d39fSLORTET } 3022670d39fSLORTET svg.appendChild(path); 3032670d39fSLORTET 3042670d39fSLORTET const span = document.createElement('span'); 3052670d39fSLORTET span.className = 'menuicon'; 3062670d39fSLORTET span.appendChild(svg); 3072670d39fSLORTET return span; 3082670d39fSLORTET } 3092670d39fSLORTET 3102670d39fSLORTET function syncProxyCheckboxIcon(proxy, checked) { 3112670d39fSLORTET const next = checked ? '1' : '0'; 3122670d39fSLORTET if (proxy.dataset.extranetChecked === next && proxy.querySelector(':scope > .menuicon')) { 3132670d39fSLORTET return; 3142670d39fSLORTET } 3152670d39fSLORTET const oldIcon = proxy.querySelector(':scope > .menuicon'); 3162670d39fSLORTET const newIcon = renderCheckboxIcon(checked); 3172670d39fSLORTET if (oldIcon) { 3182670d39fSLORTET oldIcon.replaceWith(newIcon); 3192670d39fSLORTET } else { 3202670d39fSLORTET proxy.insertBefore(newIcon, proxy.firstChild || null); 3212670d39fSLORTET } 3222670d39fSLORTET proxy.dataset.extranetChecked = next; 3232670d39fSLORTET } 3242670d39fSLORTET 3252670d39fSLORTET function refreshAllExtranetMenuItemsFromMacroState(macroState) { 3262670d39fSLORTET const items = document.querySelectorAll('.prosemirror_wrapper .menuitem.extranet-page-setting-item'); 3272670d39fSLORTET const modifiedElements = []; 3282670d39fSLORTET const itemStates = []; 3292670d39fSLORTET items.forEach((item) => { 3302670d39fSLORTET const isNoextranet = item.classList.contains('extranet-noextranet-item'); 3312670d39fSLORTET const key = isNoextranet ? 'noextranet' : 'extranet'; 3322670d39fSLORTET const active = !!macroState[key]; 3332670d39fSLORTET const wasActive = item.dataset.extranetChecked === '1'; 3342670d39fSLORTET item.classList.remove('is-active'); 3352670d39fSLORTET item.setAttribute('aria-checked', active ? 'true' : 'false'); 3362670d39fSLORTET const expectedDataset = active ? '1' : '0'; 3372670d39fSLORTET const hasIcon = !!item.querySelector(':scope > .menuicon'); 3382670d39fSLORTET if (wasActive !== active || !hasIcon || item.dataset.extranetChecked !== expectedDataset) { 3392670d39fSLORTET syncProxyCheckboxIcon(item, active); 3402670d39fSLORTET } 3412670d39fSLORTET itemStates.push({ 3422670d39fSLORTET key, 3432670d39fSLORTET before: wasActive, 3442670d39fSLORTET after: active, 3452670d39fSLORTET changed: wasActive !== active, 3462670d39fSLORTET element: item 3472670d39fSLORTET }); 3482670d39fSLORTET if (wasActive !== active) { 3492670d39fSLORTET modifiedElements.push(item); 3502670d39fSLORTET } 3512670d39fSLORTET }); 3522670d39fSLORTET // Debug logging disabled: this runs frequently during editor updates. 3532670d39fSLORTET } 3542670d39fSLORTET 3552670d39fSLORTET function refreshAllExtranetMenuItems(state) { 3562670d39fSLORTET refreshAllExtranetMenuItemsFromMacroState(getMacroState(state)); 3572670d39fSLORTET } 3582670d39fSLORTET 3592670d39fSLORTET function setDocMacroState(view, macroState) { 3602670d39fSLORTET const desired = { 3612670d39fSLORTET noextranet: !!macroState.noextranet, 3622670d39fSLORTET extranet: !!macroState.extranet 3632670d39fSLORTET }; 3642670d39fSLORTET localMacroState = desired; 3652670d39fSLORTET 3662670d39fSLORTET const hasDesiredAttrs = () => { 3672670d39fSLORTET const attrs = view.state && view.state.doc && view.state.doc.attrs ? view.state.doc.attrs : {}; 3682670d39fSLORTET return !!attrs.noextranet === desired.noextranet && !!attrs.extranet === desired.extranet; 3692670d39fSLORTET }; 3702670d39fSLORTET 3712670d39fSLORTET const {state} = view; 3722670d39fSLORTET let tr = state.tr; 3732670d39fSLORTET 3742670d39fSLORTET if (typeof tr.setDocAttr === 'function') { 3752670d39fSLORTET tr = tr.setDocAttr('noextranet', desired.noextranet); 3762670d39fSLORTET tr = tr.setDocAttr('extranet', desired.extranet); 3772670d39fSLORTET view.dispatch(tr); 3782670d39fSLORTET if (hasDesiredAttrs()) { 3792670d39fSLORTET persistMacroStateInJsonField(view.state, desired); 3802670d39fSLORTET return true; 3812670d39fSLORTET } 3822670d39fSLORTET } 3832670d39fSLORTET 3842670d39fSLORTET const classes = (window.Prosemirror && window.Prosemirror.classes) || {}; 3852670d39fSLORTET const stepCtor = Object.values(classes).find( 3862670d39fSLORTET (Ctor) => typeof Ctor === 'function' && /DocAttr/i.test(Ctor.name || '') 3872670d39fSLORTET ); 3882670d39fSLORTET if (stepCtor) { 3892670d39fSLORTET try { 3902670d39fSLORTET tr = state.tr; 3912670d39fSLORTET tr = tr.step(new stepCtor('noextranet', desired.noextranet, 'setDocAttr')); 3922670d39fSLORTET tr = tr.step(new stepCtor('extranet', desired.extranet, 'setDocAttr')); 3932670d39fSLORTET view.dispatch(tr); 3942670d39fSLORTET if (hasDesiredAttrs()) { 3952670d39fSLORTET persistMacroStateInJsonField(view.state, desired); 3962670d39fSLORTET return true; 3972670d39fSLORTET } 3982670d39fSLORTET } catch (e) { 3992670d39fSLORTET // fallback below 4002670d39fSLORTET } 4012670d39fSLORTET } 4022670d39fSLORTET 4032670d39fSLORTET return persistMacroStateInJsonField(state, desired); 4042670d39fSLORTET } 4052670d39fSLORTET 4062670d39fSLORTET function getSourceMacroState() { 4072670d39fSLORTET const fromJson = readMacroStateFromJsonField(); 4082670d39fSLORTET if (fromJson) return fromJson; 4092670d39fSLORTET const fromTextarea = readMacroStateFromWikiTextarea(); 4102670d39fSLORTET if (fromTextarea) return fromTextarea; 4112670d39fSLORTET return null; 4122670d39fSLORTET } 4132670d39fSLORTET 4142670d39fSLORTET function bootstrapStateFromSource() { 4152670d39fSLORTET const view = getCurrentEditorView(); 4162670d39fSLORTET if (!view || !view.state || !view.state.doc) return; 4172670d39fSLORTET 4182670d39fSLORTET const sourceState = getSourceMacroState(); 4192670d39fSLORTET const docState = readMacroStateFromDoc(view.state.doc); 4202670d39fSLORTET if (!sourceState) return; 4212670d39fSLORTET 4222670d39fSLORTET const current = docState || {noextranet: false, extranet: false}; 4232670d39fSLORTET if (!!current.noextranet === !!sourceState.noextranet && !!current.extranet === !!sourceState.extranet) return; 4242670d39fSLORTET 4252670d39fSLORTET setDocMacroState(view, sourceState); 4262670d39fSLORTET } 4272670d39fSLORTET 4282670d39fSLORTET function getMacroLabel(key) { 4292670d39fSLORTET return key === 'extranet' ? getExtranetLabel() : getNoExtranetLabel(); 4302670d39fSLORTET } 4312670d39fSLORTET 4322670d39fSLORTET function isMacroActive(state, key) { 4332670d39fSLORTET const macroState = getMacroState(state); 4342670d39fSLORTET return !!macroState[key]; 4352670d39fSLORTET } 4362670d39fSLORTET 4372670d39fSLORTET function buildStateForToggle(state, key) { 4382670d39fSLORTET const active = isMacroActive(state, key); 4392670d39fSLORTET if (key === 'noextranet') { 4402670d39fSLORTET return active 4412670d39fSLORTET ? {noextranet: false, extranet: false} 4422670d39fSLORTET : {noextranet: true, extranet: false}; 4432670d39fSLORTET } 4442670d39fSLORTET 4452670d39fSLORTET return active 4462670d39fSLORTET ? {noextranet: false, extranet: false} 4472670d39fSLORTET : {noextranet: false, extranet: true}; 4482670d39fSLORTET } 4492670d39fSLORTET 4502670d39fSLORTET function createMacroDispatcher(key) { 4512670d39fSLORTET return class extends AbstractMenuItemDispatcher { 4522670d39fSLORTET static isAvailable(schema) { 4532670d39fSLORTET return !!(schema && schema.nodes && schema.nodes.doc); 4542670d39fSLORTET } 4552670d39fSLORTET 4562670d39fSLORTET static getMenuItem(schema) { 4572670d39fSLORTET if (!this.isAvailable(schema)) return hiddenMenuItem(); 4582670d39fSLORTET 4592670d39fSLORTET return new MenuItem({ 4602670d39fSLORTET label: getMacroLabel(key), 4612670d39fSLORTET render: (view) => { 4622670d39fSLORTET const label = getMacroLabel(key); 4632670d39fSLORTET const item = document.createElement('span'); 4642670d39fSLORTET item.className = `menuitem extranet-page-setting-item extranet-${key}-item`; 4652670d39fSLORTET 4662670d39fSLORTET item.appendChild(renderCheckboxIcon(isMacroActive(view.state, key))); 4672670d39fSLORTET 4682670d39fSLORTET const title = document.createElement('span'); 4692670d39fSLORTET title.className = 'menulabel'; 4702670d39fSLORTET title.setAttribute('title', label); 4712670d39fSLORTET title.textContent = label; 4722670d39fSLORTET item.appendChild(title); 4732670d39fSLORTET 4742670d39fSLORTET return item; 4752670d39fSLORTET }, 4762670d39fSLORTET update: (view, dom) => { 4772670d39fSLORTET const checked = isMacroActive(view.state, key); 4782670d39fSLORTET if (dom) { 4792670d39fSLORTET syncProxyCheckboxIcon(dom, checked); 4802670d39fSLORTET const labelEl = dom.querySelector('.menulabel'); 4812670d39fSLORTET if (labelEl) { 4822670d39fSLORTET const label = getMacroLabel(key); 4832670d39fSLORTET labelEl.textContent = label; 4842670d39fSLORTET labelEl.setAttribute('title', label); 4852670d39fSLORTET } 4862670d39fSLORTET } 4872670d39fSLORTET }, 4882670d39fSLORTET command: (state, dispatch, view) => { 4892670d39fSLORTET if (!dispatch || !view) return true; 4902670d39fSLORTET const currentState = getMacroState(state); 4912670d39fSLORTET const nextState = buildStateForToggle(state, key); 4922670d39fSLORTET const applied = setDocMacroState(view, nextState); 4932670d39fSLORTET if (applied) { 4942670d39fSLORTET // Force immediate UI sync from the intended target state. 4952670d39fSLORTET refreshAllExtranetMenuItemsFromMacroState(nextState); 4962670d39fSLORTET scheduleMoveBurst(); 4972670d39fSLORTET } 4982670d39fSLORTET return applied; 4992670d39fSLORTET }, 5002670d39fSLORTET // Keep parent "Modules" menu from turning blue for extranet page settings. 5012670d39fSLORTET isActive: () => false 5022670d39fSLORTET }); 5032670d39fSLORTET } 5042670d39fSLORTET }; 5052670d39fSLORTET } 5062670d39fSLORTET 507*ef5bb1f3SLORTET const managedMacroKey = getManagedMacroKey(); 508*ef5bb1f3SLORTET if (managedMacroKey) { 509*ef5bb1f3SLORTET window.Prosemirror.pluginMenuItemDispatchers.push(createMacroDispatcher(managedMacroKey)); 510*ef5bb1f3SLORTET } 5112670d39fSLORTET 5122670d39fSLORTET function moveExtranetItemsToSettingsMenu() { 5132670d39fSLORTET const menubars = document.querySelectorAll('.prosemirror_wrapper .menubar'); 5142670d39fSLORTET 5152670d39fSLORTET menubars.forEach((menubar) => { 5162670d39fSLORTET const sourceItems = menubar.querySelectorAll('.menuitem.extranet-page-setting-item'); 5172670d39fSLORTET if (!sourceItems.length) return; 5182670d39fSLORTET 5192670d39fSLORTET const settingsDropdown = findSettingsDropdown(menubar); 5202670d39fSLORTET 5212670d39fSLORTET if (!settingsDropdown) return; 5222670d39fSLORTET 5232670d39fSLORTET const target = settingsDropdown.querySelector('.dropdown_content'); 5242670d39fSLORTET if (!target) return; 5252670d39fSLORTET 5262670d39fSLORTET sourceItems.forEach((sourceItem) => { 5272670d39fSLORTET if (sourceItem.parentElement !== target) { 5282670d39fSLORTET target.appendChild(sourceItem); 5292670d39fSLORTET } 5302670d39fSLORTET }); 5312670d39fSLORTET 5322670d39fSLORTET const view = window.Prosemirror && window.Prosemirror.view; 5332670d39fSLORTET const currentState = view && view.state ? view.state : null; 5342670d39fSLORTET 5352670d39fSLORTET sourceItems.forEach((sourceItem) => { 5362670d39fSLORTET const isNoextranet = sourceItem.classList.contains('extranet-noextranet-item'); 5372670d39fSLORTET const key = isNoextranet ? 'noextranet' : 'extranet'; 5382670d39fSLORTET const active = isMacroActive(currentState, key); 5392670d39fSLORTET sourceItem.classList.remove('is-active'); 5402670d39fSLORTET syncProxyCheckboxIcon(sourceItem, !!active); 5412670d39fSLORTET }); 5422670d39fSLORTET }); 5432670d39fSLORTET 5442670d39fSLORTET const view = window.Prosemirror && window.Prosemirror.view; 5452670d39fSLORTET if (view && view.state) { 5462670d39fSLORTET refreshAllExtranetMenuItems(view.state); 5472670d39fSLORTET } 5482670d39fSLORTET } 5492670d39fSLORTET 5502670d39fSLORTET const scheduleMoveBurst = polyfill && typeof polyfill.makeBurstScheduler === 'function' 5512670d39fSLORTET ? polyfill.makeBurstScheduler(moveExtranetItemsToSettingsMenu) 5522670d39fSLORTET : (function () { 5532670d39fSLORTET let scheduled = false; 5542670d39fSLORTET function scheduleMove() { 5552670d39fSLORTET if (scheduled) return; 5562670d39fSLORTET scheduled = true; 5572670d39fSLORTET window.requestAnimationFrame(() => { 5582670d39fSLORTET scheduled = false; 5592670d39fSLORTET moveExtranetItemsToSettingsMenu(); 5602670d39fSLORTET }); 5612670d39fSLORTET } 5622670d39fSLORTET 5632670d39fSLORTET return function () { 5642670d39fSLORTET scheduleMove(); 5652670d39fSLORTET window.setTimeout(scheduleMove, 0); 5662670d39fSLORTET window.setTimeout(scheduleMove, 100); 5672670d39fSLORTET window.setTimeout(scheduleMove, 300); 5682670d39fSLORTET }; 5692670d39fSLORTET })(); 5702670d39fSLORTET 5712670d39fSLORTET if (polyfill && typeof polyfill.bindCommonEditorLifecycle === 'function') { 5722670d39fSLORTET polyfill.bindCommonEditorLifecycle({ 5732670d39fSLORTET onSwitchToText: function () { 5742670d39fSLORTET ensureShowDefaultEditorWrapped(); 5752670d39fSLORTET syncCurrentMacroStateToJsonField(); 5762670d39fSLORTET }, 5772670d39fSLORTET onSubmit: syncCurrentMacroStateToJsonField, 5782670d39fSLORTET onEditorToggle: scheduleMoveBurst, 5792670d39fSLORTET onAfterSwitch: scheduleMoveBurst 5802670d39fSLORTET }); 5812670d39fSLORTET } else { 5822670d39fSLORTET document.addEventListener('mousedown', (event) => { 5832670d39fSLORTET const target = event.target instanceof Element ? event.target : null; 5842670d39fSLORTET if (!target) return; 5852670d39fSLORTET if (!target.closest('.plugin_prosemirror_useWYSIWYG')) return; 5862670d39fSLORTET ensureShowDefaultEditorWrapped(); 5872670d39fSLORTET syncCurrentMacroStateToJsonField(); 5882670d39fSLORTET }, true); 5892670d39fSLORTET 5902670d39fSLORTET document.addEventListener('click', (event) => { 5912670d39fSLORTET const target = event.target instanceof Element ? event.target : null; 5922670d39fSLORTET if (!target) return; 5932670d39fSLORTET if (target.closest('.plugin_prosemirror_useWYSIWYG')) { 5942670d39fSLORTET scheduleMoveBurst(); 5952670d39fSLORTET } 5962670d39fSLORTET 5972670d39fSLORTET const submitControl = target.closest('#dw__editform button[type="submit"], #dw__editform input[type="submit"]'); 5982670d39fSLORTET if (!submitControl) return; 5992670d39fSLORTET syncCurrentMacroStateToJsonField(); 6002670d39fSLORTET }, true); 6012670d39fSLORTET 6022670d39fSLORTET document.addEventListener('submit', (event) => { 6032670d39fSLORTET const form = event.target instanceof HTMLFormElement ? event.target : null; 6042670d39fSLORTET if (!form || form.id !== 'dw__editform') return; 6052670d39fSLORTET syncCurrentMacroStateToJsonField(); 6062670d39fSLORTET }, true); 6072670d39fSLORTET 6082670d39fSLORTET jQuery(window).on('fastwiki:afterSwitch', function () { 6092670d39fSLORTET scheduleMoveBurst(); 6102670d39fSLORTET }); 6112670d39fSLORTET } 6122670d39fSLORTET 6132670d39fSLORTET ensureShowDefaultEditorWrapped(); 6142670d39fSLORTET window.setTimeout(ensureShowDefaultEditorWrapped, 0); 615*ef5bb1f3SLORTET if (!isFixedMode()) { 6162670d39fSLORTET bootstrapStateFromSource(); 6172670d39fSLORTET window.setTimeout(bootstrapStateFromSource, 0); 6182670d39fSLORTET scheduleMoveBurst(); 6192670d39fSLORTET } 620*ef5bb1f3SLORTET } 6212670d39fSLORTET 6222670d39fSLORTET jQuery(document).on('PROSEMIRROR_API_INITIALIZED', initExtranetProsemirror); 6232670d39fSLORTET initExtranetProsemirror(); 6242670d39fSLORTET})(); 625