]> BookStack Code Mirror - bookstack/blobdiff - resources/js/wysiwyg/plugins-tasklist.js
Updated npm package versions
[bookstack] / resources / js / wysiwyg / plugins-tasklist.js
index cb1bb4a7a9ba0fe6bf7c847874246e78d3df9ef9..4afbfa8e623600466cb52538ee577b4686a8745d 100644 (file)
@@ -24,8 +24,9 @@ function register(editor, url) {
         },
         onSetup(api) {
             editor.on('NodeChange', event => {
-                const inList = event.parents.find(el => el.nodeName === 'LI' && el.classList.contains('task-list-item')) !== undefined;
-                api.setActive(inList);
+                const parentListEl = event.parents.find(el => el.nodeName === 'LI');
+                const inList = parentListEl && parentListEl.classList.contains('task-list-item');
+                api.setActive(Boolean(inList));
             });
         }
     });
@@ -35,12 +36,22 @@ function register(editor, url) {
     const existingBullListButton = editor.ui.registry.getAll().buttons.bullist;
     existingBullListButton.onSetup = function(api) {
         editor.on('NodeChange', event => {
-            const notInTaskList = event.parents.find(el => el.nodeName === 'LI' && el.classList.contains('task-list-item')) === undefined;
-            const inList = event.parents.find(el => el.nodeName === 'UL') !== undefined;
-            api.setActive(inList && notInTaskList);
+            const parentList = event.parents.find(el => el.nodeName === 'LI');
+            const inTaskList = parentList && parentList.classList.contains('task-list-item');
+            const inUlList = parentList && parentList.parentNode.nodeName === 'UL';
+            api.setActive(Boolean(inUlList && !inTaskList));
         });
     };
     existingBullListButton.onAction = function() {
+        // Cheeky hack to prevent list toggle action treating tasklists as normal
+        // unordered lists which would unwrap the list on toggle from tasklist to bullet list.
+        // Instead we quickly jump through an ordered list first if we're within a tasklist.
+        if (elementWithinTaskList(editor.selection.getNode())) {
+            editor.execCommand('InsertOrderedList', null, {
+                'list-item-attributes': {class: null}
+            });
+        }
+
         editor.execCommand('InsertUnorderedList', null, {
             'list-item-attributes': {class: null}
         });
@@ -73,13 +84,23 @@ function register(editor, url) {
 
     // Handle checkbox click in editor
     editor.on('click', function(event) {
-        const clickedEl = event.originalTarget;
+        const clickedEl = event.target;
         if (clickedEl.nodeName === 'LI' && clickedEl.classList.contains('task-list-item')) {
             handleTaskListItemClick(event, clickedEl, editor);
+            event.preventDefault();
         }
     });
 }
 
+/**
+ * @param {Element} element
+ * @return {boolean}
+ */
+function elementWithinTaskList(element) {
+    const listEl = element.closest('li');
+    return listEl && listEl.parentNode.nodeName === 'UL' && listEl.classList.contains('task-list-item');
+}
+
 /**
  * @param {MouseEvent} event
  * @param {Element} clickedEl
@@ -126,6 +147,7 @@ function parseTaskListNode(node) {
  * @param {AstNode} node
  */
 function serializeTaskListNode(node) {
+    // Get checked status and clean it from list node
     const isChecked = node.attr('checked') === 'checked';
     node.attr('checked', null);
 
@@ -134,7 +156,8 @@ function serializeTaskListNode(node) {
         inputAttrs.checked = 'checked';
     }
 
-    const checkbox = new tinymce.html.Node.create('input', inputAttrs);
+    // Create & insert checkbox input element
+    const checkbox = tinymce.html.Node.create('input', inputAttrs);
     checkbox.shortEnded = true;
     node.firstChild ? node.insert(checkbox, node.firstChild, true) : node.append(checkbox);
 }