diff --git a/private/css/cms.balloon-toolbar.css b/private/css/cms.balloon-toolbar.css index c215260..e58c5eb 100644 --- a/private/css/cms.balloon-toolbar.css +++ b/private/css/cms.balloon-toolbar.css @@ -20,6 +20,11 @@ &.show [role="menubar"] { visibility: visible; } + &.disabled { + cursor: not-allowed; + pointer-events: none; + color: var(--dca-gray-light); + } [role="menubar"] { padding: 3px; position: absolute; diff --git a/private/css/cms.tiptap.css b/private/css/cms.tiptap.css index 86b2289..048ef2d 100644 --- a/private/css/cms.tiptap.css +++ b/private/css/cms.tiptap.css @@ -98,10 +98,11 @@ display: flex; flex-flow: row wrap; border: solid 1px var(--dca-gray-light, var(--hairline-color)); - box-shadow: 0 1.5px 1.5px rgba(var(--dca-shadow),.4); + box-shadow: 0 1.5px 1.5px rgba(var(--dca-shadow), .4); color: var(--dca-black, var(--body-fg)); background: var(--dca-white, var(--body-bg)); opacity: 1; + div.grouper { padding: 0; margin: 0; @@ -177,6 +178,15 @@ height: 1.2rem; } } + /* Allow to disable the full menubar */ + [role="menubar"].disabled { + button, [role="button"] { + cursor: not-allowed; + pointer-events: none; + color: var(--dca-gray-light); + } + } + .dropdown-content { color: var(--dca-black, var(--body-fg)); border-radius: 0; diff --git a/private/js/cms.tiptap.js b/private/js/cms.tiptap.js index dc9cb82..f75ab14 100644 --- a/private/js/cms.tiptap.js +++ b/private/js/cms.tiptap.js @@ -315,7 +315,7 @@ class CMSTipTapPlugin { event.stopPropagation(); event.preventDefault(); const button = event.target.closest('button, .dropdown'); - if (button && !button.disabled) { + if (button && !button.disabled && !editor.options.el.querySelector('dialog.cms-form-dialog')) { const action = button.dataset.action; if (button.classList.contains('dropdown')) { // Open dropdown @@ -364,8 +364,6 @@ class CMSTipTapPlugin { // hide the toolbar editor.options.element.querySelectorAll('[role="menubar"], [role="button"]') .forEach((el) => el.classList.remove('show')); - } - if (!editor.options.element.contains(document.activeElement)) { // save the content (is no-op for non-inline calls) editor.options.save_callback(); } @@ -400,13 +398,20 @@ class CMSTipTapPlugin { html += group + this.separator_markup; } } else if (item.constructor === Object) { - const dropdown = this._populateToolbar(editor, item.items, filter); - // Are there any items in the dropdown? - if (dropdown.replaceAll(this.separator_markup, '').replaceAll(this.space_markup, '').length > 0) { - const title = item.title && item.icon ? `title='${item.title}' ` : ''; - const icon = item.icon || item.title; - html += `${icon}`; + let dropdown; + + if (typeof item.items === 'string') { + dropdown = item.items; + } else { + dropdown = this._populateToolbar(editor, item.items, filter); + // Are there any items in the dropdown? + if (dropdown.replaceAll(this.separator_markup, '').replaceAll(this.space_markup, '').length === 0) { + continue + } } + const title = item.title && item.icon ? `title='${item.title}' ` : ''; + const icon = item.icon || item.title; + html += `${icon}`; } else { switch (item) { case '|': diff --git a/private/js/tiptap_plugins/cms.balloon-toolbar.js b/private/js/tiptap_plugins/cms.balloon-toolbar.js index 4af295d..401ae21 100644 --- a/private/js/tiptap_plugins/cms.balloon-toolbar.js +++ b/private/js/tiptap_plugins/cms.balloon-toolbar.js @@ -52,8 +52,7 @@ export default class CmsBalloonToolbar { this.form = null; } else { // Add the form dialog only if it is not already open - this.form = new CmsForm(this.editor.options.element, () => { - }); + this.form = new CmsForm(this.editor.options.element, () => {}); const rect = this.toolbar.getBoundingClientRect(); const options = { x: (rect.left + rect.right) / 2, diff --git a/private/js/tiptap_plugins/cms.formextension.js b/private/js/tiptap_plugins/cms.formextension.js index f571599..73621b8 100644 --- a/private/js/tiptap_plugins/cms.formextension.js +++ b/private/js/tiptap_plugins/cms.formextension.js @@ -1,5 +1,5 @@ -/* eslint-env es6 */ -/* jshint esversion: 6 */ +/* eslint-env es11 */ +/* jshint esversion: 11 */ /* global document, window, console */ 'use strict'; @@ -54,6 +54,8 @@ function addFakeSelection(view) { // Add meta to trigger the plugin tr.setMeta("fake-selection", "add"); dispatch(tr); + view.dom.parentNode.querySelector('.cms-toolbar')?.classList.add('disabled'); + view.dom.parentNode.querySelector('.cms-balloon')?.classList.add('disabled'); } function clearFakeSelection(view) { @@ -62,6 +64,8 @@ function clearFakeSelection(view) { // Add meta to trigger the plugin tr.setMeta("fake-selection", "remove"); dispatch(tr); + view.dom.parentNode.querySelector('.cms-toolbar')?.classList.remove('disabled'); + view.dom.parentNode.querySelector('.cms-balloon')?.classList.remove('disabled'); } @@ -72,6 +76,9 @@ const FormExtension = Extension.create({ 'use strict'; return { openCmsForm: (action, target) => ({editor, commands}) => { + if (editor.options.el.querySelector(`dialog.${action}-form`)) { + return false; + } let options; addFakeSelection(editor.view); if (target) { @@ -111,6 +118,7 @@ const FormExtension = Extension.create({ // Populate the form with the current attributes (if existent) populateForm(formElement, TiptapToolbar[action].attributes(editor), formRepresentation.form); } + dialog.dialog.classList.add(action + '-form'); dialog.open(); formElement.querySelectorAll('form.cms-form .js-linkfield') .forEach((el) => {