Skip to content

Commit

Permalink
feat: keep selection highlighted when opening dialogue
Browse files Browse the repository at this point in the history
  • Loading branch information
fsbraun committed Dec 21, 2024
1 parent 20a9e59 commit ca93044
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 36 deletions.
8 changes: 1 addition & 7 deletions private/css/cms.balloon-toolbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,8 @@
}
}

@keyframes delayedHide {
to {
.cms-editor-inline-wrapper:not(:has(.cms-toolbar.show)) .cms-balloon {
visibility: hidden;
}
}

.cms-editor-inline-wrapper:not(:has(.ProseMirror-focused)) .cms-balloon {
animation: 0s linear 0.2s forwards delayedHide;
}

dialog.cms-form-dialog.cms-balloon-menu {
Expand Down
2 changes: 1 addition & 1 deletion private/css/cms.linkfield.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
font-size: 0.8rem;
position: relative;
input[type="text"] {
padding-inline-end: 2em;
padding-inline-end: 2em !important;
background: var(--dca-white) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="16" fill="%23808080" viewBox="0 0 16 16"><path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z"/></svg>') no-repeat right center;
&[dir=rtl] {
background-position: left center;
Expand Down
11 changes: 8 additions & 3 deletions private/css/cms.tiptap.css
Original file line number Diff line number Diff line change
Expand Up @@ -45,21 +45,26 @@
a[href] {
cursor: pointer;
}
.fake-selection {
background-color: Highlight;
color: HighlightText;
}
table {
th, td {
position: relative;
}
.selectedCell {
background: color-mix(in srgb, var(--dca-primary) 20%, transparent);
color: HighlightText;
background: Highlight;
}
.column-resize-handle {
top: 0;
bottom: 0;
right: -1px;
width: 2px;
position: absolute;
background: var(--dca-primary);
box-shadow: 0 0 2px var(--dca-primary);
background: Highlight;
box-shadow: 0 0 2px Highlight;
}
}
& cms-plugin {
Expand Down
10 changes: 7 additions & 3 deletions private/js/cms.linkfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,22 @@

class LinkField {
constructor(element, options) {
const hasFocus = element.contains(document.activeElement);

this.options = options;
this.urlElement = element;
this.form = element.closest("form");
this.selectElement = this.form?.querySelector(`input[name="${this.urlElement.id + '_select'}"]`);
if (this.selectElement) {
this.urlElement.setAttribute('type', 'hidden'); // Two input types?
this.selectElement.setAttribute('type', 'hidden'); // Make hidden and add common input
this.createInput();
this.createInput(hasFocus);
this.registerEvents();
}
this.populateField();
}

createInput() {
createInput(hasFocus = false) {
this.inputElement = document.createElement('input');
this.inputElement.setAttribute('type', 'text');
this.inputElement.setAttribute('autocomplete', 'off');
Expand All @@ -40,7 +42,9 @@ class LinkField {
}
this.wrapper.appendChild(this.inputElement);
this.wrapper.appendChild(this.dropdown);

if (hasFocus) {
this.inputElement.focus();
}
}

populateField() {
Expand Down
21 changes: 12 additions & 9 deletions private/js/cms.tiptap.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,23 @@ import Table from '@tiptap/extension-table';
import TableCell from '@tiptap/extension-table-cell';
import TableHeader from '@tiptap/extension-table-header';
import TableRow from '@tiptap/extension-table-row';
import { TextAlign, TextAlignOptions } from '@tiptap/extension-text-align';
import { CmsPluginNode, CmsBlockPluginNode } from './tiptap_plugins/cms.plugin';
import {TextAlign, TextAlignOptions} from '@tiptap/extension-text-align';
import {CmsPluginNode, CmsBlockPluginNode} from './tiptap_plugins/cms.plugin';
import TiptapToolbar from "./tiptap_plugins/cms.tiptap.toolbar";
import {StarterKit} from "@tiptap/starter-kit";

import { InlineColors, Small, Var, Kbd, Samp } from "./tiptap_plugins/cms.styles";
import {InlineColors, Small, Var, Kbd, Samp} from "./tiptap_plugins/cms.styles";
import CmsBalloonToolbar from "./tiptap_plugins/cms.balloon-toolbar";
import FormExtension from "./tiptap_plugins/cms.formextension";

import { formToHtml, populateForm } from './cms.dialog';
import {formToHtml, populateForm} from './cms.dialog';
import LinkField from './cms.linkfield';

import '../css/cms.tiptap.css';
import '../css/cms.linkfield.css';



class CMSTipTapPlugin {
defaultOptions() {
return {
Expand Down Expand Up @@ -62,12 +63,12 @@ class CMSTipTapPlugin {
],
toolbar_HTMLField: [
['Paragraph', '-', 'Heading1', 'Heading2', 'Heading3', 'Heading4', 'Heading5'], '|',
['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript', '-', 'RemoveFormat']
['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript', '-', 'RemoveFormat'],
['Undo', 'Redo'],
],
toolbar_CMS: [
['Paragraph', '-', 'Heading1', 'Heading2', 'Heading3', 'Heading4', 'Heading5'], '|',
['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript', '-', 'RemoveFormat']
['Bold', 'Italic', 'Underline', 'Strike', '-', 'Subscript', 'Superscript', '-', 'RemoveFormat'],
['Undo', 'Redo'],
],
};
Expand Down Expand Up @@ -226,7 +227,7 @@ class CMSTipTapPlugin {
}

_createBlockToolbar(el, editor, options) {
const toolbar = this._populateToolbar(editor,options.toolbar || this.options.toolbar_HTMLField, 'block');
const toolbar = this._populateToolbar(editor, options.toolbar || this.options.toolbar_HTMLField, 'block');
const ballonToolbar = new CmsBalloonToolbar(editor, toolbar,
(event) => this._handleToolbarClick(event, editor),
(el) => this._updateToolbar(editor, el));
Expand Down Expand Up @@ -352,17 +353,19 @@ class CMSTipTapPlugin {

}

// Blur editor event
// Blur editor event
_blurEditor(editor, event) {
// Let the editor process clicks on the toolbar first
// This hopefully prevents race conditions
setTimeout(() => {
// Allow toolbar and other editor widgets to process the click first
// They need to refocus the editor to avoid a save
if (!editor.options.element.contains(document.activeElement)) {
if(!editor.options.el.contains(document.activeElement)) {
// 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();
}
Expand Down
3 changes: 2 additions & 1 deletion private/js/tiptap_plugins/cms.dynlink.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-env es11 */
/* jshint esversion: 11 */
/* global document, window, console */
'use strict';

import Link from '@tiptap/extension-link';

Expand Down Expand Up @@ -30,12 +31,12 @@ const CmsDynLink = Link.extend({
event.preventDefault();
setTimeout(() => {
if (this.editor.isActive('link')) {
this.editor.commands.extendMarkRange('link');
this.editor.commands.openCmsForm('Link');
}
}, 0);
}
}).bind(this); // hacky: move the eventHandler to the Mark object (this) to be able to remove it later
console.log("Event", editor.view.dom);
editor.view.dom.addEventListener('click', this);
},

Expand Down
75 changes: 72 additions & 3 deletions private/js/tiptap_plugins/cms.formextension.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,69 @@
/* eslint-env es6 */
/* jshint esversion: 6 */
/* global document, window, console */
'use strict';

import {CmsForm, formToHtml, populateForm} from "../cms.dialog";
import {Extension} from "@tiptap/core";
import TiptapToolbar from "./cms.tiptap.toolbar";
import LinkField from "../cms.linkfield";

import {Decoration, DecorationSet} from '@tiptap/pm/view';
import {Plugin} from '@tiptap/pm/state';


// ProseMirror plugin to handle temporary decorations
const _fakeSelectionPlugin = new Plugin({
state: {
init(_, {doc}) {
return DecorationSet.empty;
},
apply(tr, decorationSet) {
// Remove decoration on any transaction unless explicitly preserved
if (tr.getMeta("fake-selection") === "add") {
const {from, to} = tr.selection;
const decoration = Decoration.inline(from, to, {class: "fake-selection"});
return decorationSet.add(tr.doc, [decoration]);
} else if (tr.getMeta("fake-selection") === "remove") {
const decorations = decorationSet.find().filter(
(decoration) => decoration.spec?.class === "fake-selection"
);
return DecorationSet.create(tr.doc, decorations);
}
return decorationSet.map(tr.mapping, tr.doc);
},
},
props: {
decorations(state) {
return this.getState(state);
},
},
});


const fakeSelectionPlugin = Extension.create({
addProseMirrorPlugins() {
return [_fakeSelectionPlugin];
},
});


function addFakeSelection(view) {
const {state, dispatch} = view;
const tr = state.tr;
// Add meta to trigger the plugin
tr.setMeta("fake-selection", "add");
dispatch(tr);
}

function clearFakeSelection(view) {
const {state, dispatch} = view;
const tr = state.tr;
// Add meta to trigger the plugin
tr.setMeta("fake-selection", "remove");
dispatch(tr);
}



const FormExtension = Extension.create({
Expand All @@ -16,6 +73,7 @@ const FormExtension = Extension.create({
return {
openCmsForm: (action, target) => ({editor, commands}) => {
let options;
addFakeSelection(editor.view);
if (target) {
const rect = target.getBoundingClientRect();
options = {
Expand All @@ -40,8 +98,11 @@ const FormExtension = Extension.create({
}
const dialog = new CmsForm(
editor.options.element,
data => TiptapToolbar[action].formAction(editor, data),
() => editor.commands.focus()
data => {
TiptapToolbar[action].formAction(editor, data);
edior.commands.closeCmsForm();
},
() => editor.commands.closeCmsForm()
);
const formRepresentation = window.cms_editor_plugin._getRepresentation(action);
const formElement = dialog.formDialog(formToHtml(formRepresentation.form), options);
Expand All @@ -57,9 +118,17 @@ const FormExtension = Extension.create({
url: editor.options.settings.url_endpoint || '',
});
}, this);
},

closeCmsForm: () => ({editor}) => {
clearFakeSelection(editor.view);
editor.commands.focus();
}
};
}
},
addProseMirrorPlugins() {
return [_fakeSelectionPlugin];
},
});

export default FormExtension;
17 changes: 8 additions & 9 deletions private/js/tiptap_plugins/cms.tiptap.toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,21 @@ const TiptapToolbar = {
type: 'block',
},
Link: {
action: (editor) => editor.commands.openCmsForm('Link'),
action: (editor) => {
if (editor.isActive('link')) {
// If the user is currently editing a link, update the whole link
editor.commands.extendMarkRange('link');
}
editor.commands.openCmsForm('Link');
},
formAction: (editor, data) => {
if (data) {
const link = {
href: data.get('href'),
'data-cms-href': data.get('href_select') || null,
'target': data.get('target') || null,
};
if (editor.isActive('link')) {
// If the user is currently editing a link, update the whole link
editor.chain().focus().extendMarkRange('link').setLink(link).run();
} else {
editor.chain().focus().setLink(link).run();
}
} else {
editor.focus();
editor.commands.setLink(link);
}
},
enabled: (editor) => editor.can().setLink({href: '#'}),
Expand Down

0 comments on commit ca93044

Please sign in to comment.