xref: /plugin/catmenu/script/prosemirror.js (revision 6983cdfd4483215ff5a1e573925c9c612964e790)
1*6983cdfdSLORTET(function () {
2*6983cdfdSLORTET    function initializeCatmenuProsemirror() {
3*6983cdfdSLORTET        if (window.__catmenuProsemirrorInitialized) return;
4*6983cdfdSLORTET        if (!window.Prosemirror || !window.Prosemirror.classes) return;
5*6983cdfdSLORTET        window.__catmenuProsemirrorInitialized = true;
6*6983cdfdSLORTET
7*6983cdfdSLORTET        const {classes: {MenuItem, AbstractMenuItemDispatcher}} = window.Prosemirror;
8*6983cdfdSLORTET        const i18n = (window.LANG && LANG.plugins && LANG.plugins.catmenu) ? LANG.plugins.catmenu : {};
9*6983cdfdSLORTET        function hiddenMenuItem() {
10*6983cdfdSLORTET            return new MenuItem({
11*6983cdfdSLORTET                label: '',
12*6983cdfdSLORTET                render: () => {
13*6983cdfdSLORTET                    const el = document.createElement('span');
14*6983cdfdSLORTET                    el.style.display = 'none';
15*6983cdfdSLORTET                    return el;
16*6983cdfdSLORTET                },
17*6983cdfdSLORTET                command: () => false
18*6983cdfdSLORTET            });
19*6983cdfdSLORTET        }
20*6983cdfdSLORTET
21*6983cdfdSLORTET        function t(key, fallback) {
22*6983cdfdSLORTET            return i18n[key] || fallback;
23*6983cdfdSLORTET        }
24*6983cdfdSLORTET
25*6983cdfdSLORTET        function shouldShowInEditorMenu() {
26*6983cdfdSLORTET            const raw = window.JSINFO &&
27*6983cdfdSLORTET                JSINFO.plugins &&
28*6983cdfdSLORTET                JSINFO.plugins.catmenu
29*6983cdfdSLORTET                ? JSINFO.plugins.catmenu.show_in_editor_menu
30*6983cdfdSLORTET                : true;
31*6983cdfdSLORTET
32*6983cdfdSLORTET            if (typeof raw === 'boolean') return raw;
33*6983cdfdSLORTET            const normalized = String(raw).trim().toLowerCase();
34*6983cdfdSLORTET            return !(normalized === '0' || normalized === 'false' || normalized === 'off' || normalized === 'no');
35*6983cdfdSLORTET        }
36*6983cdfdSLORTET
37*6983cdfdSLORTET        window.Prosemirror.pluginSchemas.push((nodes, marks) => {
38*6983cdfdSLORTET            nodes = nodes.addToEnd('catmenu', {
39*6983cdfdSLORTET                group: 'protected_block',
40*6983cdfdSLORTET                inline: false,
41*6983cdfdSLORTET                selectable: true,
42*6983cdfdSLORTET                draggable: true,
43*6983cdfdSLORTET                defining: true,
44*6983cdfdSLORTET                isolating: true,
45*6983cdfdSLORTET                code: true,
46*6983cdfdSLORTET                attrs: {
47*6983cdfdSLORTET                    syntax: {default: '{{catmenu>.}}'}
48*6983cdfdSLORTET                },
49*6983cdfdSLORTET                toDOM: (node) => ['pre', {class: 'dwplugin', 'data-pluginname': 'catmenu'}, node.attrs.syntax],
50*6983cdfdSLORTET                parseDOM: [{
51*6983cdfdSLORTET                    tag: 'pre.dwplugin[data-pluginname="catmenu"]',
52*6983cdfdSLORTET                    getAttrs: (dom) => ({syntax: (dom.textContent || '{{catmenu>.}}').trim()})
53*6983cdfdSLORTET                }]
54*6983cdfdSLORTET            });
55*6983cdfdSLORTET            return {nodes, marks};
56*6983cdfdSLORTET        });
57*6983cdfdSLORTET
58*6983cdfdSLORTET        function parseCatmenuSyntax(syntax) {
59*6983cdfdSLORTET            const m = (syntax || '').match(/^\{\{catmenu>(.*?)\}\}$/i);
60*6983cdfdSLORTET            if (!m) return null;
61*6983cdfdSLORTET            return {namespace: (m[1] || '.').trim() || '.'};
62*6983cdfdSLORTET        }
63*6983cdfdSLORTET
64*6983cdfdSLORTET        function buildCatmenuSyntax(values) {
65*6983cdfdSLORTET            return '{{catmenu>' + ((values && values.namespace) ? values.namespace : '.') + '}}';
66*6983cdfdSLORTET        }
67*6983cdfdSLORTET
68*6983cdfdSLORTET        function formatCatmenuLabel(values) {
69*6983cdfdSLORTET            return 'CatMenu: ' + (values.namespace || '.');
70*6983cdfdSLORTET        }
71*6983cdfdSLORTET
72*6983cdfdSLORTET        function getFolderIconUrl() {
73*6983cdfdSLORTET            const svg = "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill='%232f6fae' d='M10 4l2 2h8a2 2 0 0 1 2 2v2H2V6a2 2 0 0 1 2-2h6z'/><path fill='%233f88c8' d='M2 10h20v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-8z'/></svg>";
74*6983cdfdSLORTET            return 'data:image/svg+xml;utf8,' + encodeURIComponent(svg);
75*6983cdfdSLORTET        }
76*6983cdfdSLORTET
77*6983cdfdSLORTET        function getFolderMenuIcon() {
78*6983cdfdSLORTET            const ns = 'http://www.w3.org/2000/svg';
79*6983cdfdSLORTET            const svg = document.createElementNS(ns, 'svg');
80*6983cdfdSLORTET            svg.setAttribute('viewBox', '0 0 24 24');
81*6983cdfdSLORTET
82*6983cdfdSLORTET            const path1 = document.createElementNS(ns, 'path');
83*6983cdfdSLORTET            path1.setAttribute('d', 'M10 4l2 2h8a2 2 0 0 1 2 2v2H2V6a2 2 0 0 1 2-2h6z');
84*6983cdfdSLORTET            path1.setAttribute('fill', 'currentColor');
85*6983cdfdSLORTET            svg.appendChild(path1);
86*6983cdfdSLORTET
87*6983cdfdSLORTET            const path2 = document.createElementNS(ns, 'path');
88*6983cdfdSLORTET            path2.setAttribute('d', 'M2 10h20v8a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2v-8z');
89*6983cdfdSLORTET            path2.setAttribute('fill', 'currentColor');
90*6983cdfdSLORTET            svg.appendChild(path2);
91*6983cdfdSLORTET            return svg;
92*6983cdfdSLORTET        }
93*6983cdfdSLORTET
94*6983cdfdSLORTET        function isLegacyCatmenuPluginNode(node) {
95*6983cdfdSLORTET            return !!(
96*6983cdfdSLORTET                node &&
97*6983cdfdSLORTET                node.type &&
98*6983cdfdSLORTET                (node.type.name === 'dwplugin_inline' || node.type.name === 'dwplugin_block') &&
99*6983cdfdSLORTET                node.attrs &&
100*6983cdfdSLORTET                node.attrs['data-pluginname'] === 'catmenu'
101*6983cdfdSLORTET            );
102*6983cdfdSLORTET        }
103*6983cdfdSLORTET
104*6983cdfdSLORTET        function isCatmenuNode(node) {
105*6983cdfdSLORTET            return !!(node && node.type && node.type.name === 'catmenu') || isLegacyCatmenuPluginNode(node);
106*6983cdfdSLORTET        }
107*6983cdfdSLORTET
108*6983cdfdSLORTET        function syntaxFromNode(node) {
109*6983cdfdSLORTET            if (!node) return '{{catmenu>.}}';
110*6983cdfdSLORTET            if (node.type && node.type.name === 'catmenu') {
111*6983cdfdSLORTET                return String((node.attrs && node.attrs.syntax) || '{{catmenu>.}}');
112*6983cdfdSLORTET            }
113*6983cdfdSLORTET            return String(node.textContent || '{{catmenu>.}}');
114*6983cdfdSLORTET        }
115*6983cdfdSLORTET
116*6983cdfdSLORTET        function createCatmenuNode(schema, syntax) {
117*6983cdfdSLORTET            const normalized = String(syntax || '{{catmenu>.}}').trim() || '{{catmenu>.}}';
118*6983cdfdSLORTET            if (schema.nodes.catmenu) {
119*6983cdfdSLORTET                return schema.nodes.catmenu.createChecked({syntax: normalized});
120*6983cdfdSLORTET            }
121*6983cdfdSLORTET            const fallback = schema.nodes.dwplugin_block;
122*6983cdfdSLORTET            if (!fallback) return null;
123*6983cdfdSLORTET            return fallback.createChecked(
124*6983cdfdSLORTET                {class: 'dwplugin', 'data-pluginname': 'catmenu'},
125*6983cdfdSLORTET                schema.text(normalized)
126*6983cdfdSLORTET            );
127*6983cdfdSLORTET        }
128*6983cdfdSLORTET
129*6983cdfdSLORTET        function findCatmenuAtSelection(state) {
130*6983cdfdSLORTET            const {selection} = state;
131*6983cdfdSLORTET            if (isCatmenuNode(selection.node)) {
132*6983cdfdSLORTET                return {node: selection.node, pos: selection.from};
133*6983cdfdSLORTET            }
134*6983cdfdSLORTET
135*6983cdfdSLORTET            const $from = selection.$from;
136*6983cdfdSLORTET            if ($from.depth > 0 && isCatmenuNode($from.parent)) {
137*6983cdfdSLORTET                return {node: $from.parent, pos: $from.before($from.depth)};
138*6983cdfdSLORTET            }
139*6983cdfdSLORTET            if (isCatmenuNode($from.nodeBefore)) {
140*6983cdfdSLORTET                return {node: $from.nodeBefore, pos: $from.pos - $from.nodeBefore.nodeSize};
141*6983cdfdSLORTET            }
142*6983cdfdSLORTET            if (isCatmenuNode($from.nodeAfter)) {
143*6983cdfdSLORTET                return {node: $from.nodeAfter, pos: $from.pos};
144*6983cdfdSLORTET            }
145*6983cdfdSLORTET
146*6983cdfdSLORTET            for (let depth = $from.depth; depth > 0; depth -= 1) {
147*6983cdfdSLORTET                const ancestor = $from.node(depth);
148*6983cdfdSLORTET                if (isCatmenuNode(ancestor)) {
149*6983cdfdSLORTET                    return {node: ancestor, pos: $from.before(depth)};
150*6983cdfdSLORTET                }
151*6983cdfdSLORTET            }
152*6983cdfdSLORTET            return null;
153*6983cdfdSLORTET        }
154*6983cdfdSLORTET
155*6983cdfdSLORTET        function insertParagraphAfterSelectedCatmenu(view) {
156*6983cdfdSLORTET            if (!view || !view.state) return false;
157*6983cdfdSLORTET            const selected = findCatmenuAtSelection(view.state);
158*6983cdfdSLORTET            if (!selected) return false;
159*6983cdfdSLORTET
160*6983cdfdSLORTET            const {schema} = view.state;
161*6983cdfdSLORTET            const paragraph = schema.nodes.paragraph && schema.nodes.paragraph.createAndFill();
162*6983cdfdSLORTET            if (!paragraph) return false;
163*6983cdfdSLORTET
164*6983cdfdSLORTET            const insertPos = selected.pos + selected.node.nodeSize;
165*6983cdfdSLORTET            let tr = view.state.tr.insert(insertPos, paragraph).scrollIntoView();
166*6983cdfdSLORTET            view.dispatch(tr);
167*6983cdfdSLORTET
168*6983cdfdSLORTET            try {
169*6983cdfdSLORTET                const SelectionClass = view.state.selection.constructor;
170*6983cdfdSLORTET                const $target = view.state.doc.resolve(insertPos + 1);
171*6983cdfdSLORTET                const selection = SelectionClass.near($target, 1);
172*6983cdfdSLORTET                view.dispatch(view.state.tr.setSelection(selection).scrollIntoView());
173*6983cdfdSLORTET            } catch (e) {
174*6983cdfdSLORTET                // Keep default selection on fallback.
175*6983cdfdSLORTET            }
176*6983cdfdSLORTET
177*6983cdfdSLORTET            view.focus();
178*6983cdfdSLORTET            return true;
179*6983cdfdSLORTET        }
180*6983cdfdSLORTET
181*6983cdfdSLORTET        function insertCatmenuBlock(view, pluginNode) {
182*6983cdfdSLORTET            const state = view.state;
183*6983cdfdSLORTET            const {$from} = state.selection;
184*6983cdfdSLORTET            const index = $from.index();
185*6983cdfdSLORTET
186*6983cdfdSLORTET            if ($from.parent.canReplaceWith(index, index, pluginNode.type)) {
187*6983cdfdSLORTET                view.dispatch(state.tr.replaceSelectionWith(pluginNode));
188*6983cdfdSLORTET                return true;
189*6983cdfdSLORTET            }
190*6983cdfdSLORTET
191*6983cdfdSLORTET            for (let depth = $from.depth; depth > 0; depth -= 1) {
192*6983cdfdSLORTET                const insertPos = $from.after(depth);
193*6983cdfdSLORTET                try {
194*6983cdfdSLORTET                    view.dispatch(state.tr.insert(insertPos, pluginNode));
195*6983cdfdSLORTET                    return true;
196*6983cdfdSLORTET                } catch (e) {
197*6983cdfdSLORTET                    // try a higher ancestor
198*6983cdfdSLORTET                }
199*6983cdfdSLORTET            }
200*6983cdfdSLORTET            return false;
201*6983cdfdSLORTET        }
202*6983cdfdSLORTET
203*6983cdfdSLORTET        function showCatmenuDialog(initialValues, onSubmit) {
204*6983cdfdSLORTET            const values = {namespace: '.', ...initialValues};
205*6983cdfdSLORTET            const $dialog = jQuery('<div class="plugin_catmenu_form" title="' + t('toolbar_popup_title', 'CatMenu') + '"></div>');
206*6983cdfdSLORTET
207*6983cdfdSLORTET            $dialog.append('<label>' + t('toolbar_namespace', 'Namespace') + '</label>');
208*6983cdfdSLORTET            const $namespace = jQuery('<input type="text" class="edit" style="width:100%;" />').val(values.namespace);
209*6983cdfdSLORTET            $dialog.append($namespace);
210*6983cdfdSLORTET            $dialog.append('<div style="font-size:.9em;color:#555;margin-top:4px;">' + t('toolbar_namespace_help', 'Folder. "." = current folder.') + '</div>');
211*6983cdfdSLORTET
212*6983cdfdSLORTET            $dialog.dialog({
213*6983cdfdSLORTET                modal: true,
214*6983cdfdSLORTET                width: 460,
215*6983cdfdSLORTET                close: function () {
216*6983cdfdSLORTET                    jQuery(this).dialog('destroy').remove();
217*6983cdfdSLORTET                },
218*6983cdfdSLORTET                buttons: [
219*6983cdfdSLORTET                    {
220*6983cdfdSLORTET                        text: t('toolbar_insert', 'Insert'),
221*6983cdfdSLORTET                        click: function () {
222*6983cdfdSLORTET                            onSubmit({namespace: String($namespace.val() || '.').trim() || '.'});
223*6983cdfdSLORTET                            jQuery(this).dialog('close');
224*6983cdfdSLORTET                        }
225*6983cdfdSLORTET                    },
226*6983cdfdSLORTET                    {
227*6983cdfdSLORTET                        text: t('toolbar_cancel', 'Cancel'),
228*6983cdfdSLORTET                        click: function () {
229*6983cdfdSLORTET                            jQuery(this).dialog('close');
230*6983cdfdSLORTET                        }
231*6983cdfdSLORTET                    }
232*6983cdfdSLORTET                ]
233*6983cdfdSLORTET            });
234*6983cdfdSLORTET        }
235*6983cdfdSLORTET
236*6983cdfdSLORTET        class CatmenuNodeView {
237*6983cdfdSLORTET            constructor(node, view, getPos) {
238*6983cdfdSLORTET                this.node = node;
239*6983cdfdSLORTET                this.view = view;
240*6983cdfdSLORTET                this.getPos = getPos;
241*6983cdfdSLORTET                this.dom = document.createElement('div');
242*6983cdfdSLORTET                const typeClass = (node.type && node.type.name === 'dwplugin_inline') ? 'pm_catmenu_inline' : 'pm_catmenu_block';
243*6983cdfdSLORTET                this.dom.className = 'plugin_catmenu pm_catmenu_node nodeHasForm ' + typeClass;
244*6983cdfdSLORTET                this.dom.setAttribute('contenteditable', 'false');
245*6983cdfdSLORTET                this.render();
246*6983cdfdSLORTET
247*6983cdfdSLORTET                this.dom.addEventListener('click', (event) => {
248*6983cdfdSLORTET                    event.preventDefault();
249*6983cdfdSLORTET                    event.stopPropagation();
250*6983cdfdSLORTET                    this.openEditor();
251*6983cdfdSLORTET                });
252*6983cdfdSLORTET            }
253*6983cdfdSLORTET
254*6983cdfdSLORTET            render() {
255*6983cdfdSLORTET                const syntax = syntaxFromNode(this.node);
256*6983cdfdSLORTET                const parsed = parseCatmenuSyntax(syntax);
257*6983cdfdSLORTET                const label = parsed ? formatCatmenuLabel(parsed) : syntax;
258*6983cdfdSLORTET                this.dom.textContent = '';
259*6983cdfdSLORTET
260*6983cdfdSLORTET                const icon = document.createElement('img');
261*6983cdfdSLORTET                icon.className = 'pm_catmenu_icon';
262*6983cdfdSLORTET                icon.src = getFolderIconUrl();
263*6983cdfdSLORTET                icon.alt = '';
264*6983cdfdSLORTET                icon.setAttribute('aria-hidden', 'true');
265*6983cdfdSLORTET                this.dom.appendChild(icon);
266*6983cdfdSLORTET
267*6983cdfdSLORTET                const text = document.createElement('span');
268*6983cdfdSLORTET                text.textContent = label;
269*6983cdfdSLORTET                this.dom.appendChild(text);
270*6983cdfdSLORTET                this.dom.setAttribute('title', syntax);
271*6983cdfdSLORTET            }
272*6983cdfdSLORTET
273*6983cdfdSLORTET            openEditor() {
274*6983cdfdSLORTET                const parsed = parseCatmenuSyntax(syntaxFromNode(this.node)) || {namespace: '.'};
275*6983cdfdSLORTET                showCatmenuDialog(parsed, (values) => {
276*6983cdfdSLORTET                    const syntax = buildCatmenuSyntax(values);
277*6983cdfdSLORTET                    const replacement = createCatmenuNode(this.view.state.schema, syntax);
278*6983cdfdSLORTET                    if (!replacement) return;
279*6983cdfdSLORTET
280*6983cdfdSLORTET                    const pos = this.getPos();
281*6983cdfdSLORTET                    this.view.dispatch(this.view.state.tr.replaceWith(pos, pos + this.node.nodeSize, replacement));
282*6983cdfdSLORTET                    this.view.focus();
283*6983cdfdSLORTET                });
284*6983cdfdSLORTET            }
285*6983cdfdSLORTET
286*6983cdfdSLORTET            update(node) {
287*6983cdfdSLORTET                if (!isCatmenuNode(node)) return false;
288*6983cdfdSLORTET                this.node = node;
289*6983cdfdSLORTET                const typeClass = (node.type && node.type.name === 'dwplugin_inline') ? 'pm_catmenu_inline' : 'pm_catmenu_block';
290*6983cdfdSLORTET                this.dom.className = 'plugin_catmenu pm_catmenu_node nodeHasForm ' + typeClass;
291*6983cdfdSLORTET                this.render();
292*6983cdfdSLORTET                return true;
293*6983cdfdSLORTET            }
294*6983cdfdSLORTET
295*6983cdfdSLORTET            selectNode() { this.dom.classList.add('ProseMirror-selectednode'); }
296*6983cdfdSLORTET            deselectNode() { this.dom.classList.remove('ProseMirror-selectednode'); }
297*6983cdfdSLORTET            stopEvent() { return true; }
298*6983cdfdSLORTET            ignoreMutation() { return true; }
299*6983cdfdSLORTET        }
300*6983cdfdSLORTET
301*6983cdfdSLORTET        class CatmenuMenuItemDispatcher extends AbstractMenuItemDispatcher {
302*6983cdfdSLORTET            static isAvailable(schema) {
303*6983cdfdSLORTET                return !!(schema.nodes.catmenu || schema.nodes.dwplugin_block);
304*6983cdfdSLORTET            }
305*6983cdfdSLORTET
306*6983cdfdSLORTET            static getIcon() {
307*6983cdfdSLORTET                const wrapper = document.createElement('span');
308*6983cdfdSLORTET                wrapper.className = 'menuicon';
309*6983cdfdSLORTET                wrapper.appendChild(getFolderMenuIcon());
310*6983cdfdSLORTET                return wrapper;
311*6983cdfdSLORTET            }
312*6983cdfdSLORTET
313*6983cdfdSLORTET            static getMenuItem(schema) {
314*6983cdfdSLORTET                if (!this.isAvailable(schema)) return hiddenMenuItem();
315*6983cdfdSLORTET
316*6983cdfdSLORTET                return new MenuItem({
317*6983cdfdSLORTET                    label: t('toolbar_button', 'CatMenu'),
318*6983cdfdSLORTET                    icon: this.getIcon(),
319*6983cdfdSLORTET                    command: (state, dispatch, view) => {
320*6983cdfdSLORTET                        const existing = findCatmenuAtSelection(state);
321*6983cdfdSLORTET                        if (!dispatch || !view) return true;
322*6983cdfdSLORTET
323*6983cdfdSLORTET                        const initialValues = existing
324*6983cdfdSLORTET                            ? (parseCatmenuSyntax(syntaxFromNode(existing.node)) || {namespace: '.'})
325*6983cdfdSLORTET                            : {namespace: '.'};
326*6983cdfdSLORTET
327*6983cdfdSLORTET                        showCatmenuDialog(initialValues, (values) => {
328*6983cdfdSLORTET                            const syntax = buildCatmenuSyntax(values);
329*6983cdfdSLORTET                            const pluginNode = createCatmenuNode(schema, syntax);
330*6983cdfdSLORTET                            if (!pluginNode) return;
331*6983cdfdSLORTET
332*6983cdfdSLORTET                            if (existing) {
333*6983cdfdSLORTET                                view.dispatch(view.state.tr.replaceWith(existing.pos, existing.pos + existing.node.nodeSize, pluginNode));
334*6983cdfdSLORTET                            } else if (!insertCatmenuBlock(view, pluginNode)) {
335*6983cdfdSLORTET                                const endPos = view.state.doc.content.size;
336*6983cdfdSLORTET                                view.dispatch(view.state.tr.insert(endPos, pluginNode));
337*6983cdfdSLORTET                            }
338*6983cdfdSLORTET                            view.focus();
339*6983cdfdSLORTET                        });
340*6983cdfdSLORTET
341*6983cdfdSLORTET                        return true;
342*6983cdfdSLORTET                    }
343*6983cdfdSLORTET                });
344*6983cdfdSLORTET            }
345*6983cdfdSLORTET        }
346*6983cdfdSLORTET
347*6983cdfdSLORTET        window.Prosemirror.pluginNodeViews.catmenu = (node, view, getPos) => new CatmenuNodeView(node, view, getPos);
348*6983cdfdSLORTET
349*6983cdfdSLORTET        const originalInline = window.Prosemirror.pluginNodeViews.dwplugin_inline;
350*6983cdfdSLORTET        window.Prosemirror.pluginNodeViews.dwplugin_inline = (node, view, getPos) => {
351*6983cdfdSLORTET            if (isLegacyCatmenuPluginNode(node)) return new CatmenuNodeView(node, view, getPos);
352*6983cdfdSLORTET            return typeof originalInline === 'function' ? originalInline(node, view, getPos) : undefined;
353*6983cdfdSLORTET        };
354*6983cdfdSLORTET
355*6983cdfdSLORTET        const originalBlock = window.Prosemirror.pluginNodeViews.dwplugin_block;
356*6983cdfdSLORTET        window.Prosemirror.pluginNodeViews.dwplugin_block = (node, view, getPos) => {
357*6983cdfdSLORTET            if (isLegacyCatmenuPluginNode(node)) return new CatmenuNodeView(node, view, getPos);
358*6983cdfdSLORTET            return typeof originalBlock === 'function' ? originalBlock(node, view, getPos) : undefined;
359*6983cdfdSLORTET        };
360*6983cdfdSLORTET
361*6983cdfdSLORTET        if (shouldShowInEditorMenu()) {
362*6983cdfdSLORTET            window.Prosemirror.pluginMenuItemDispatchers.push(CatmenuMenuItemDispatcher);
363*6983cdfdSLORTET        }
364*6983cdfdSLORTET
365*6983cdfdSLORTET        if (!window.__catmenuKeyboardGuardInstalled) {
366*6983cdfdSLORTET            window.__catmenuKeyboardGuardInstalled = true;
367*6983cdfdSLORTET            document.addEventListener('keydown', (event) => {
368*6983cdfdSLORTET                if (event.key !== 'Enter') return;
369*6983cdfdSLORTET                const view = window.Prosemirror && window.Prosemirror.view;
370*6983cdfdSLORTET                if (!view || !view.state) return;
371*6983cdfdSLORTET                if (!findCatmenuAtSelection(view.state)) return;
372*6983cdfdSLORTET                event.preventDefault();
373*6983cdfdSLORTET                event.stopPropagation();
374*6983cdfdSLORTET                insertParagraphAfterSelectedCatmenu(view);
375*6983cdfdSLORTET            }, true);
376*6983cdfdSLORTET        }
377*6983cdfdSLORTET    }
378*6983cdfdSLORTET
379*6983cdfdSLORTET    jQuery(document).on('PROSEMIRROR_API_INITIALIZED', initializeCatmenuProsemirror);
380*6983cdfdSLORTET    initializeCatmenuProsemirror();
381*6983cdfdSLORTET})();
382