]> BookStack Code Mirror - bookstack/commitdiff
WYSIWYG details: Improved usage reliability and dark mdoe styles
authorDan Brown <redacted>
Wed, 9 Feb 2022 11:25:22 +0000 (11:25 +0000)
committerDan Brown <redacted>
Wed, 9 Feb 2022 11:25:22 +0000 (11:25 +0000)
resources/js/wysiwyg/config.js
resources/js/wysiwyg/plugins-details.js
resources/sass/_pages.scss
resources/sass/_tinymce.scss

index 13d15e1c5b388c41af489df97c0255c3e14361e1..7fa3b0f26522abc2cbb43cbfc0b51775051f9175 100644 (file)
@@ -210,6 +210,16 @@ body {
 }`.trim().replace('\n', '');
 }
 
+// Custom "Document Root" element, a custom element to identify/define
+// block that may act as another "editable body".
+// Using a custom node means we can identify and add/remove these as desired
+// without affecting user content.
+class DocRootElement extends HTMLDivElement {
+    constructor() {
+        super();
+    }
+}
+
 /**
  * @param {WysiwygConfigOptions} options
  * @return {Object}
@@ -218,8 +228,10 @@ export function build(options) {
 
     // Set language
     window.tinymce.addI18n(options.language, options.translationMap);
-
+    // Build toolbar content
     const {toolbar, groupButtons: toolBarGroupButtons} = buildToolbar(options);
+    // Define our custom root node
+    customElements.define('doc-root', DocRootElement, {extends: 'div'});
 
     // Return config object
     return {
@@ -242,9 +254,10 @@ export function build(options) {
         statusbar: false,
         menubar: false,
         paste_data_images: false,
-        extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram],details[*],summary[*]',
+        extended_valid_elements: 'pre[*],svg[*],div[drawio-diagram],details[*],summary[*],doc-root',
         automatic_uploads: false,
-        valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote],+div[pre],+div[img]",
+        custom_elements: 'doc-root',
+        valid_children: "-div[p|h1|h2|h3|h4|h5|h6|blockquote|div],+div[pre],+div[img],+doc-root[p|h1|h2|h3|h4|h5|h6|blockquote|pre|img|ul|ol],-doc-root[doc-root|#text]",
         plugins: gatherPlugins(options),
         imagetools_toolbar: 'imageoptions',
         contextmenu: false,
index 83a29a29d9f4bd2880cc7562fa212af981a8f9d4..0f089fc8ed55077aff4f92d9d89dfd4457c9af79 100644 (file)
@@ -178,13 +178,16 @@ function setupElementFilters(editor) {
  * @param {tinymce.html.Node} detailsEl
  */
 function ensureDetailsWrappedInEditable(detailsEl) {
+    unwrapDetailsEditable(detailsEl);
+
     detailsEl.attr('contenteditable', 'false');
-    const wrap = tinymce.html.Node.create('div', {detailswrap: 'true', contenteditable: 'true'});
+    const wrap = tinymce.html.Node.create('doc-root', {contenteditable: 'true'});
     for (const child of detailsEl.children()) {
         if (child.name !== 'summary') {
             wrap.append(child);
         }
     }
+
     detailsEl.append(wrap);
 }
 
@@ -193,11 +196,17 @@ function ensureDetailsWrappedInEditable(detailsEl) {
  */
 function unwrapDetailsEditable(detailsEl) {
     detailsEl.attr('contenteditable', null);
+    let madeUnwrap = false;
     for (const child of detailsEl.children()) {
-        if (child.attr('detailswrap')) {
+        if (child.name === 'doc-root') {
             child.unwrap();
+            madeUnwrap = true;
         }
     }
+
+    if (madeUnwrap) {
+        unwrapDetailsEditable(detailsEl);
+    }
 }
 
 
index 49493729906c66a2de9cdc3011ac865dc93504bc..4c54c1045db1527e836d89bb7f93bdcd856abd9e 100755 (executable)
@@ -136,7 +136,8 @@ body.tox-fullscreen, body.markdown-fullscreen {
   }
 
   details {
-    border: 1px solid #DDD;
+    border: 1px solid;
+    @include lightDark(border-color, #DDD, #555);
     margin-bottom: 1em;
     padding: $-s;
   }
@@ -146,11 +147,13 @@ body.tox-fullscreen, body.markdown-fullscreen {
     margin-right: -$-s;
     margin-bottom: -$-s;
     font-weight: bold;
-    background-color: #EEEEEE;
+    @include lightDark(background-color, #EEE, #333);
     padding: $-xs $-s;
   }
   details[open] > summary {
-    margin-bottom: 0;
+    margin-bottom: $-s;
+    border-bottom: 1px solid;
+    @include lightDark(border-color, #DDD, #555);
   }
   details > summary + * {
     margin-top: .2em;
index 57bb697548af418fd90c5485eb6000cc0ac4c56b..ecb258a53f00c1a5b0f51b059af3e52caf1c130c 100644 (file)
   display: block;
 }
 
+// Default styles for our custom root nodes
+.page-content.mce-content-body doc-root {
+  display: block;
+}
+
 // In editor line height override
 .page-content.mce-content-body p {
   line-height: 1.6;
@@ -41,7 +46,7 @@ body.page-content.mce-content-body  {
 .page-content.mce-content-body details summary {
   pointer-events: none;
 }
-.page-content.mce-content-body details [detailswrap] {
+.page-content.mce-content-body details doc-root {
   padding: $-s;
   margin-left: (2px - $-s);
   margin-right: (2px - $-s);