diff --git a/djangocms_text/editors.py b/djangocms_text/editors.py index 36e2aae..2d0e857 100644 --- a/djangocms_text/editors.py +++ b/djangocms_text/editors.py @@ -209,29 +209,44 @@ def default(self, obj): "title": _("Table"), "icon": '', }, + "toggleHeaderRow": { + "title": _("Header row"), + "icon": '', + }, + "toggleHeaderColumn": { + "title": _("Header column"), + "icon": '', + }, "addRowBefore": { "title": _("Add row before"), + "icon": '', }, "addRowAfter": { "title": _("Add row after"), + "icon": '', }, "addColumnBefore": { "title": _("Add column before"), + "icon": '', }, "addColumnAfter": { "title": _("Add column after"), + "icon": '', }, "deleteRow": { "title": _("Delete row"), + "icon": '', }, "deleteColumn": { "title": _("Delete column"), + "icon": '', }, "deleteTable": { "title": _("Delete table"), }, "mergeOrSplit": { - "title": _("Merge or split cells"), + "title": _("Merge/split cells"), + "icon": '', }, "Code": { "title": _("Code"), diff --git a/djangocms_text/static/djangocms_text/css/cms.text.css b/djangocms_text/static/djangocms_text/css/cms.text.css index fe6ffb5..faecdb5 100644 --- a/djangocms_text/static/djangocms_text/css/cms.text.css +++ b/djangocms_text/static/djangocms_text/css/cms.text.css @@ -175,6 +175,6 @@ form.cms-form { } cms-plugin.cms-editor-inline-wrapper:focus { - outline: 3px solid Highlight; + outline: 3px solid AccentColor; outline-offset: 2px; } diff --git a/private/css/cms.tiptap.css b/private/css/cms.tiptap.css index 54ca366..f731582 100644 --- a/private/css/cms.tiptap.css +++ b/private/css/cms.tiptap.css @@ -34,10 +34,6 @@ } position: relative; - &:has(dialog.cms-form-dialog) [role="menubar"] { - /* show toolbar if form dialog is open */ - visibility: visible; - } .tiptap { &.ProseMirror-focused { /* Safari: Only outline the editor div, not toolbar etc. */ @@ -73,7 +69,7 @@ } &.ProseMirror-focused { td, th { - outline: AccentColor solid 0.5px; + outline: Highlight solid 0.5px; } } & cms-plugin { @@ -86,9 +82,5 @@ outline-offset: 2px; } } - &.ProseMirror-focused [role="menubar"] { - /* show toolbar if editor is focused */ - visibility: visible; - } } } diff --git a/private/css/cms.toolbar.css b/private/css/cms.toolbar.css index 32c674c..4caab83 100644 --- a/private/css/cms.toolbar.css +++ b/private/css/cms.toolbar.css @@ -1,11 +1,22 @@ .cms-editor-inline-wrapper { + .ProseMirror-focused [role="menubar"] { + /* show toolbar if editor is focused */ + visibility: visible; + [role="button"].show { + z-index: 10; + > .dropdown-content { + visibility: visible; + height: auto; + } + } + } + &:has(dialog.cms-form-dialog) [role="menubar"] { + /* show toolbar if form dialog is open */ + visibility: visible; + } + [role="menubar"] { bottom: calc(100% - 1px); - - [role="button"].show > .dropdown-content { - visibility: visible; - height: auto; - } padding: 2px 0.4rem; /* border-radius: 3px; */ margin: 0 !important; @@ -34,6 +45,13 @@ display: block; top: 0; visibility: visible; + [role="button"].show { + z-index: 10; + > .dropdown-content { + visibility: visible; + height: auto; + } + } position: static; width: 100%; box-sizing: border-box; @@ -48,7 +66,7 @@ padding-right: 0; .dropdown-content { inset-block-start: 100%; - inset-inline-start: 0; + inset-inline-start: -2px; } } .tt-table { diff --git a/private/js/tiptap_plugins/cms.tiptap.toolbar.js b/private/js/tiptap_plugins/cms.tiptap.toolbar.js index 969cc0a..1d7ff32 100644 --- a/private/js/tiptap_plugins/cms.tiptap.toolbar.js +++ b/private/js/tiptap_plugins/cms.tiptap.toolbar.js @@ -25,6 +25,8 @@ const _tableMenu = [ 'addRowAfter', 'deleteRow', '|', + 'toggleHeaderColumn', + 'toggleHeaderRow', 'mergeOrSplit', ]; @@ -190,6 +192,18 @@ const TiptapToolbar = { items: generateTableMenu, class: 'tt-table', }, + toggleHeaderColumn: { + action: (editor, button) => editor.commands.toggleHeaderColumn(), + enabled: (editor) => editor.can().toggleHeaderColumn(), + active: (editor) => editor.isActive('headerColumn'), + type: 'mark', + }, + toggleHeaderRow: { + action: (editor, button) => editor.commands.toggleHeaderRow(), + enabled: (editor) => editor.can().toggleHeaderRow(), + active: (editor) => editor.isActive('headerRow'), + type: 'mark', + }, addColumnBefore: { action: (editor, button) => editor.commands.addColumnBefore(), enabled: (editor) => editor.can().addColumnBefore(), diff --git a/private/js/tiptap_plugins/cms.toolbar.js b/private/js/tiptap_plugins/cms.toolbar.js index 0cf7a5d..503a370 100644 --- a/private/js/tiptap_plugins/cms.toolbar.js +++ b/private/js/tiptap_plugins/cms.toolbar.js @@ -50,7 +50,7 @@ function _createBlockToolbarPlugin(editor) { return this.getState(state); }, handleDOMEvents: { - mousedown (view, event) { + mousedowxn (view, event) { if (editor.options.blockToolbar?.contains(event.target)) { event.preventDefault(); return true; @@ -107,12 +107,13 @@ function _createBlockToolbar(editor, blockToolbar) { toolbar.classList.add('cms-block-toolbar'); toolbar.style.zIndex = editor.options.baseFloatZIndex || 1000000; // - toolbar.innerHTML = `${_menu_icon}
${_populateToolbar(editor, blockToolbar, 'block')}
`; + toolbar.innerHTML = `${_drag_icon}
${_populateToolbar(editor, blockToolbar, 'block')}
`; toolbar.draggable = true; toolbar.addEventListener("dragstart", (event) => { toolbar.classList.remove('show'); - const {block, depth} = editor.options.blockToolbar.dataset; + const {resolvedPos, depth} = _getResolvedPos(editor.view.state); + const block = resolvedPos.start(depth); if (depth >= 0) { const { state, dispatch } = editor.view; const nodeSelection = NodeSelection.create(state.doc, block); @@ -162,6 +163,11 @@ function updateBlockToolbar(editor, state) { const ref = editor.options.el.getBoundingClientRect(); editor.options.blockToolbar.draggable = resolvedPos.node(depth).content.size > 0; editor.options.blockToolbar.style.insetBlockStart = `${pos.top - ref.top}px`; + let title = resolvedPos.node(1).type.name; + for (let i= 2; i <= depth; i++) { + title += ` > ${resolvedPos.node(i).type.name}`; + } + editor.options.blockToolbar.title = title; } else { editor.options.blockToolbar.draggable = false; } @@ -196,7 +202,7 @@ function _updateToolbarIcon (editor, node) { if (type in _node_icons) { _replaceIcon(editor.options.blockToolbar.firstElementChild, _node_icons[type]); } else { - _replaceIcon(editor.options.blockToolbar.firstElementChild, _menu_icon); + _replaceIcon(editor.options.blockToolbar.firstElementChild, _drag_icon); } } @@ -315,7 +321,6 @@ function _handleToolbarClick(event, editor) { _closeAllDropdowns(event, editor); button.classList.add('show'); content.style.top = button.offsetHeight + 'px'; - content.style.zIndex = button.closest('button, [role="menubar"]').style.zIndex + 10; if (button.offsetLeft + content.offsetWidth > window.innerWidth) { content.style.left = (window.innerWidth - content.offsetWidth - button.offsetLeft - 25) + 'px'; } @@ -395,7 +400,7 @@ function _populateToolbar(editor, array, filter) { } const title = item.title && item.icon ? `title='${item.title}' ` : ''; const icon = item.icon || item.title; - html += `${icon}`; + html += `${icon}`; } else { switch (item) { case '|': @@ -493,11 +498,10 @@ function _updateToolbar(editor, toolbar) { if (action) { if (TiptapToolbar[action]) { const toolbarItem = window.cms_editor_plugin._getRepresentation(action); - button.disabled = !toolbarItem.enabled(editor, button); try { - button.disabled = !toolbarItem.enabled(editor, button); + button.disabled = !toolbarItem?.enabled(editor, button); try { - if (toolbarItem.active(editor, button)) { + if (toolbarItem?.active(editor, button)) { button.classList.add('active'); } else { button.classList.remove('active');