Pārlūkot izejas kodu

Replace Quill editor with TinyMCE

Heiko Salmon 3 gadi atpakaļ
vecāks
revīzija
c09d2fcd5d
3 mainītis faili ar 51 papildinājumiem un 198 dzēšanām
  1. 2 3
      frontend/package.json
  2. 38 126
      frontend/src/components/Editor.vue
  3. 11 69
      frontend/yarn.lock

+ 2 - 3
frontend/package.json

@@ -9,6 +9,7 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
+    "@tinymce/tinymce-vue": "^3",
     "axios": "^0.21.1",
     "buefy": "^0.9.10",
     "c3": "^0.7.20",
@@ -17,13 +18,11 @@
     "dayjs": "^1.10.4",
     "humps": "^2.0.1",
     "qs": "^6.10.1",
-    "quill": "^1.3.7",
-    "quill-delta": "^4.2.2",
     "textversionjs": "^1.1.3",
+    "tinymce": "^5.9.2",
     "turndown": "^7.0.0",
     "vue": "^2.6.12",
     "vue-i18n": "^8.22.2",
-    "vue-quill-editor": "^3.0.6",
     "vue-router": "^3.2.0",
     "vuex": "^3.6.2"
   },

+ 38 - 126
frontend/src/components/Editor.vue

@@ -31,16 +31,27 @@
     </div>
 
     <!-- wsywig //-->
-    <quill-editor
-      :class="{'fullscreen': isEditorFullscreen}"
-      v-if="form.format === 'richtext'"
+    <tiny-mce
       v-model="form.body"
-      ref="quill"
-      :options="options"
+      v-if="form.format === 'richtext'"
       :disabled="disabled"
-      :placeholder="$t('campaigns.contentHelp')"
-      @change="onEditorChange($event)"
-      @ready="onEditorReady($event)"
+      :init="{
+         height: 500,
+         menubar: false,
+         plugins: [
+           'lists', 'link', 'image', 'charmap', 'anchor',
+           'fullscreen', 'table', 'code', 'wordcount', 'hr',
+         ],
+         toolbar: 'undo redo | formatselect fontsizeselect | bold italic backcolor | ' +
+           'alignleft aligncenter alignright alignjustify | ' +
+           'bullist numlist table | outdent indent | removeformat | link hr',
+         skin: false,
+         content_css: false,
+         content_style: 'body { font-family: \'Helvetica Neue\', \'Segoe UI\', Helvetica, sans-serif; font-size: 15px; line-height: 26px; color: #444; }' +
+           'img { max-width: 100%; }'+
+           'a { color: #0055d4; }'+
+           'a:hover { color: #111; }'
+         }"
     />
 
     <!-- raw html editor //-->
@@ -73,54 +84,35 @@
 </template>
 
 <script>
-import 'quill/dist/quill.snow.css';
-import 'quill/dist/quill.core.css';
-
-import { quillEditor, Quill } from 'vue-quill-editor';
 import CodeFlask from 'codeflask';
 import TurndownService from 'turndown';
-import { colors } from '../constants';
 
+import 'tinymce';
+import 'tinymce/icons/default';
+import 'tinymce/themes/silver';
+import 'tinymce/skins/ui/oxide/skin.css';
+import 'tinymce/plugins/code';
+import 'tinymce/plugins/link';
+import 'tinymce/plugins/lists';
+import 'tinymce/plugins/table';
+import 'tinymce/plugins/hr';
+import 'tinymce/plugins/wordcount';
+import 'tinymce/plugins/charmap';
+import 'tinymce/plugins/image';
+import 'tinymce/plugins/anchor';
+import 'tinymce/plugins/fullscreen';
+
+import TinyMce from '@tinymce/tinymce-vue';
 import CampaignPreview from './CampaignPreview.vue';
 import Media from '../views/Media.vue';
 
-// Setup Quill to use inline CSS style attributes instead of classes.
-Quill.register(Quill.import('attributors/attribute/direction'), true);
-Quill.register(Quill.import('attributors/style/align'), true);
-Quill.register(Quill.import('attributors/style/background'), true);
-Quill.register(Quill.import('attributors/style/color'), true);
-Quill.register(Quill.import('formats/indent'), true);
-
-const quillFontSizes = Quill.import('attributors/style/size');
-quillFontSizes.whitelist = ['11px', '13px', '22px', '32px'];
-Quill.register(quillFontSizes, true);
-
-// Sanitize {{ TrackLink "xxx" }} quotes to backticks.
-const regLink = new RegExp(/{{(\s+)?TrackLink(\s+)?"(.+?)"(\s+)?}}/);
-const Link = Quill.import('formats/link');
-Link.sanitize = (l) => l.replace(regLink, '{{ TrackLink `$3`}}');
-
 const turndown = new TurndownService();
 
-// Custom class to override the default indent behaviour to get inline CSS
-// style instead of classes.
-class IndentAttributor extends Quill.import('parchment').Attributor.Style {
-  multiplier = 30;
-
-  add(node, value) {
-    return super.add(node, `${value * this.multiplier}px`);
-  }
-
-  value(node) {
-    return parseFloat(super.value(node)) / this.multiplier || undefined;
-  }
-}
-
 export default {
   components: {
     Media,
     CampaignPreview,
-    quillEditor,
+    TinyMce,
   },
 
   props: {
@@ -153,49 +145,6 @@ export default {
       // where the caret may be lost.
       lastSel: null,
 
-      // Quill editor options.
-      options: {
-        placeholder: this.$t('campaigns.contentHelp'),
-        modules: {
-          keyboard: {
-            bindings: {
-              esc: {
-                key: 27,
-                handler: () => {
-                  this.onToggleFullscreen(true);
-                },
-              },
-            },
-          },
-          toolbar: {
-            container: [
-              [{ header: [1, 2, 3, false] }],
-              ['bold', 'italic', 'underline', 'strike', 'blockquote', 'code'],
-              [{ color: [] }, { background: [] }, { size: quillFontSizes.whitelist }],
-              [
-                { list: 'ordered' },
-                { list: 'bullet' },
-                { indent: '-1' },
-                { indent: '+1' },
-              ],
-              [
-                { align: '' },
-                { align: 'center' },
-                { align: 'right' },
-                { align: 'justify' },
-              ],
-              ['link', 'image'],
-              ['clean', 'fullscreen'],
-            ],
-
-            handlers: {
-              image: this.onToggleMedia,
-              fullscreen: () => this.onToggleFullscreen(false),
-            },
-          },
-        },
-      },
-
       // HTML editor.
       flask: null,
     };
@@ -216,15 +165,6 @@ export default {
       );
     },
 
-    onEditorReady() {
-      this.isReady = true;
-
-      // Hack to focus the editor on page load.
-      this.$nextTick(() => {
-        window.setTimeout(() => this.$refs.quill.quill.focus(), 100);
-      });
-    },
-
     onEditorChange() {
       if (!this.isReady) {
         return;
@@ -243,9 +183,6 @@ export default {
         <style>
           .codeflask .codeflask__flatten { font-size: 15px; }
           .codeflask .codeflask__lines { background: #fafafa; z-index: 10; }
-          .codeflask .token.tag { font-weight: bold; }
-          .codeflask .token.attr-name { color: #111; }
-          .codeflask .token.attr-value { color: ${colors.primary} !important; }
         </style>
         <div id="area"></area>
       `;
@@ -274,22 +211,9 @@ export default {
       this.isPreviewing = !this.isPreviewing;
     },
 
-    onToggleMedia() {
-      this.lastSel = this.$refs.quill.quill.getSelection();
-      this.isMediaVisible = !this.isMediaVisible;
-    },
-
-    onToggleFullscreen(onlyMinimize) {
-      if (onlyMinimize) {
-        if (!this.isEditorFullscreen) {
-          return;
-        }
-      }
-      this.isEditorFullscreen = !this.isEditorFullscreen;
-    },
-
     onMediaSelect(m) {
-      this.$refs.quill.quill.insertEmbed(this.lastSel.index || 0, 'image', m.url);
+      // TODO: Embed image to TinyMce
+      console.log('onMediaSelect', m);
     },
 
     beautifyHTML(str) {
@@ -400,17 +324,5 @@ export default {
       this.onEditorChange();
     },
   },
-
-  mounted() {
-    // Initialize the Quill indentation plugin.
-    const levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
-    const multiplier = 30;
-    const indentStyle = new IndentAttributor('indent', 'margin-left', {
-      scope: Quill.import('parchment').Scope.BLOCK,
-      whitelist: levels.map((value) => `${value * multiplier}px`),
-    });
-
-    Quill.register(indentStyle);
-  },
 };
 </script>

+ 11 - 69
frontend/yarn.lock

@@ -1265,6 +1265,11 @@
   resolved "https://registry.yarnpkg.com/@soda/get-current-script/-/get-current-script-1.0.1.tgz#f4afffcb36e069a801d5339c90499601c47a2516"
   integrity sha512-zeOomWIE52M9JpYXlsR3iOf7TXTTmNQHnSbqjMsQZ5phzfAenHzL/1+vQ0ZoJfagocK11LNf8vnn2JG0ufRMUQ==
 
+"@tinymce/tinymce-vue@^3":
+  version "3.2.8"
+  resolved "https://registry.yarnpkg.com/@tinymce/tinymce-vue/-/tinymce-vue-3.2.8.tgz#014571b52ec8fa83665a7fa887bf65140207de71"
+  integrity sha512-jEz+NZ0g+FZFz273OEUWz9QkwPMyjc5AJYyxOgu51O1Y5UaJ/6IUddXTX6A20mwCleEv5ebwNYdalviafx4fnA==
+
 "@types/body-parser@*":
   version "1.19.0"
   resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.0.tgz#0685b3c47eb3006ffed117cdd55164b61f80538f"
@@ -3012,11 +3017,6 @@ clone@^1.0.2:
   resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
   integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
 
-clone@^2.1.1:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
-  integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
-
 coa@^2.0.2:
   version "2.0.2"
   resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3"
@@ -4629,11 +4629,6 @@ eventemitter2@^6.4.2:
   resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.4.tgz#aa96e8275c4dbeb017a5d0e03780c65612a1202b"
   integrity sha512-HLU3NDY6wARrLCEwyGKRBvuWYyvW6mHYv72SJJAH3iJN3a6eVUvkjFkcxah1bcTgGVBBrFdIopBJPhCQFMLyXw==
 
-eventemitter3@^2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
-  integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo=
-
 eventemitter3@^4.0.0:
   version "4.0.4"
   resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384"
@@ -4792,7 +4787,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
     assign-symbols "^1.0.0"
     is-extendable "^1.0.1"
 
-extend@^3.0.2, extend@~3.0.2:
+extend@~3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
   integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
@@ -4850,16 +4845,6 @@ fast-deep-equal@^3.1.3:
   resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
   integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
 
-fast-diff@1.1.2:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
-  integrity sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig==
-
-fast-diff@1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
-  integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
-
 fast-glob@^2.2.6:
   version "2.2.7"
   resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
@@ -6597,11 +6582,6 @@ lodash.defaultsdeep@^4.6.1:
   resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6"
   integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA==
 
-lodash.isequal@^4.5.0:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
-  integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
-
 lodash.kebabcase@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
@@ -7511,11 +7491,6 @@ param-case@2.1.x:
   dependencies:
     no-case "^2.2.0"
 
-parchment@^1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/parchment/-/parchment-1.1.4.tgz#aeded7ab938fe921d4c34bc339ce1168bc2ffde5"
-  integrity sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg==
-
 parent-module@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -8266,36 +8241,6 @@ querystringify@^2.1.1:
   resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
   integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
 
-quill-delta@^3.6.2:
-  version "3.6.3"
-  resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-3.6.3.tgz#b19fd2b89412301c60e1ff213d8d860eac0f1032"
-  integrity sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==
-  dependencies:
-    deep-equal "^1.0.1"
-    extend "^3.0.2"
-    fast-diff "1.1.2"
-
-quill-delta@^4.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/quill-delta/-/quill-delta-4.2.2.tgz#015397d046e0a3bed087cd8a51f98c11a1b8f351"
-  integrity sha512-qjbn82b/yJzOjstBgkhtBjN2TNK+ZHP/BgUQO+j6bRhWQQdmj2lH6hXG7+nwwLF41Xgn//7/83lxs9n2BkTtTg==
-  dependencies:
-    fast-diff "1.2.0"
-    lodash.clonedeep "^4.5.0"
-    lodash.isequal "^4.5.0"
-
-quill@^1.3.4, quill@^1.3.7:
-  version "1.3.7"
-  resolved "https://registry.yarnpkg.com/quill/-/quill-1.3.7.tgz#da5b2f3a2c470e932340cdbf3668c9f21f9286e8"
-  integrity sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==
-  dependencies:
-    clone "^2.1.1"
-    deep-equal "^1.0.1"
-    eventemitter3 "^2.0.3"
-    extend "^3.0.2"
-    parchment "^1.1.4"
-    quill-delta "^3.6.2"
-
 ramda@~0.27.1:
   version "0.27.1"
   resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.27.1.tgz#66fc2df3ef873874ffc2da6aa8984658abacf5c9"
@@ -9579,6 +9524,11 @@ timsort@^0.3.0:
   resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
   integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=
 
+tinymce@^5.9.2:
+  version "5.9.2"
+  resolved "https://registry.yarnpkg.com/tinymce/-/tinymce-5.9.2.tgz#c56a1d7800ac23026fbe6e0fcf444c0f157ccafe"
+  integrity sha512-/dHTsbxo0YwLvB5krRqiw/qHEm04/k6l0dvAQ3hO5oNw4e9QalKcUQCdr+g/b/FWcsUMP6scvKmm8MX50/j3Cg==
+
 tmp@^0.0.33:
   version "0.0.33"
   resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
@@ -10033,14 +9983,6 @@ vue-loader@^15.9.2:
     vue-hot-reload-api "^2.3.0"
     vue-style-loader "^4.1.0"
 
-vue-quill-editor@^3.0.6:
-  version "3.0.6"
-  resolved "https://registry.yarnpkg.com/vue-quill-editor/-/vue-quill-editor-3.0.6.tgz#1f85646211d68a31a80a72cb7f45bb2f119bc8fb"
-  integrity sha512-g20oSZNWg8Hbu41Kinjd55e235qVWPLfg4NvsLW6d+DhgBTFbEuMpcWlUdrD6qT3+Noim6DRu18VLM9lVShXOQ==
-  dependencies:
-    object-assign "^4.1.1"
-    quill "^1.3.4"
-
 vue-router@^3.2.0:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.3.2.tgz#0099de402edb2fe92f9711053ab5a2156f239cad"