]> BookStack Code Mirror - bookstack/commitdiff
Changed to a psuedo-style approach for tasklist in wysiwyg
authorDan Brown <redacted>
Sat, 19 Mar 2022 17:12:56 +0000 (17:12 +0000)
committerDan Brown <redacted>
Sat, 19 Mar 2022 17:13:26 +0000 (17:13 +0000)
resources/js/wysiwyg/config.js
resources/js/wysiwyg/plugins-tasklist.js
resources/sass/_tinymce.scss

index fab6a38862fb717f78b291920e423528f10b853a..e75e4f7122330790b58667059025f90ff1c990d8 100644 (file)
@@ -207,7 +207,7 @@ export function build(options) {
         statusbar: false,
         menubar: false,
         paste_data_images: false,
-        extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram],details[*],summary[*],div[*],li[class]',
+        extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram],details[*],summary[*],div[*],li[class|checked]',
         automatic_uploads: false,
         custom_elements: 'doc-root,code-block',
         valid_children: [
index 07f93446327a4a86074d2a8ead2801771ee0c83d..4070575d92aea8fb1729bdd037916d7402de1859 100644 (file)
@@ -1,60 +1,27 @@
-/**
- * @param {Editor} editor
- */
-function defineTaskListCustomElement(editor) {
-    const doc = editor.getDoc();
-    const win = doc.defaultView;
-
-    class TaskListElement extends win.HTMLElement {
-        constructor() {
-            super();
-            // this.attachShadow({mode: 'open'});
-            //
-            // const input = doc.createElement('input');
-            // input.setAttribute('type', 'checkbox');
-            // input.setAttribute('disabled', 'disabled');
-            //
-            // if (this.hasAttribute('selected')) {
-            //     input.setAttribute('selected', 'selected');
-            // }
-            //
-            // this.shadowRoot.append(input);
-            // this.shadowRoot.close();
-        }
-    }
-
-    win.customElements.define('task-list-item', TaskListElement);
-}
-
 /**
  * @param {Editor} editor
  * @param {String} url
  */
-function register(editor, url) {
 
-    // editor.on('NewBlock', ({ newBlock}) => {
-    //     ensureElementHasCheckbox(newBlock);
-    // });
+function register(editor, url) {
 
     editor.on('PreInit', () => {
 
-        defineTaskListCustomElement(editor);
-
-        editor.parser.addNodeFilter('li', function(elms) {
-            for (const elem of elms) {
-                if (elem.attributes.map.class === 'task-list-item') {
-                    replaceTaskListNode(elem);
+        editor.parser.addNodeFilter('li', function(nodes) {
+            for (const node of nodes) {
+                if (node.attributes.map.class === 'task-list-item') {
+                    parseTaskListNode(node);
                 }
             }
         });
 
-        // editor.serializer.addNodeFilter('li', function(elms) {
-        //     for (const elem of elms) {
-        //         if (elem.attributes.map.class === 'task-list-item') {
-        //             ensureNodeHasCheckbox(elem);
-        //         }
-        //     }
-        // });
+        editor.serializer.addNodeFilter('li', function(nodes) {
+            for (const node of nodes) {
+                if (node.attributes.map.class === 'task-list-item') {
+                    serializeTaskListNode(node);
+                }
+            }
+        });
 
     });
 
@@ -63,56 +30,37 @@ function register(editor, url) {
 /**
  * @param {AstNode} node
  */
-function replaceTaskListNode(node) {
-
-    const taskListItem = new tinymce.html.Node.create('task-list-item', {
-    });
+function parseTaskListNode(node) {
+    // Force task list item class
+    node.attr('class', 'task-list-item');
 
+    // Copy checkbox status and remove checkbox within editor
     for (const child of node.children()) {
-        if (node.name !== 'input') {
-            taskListItem.append(child);
+        if (child.name === 'input') {
+            if (child.attr('checked') === 'checked') {
+                node.attr('checked', 'checked');
+            }
+            child.remove();
         }
     }
-
-    node.replace(taskListItem);
 }
 
-// /**
-//  * @param {Element} elem
-//  */
-// function ensureElementHasCheckbox(elem) {
-//     const hasCheckbox = elem.querySelector(':scope > input[type="checkbox"]') !== null;
-//     if (hasCheckbox) {
-//         return;
-//     }
-//
-//     const input = elem.ownerDocument.createElement('input');
-//     input.setAttribute('type', 'checkbox');
-//     input.setAttribute('disabled', 'disabled');
-//     elem.prepend(input);
-// }
-
 /**
- * @param {AstNode} elem
+ * @param {AstNode} node
  */
-function ensureNodeHasCheckbox(elem) {
-    // Stop if there's already an input
-    if (elem.firstChild && elem.firstChild.name === 'input') {
-        return;
-    }
-
-    const input = new tinymce.html.Node.create('input', {
-        type: 'checkbox',
-        disabled: 'disabled',
-    });
+function serializeTaskListNode(node) {
+    const isChecked = node.attr('checked') === 'checked';
+    node.attr('checked', null);
 
-    if (elem.firstChild) {
-        elem.insert(input, elem.firstChild, true);
-    } else {
-        elem.append(input);
+    const inputAttrs = {type: 'checkbox', disabled: 'disabled'};
+    if (isChecked) {
+        inputAttrs.checked = 'checked';
     }
-}
 
+    const checkbox = new tinymce.html.Node.create('input', inputAttrs);
+    checkbox.shortEnded = true;
+    node.firstChild ? node.insert(checkbox, node.firstChild, true) : node.append(checkbox);
+}
 
 /**
  * @param {WysiwygConfigOptions} options
index 6add27f453ffbc11d847459b18988f141e46b063..c4848561a9ba800f8a4a4c759cbbc05dc049dab9 100644 (file)
@@ -112,4 +112,29 @@ body.page-content.mce-content-body  {
 }
 .tox-menu .tox-collection__item-label {
   line-height: normal !important;
+}
+
+/**
+ * Fake task list checkboxes
+ */
+.page-content.mce-content-body .task-list-item > input[type="checkbox"] {
+  display: none;
+}
+.page-content.mce-content-body .task-list-item:before {
+  content: '';
+  display: inline-block;
+  border: 2px solid #CCC;
+  width: 12px;
+  height: 12px;
+  border-radius: 2px;
+  margin-right: 8px;
+  vertical-align: text-top;
+  cursor: pointer;
+}
+
+.page-content.mce-content-body .task-list-item[checked]:before {
+  background-color: #CCC;
+  background-image: url('data:image/svg+xml;utf8,<svg fill="%23FFFFFF" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m8.4856 20.274-6.736-6.736 2.9287-2.7823 3.8073 3.8073 10.836-10.836 2.9287 2.9287z" stroke-width="1.4644"/></svg>');
+  background-position: 50% 50%;
+  background-size: 100% 100%;
 }
\ No newline at end of file