From 1738957af7bd37e8b5f53d75b3b6858f3ca1d45d Mon Sep 17 00:00:00 2001
From: David Wheatley <hi@davwheat.dev>
Date: Thu, 30 Dec 2021 22:02:25 +0100
Subject: [PATCH] feat: make markdown toolbar extensible (#33)

---
 extensions/markdown/js/src/forum/index.js | 63 ++++++++++++++++-------
 1 file changed, 43 insertions(+), 20 deletions(-)

diff --git a/extensions/markdown/js/src/forum/index.js b/extensions/markdown/js/src/forum/index.js
index 9ee2c8ab4..1cb9a8f46 100644
--- a/extensions/markdown/js/src/forum/index.js
+++ b/extensions/markdown/js/src/forum/index.js
@@ -8,13 +8,14 @@
  */
 
 import app from 'flarum/forum/app';
-import { extend } from 'flarum/common/extend';
+import { extend, override } from 'flarum/common/extend';
 import TextEditor from 'flarum/common/components/TextEditor';
 import BasicEditorDriver from 'flarum/common/utils/BasicEditorDriver';
 import styleSelectedText from 'flarum/common/utils/styleSelectedText';
 
 import MarkdownToolbar from './components/MarkdownToolbar';
 import MarkdownButton from './components/MarkdownButton';
+import ItemList from 'flarum/common/utils/ItemList';
 
 const modifierKey = navigator.userAgent.match(/Macintosh/) ? '⌘' : 'ctrl';
 
@@ -48,35 +49,57 @@ function makeShortcut(id, key, editorDriver) {
   };
 }
 
+function markdownToolbarItems(oldFunc) {
+  const items = typeof oldFunc === 'function' ? oldFunc() : new ItemList();
+
+  function tooltip(name, hotkey) {
+    return app.translator.trans(`flarum-markdown.forum.composer.${name}_tooltip`) + (hotkey ? ` <${modifierKey}-${hotkey}>` : '');
+  }
+
+  const makeApplyStyle = (id) => {
+    return () => applyStyle(id, this.attrs.composer.editor);
+  };
+
+  items.add('header', <MarkdownButton title={tooltip('header')} icon="fas fa-heading" onclick={makeApplyStyle('header')} />, 1000);
+  items.add('bold', <MarkdownButton title={tooltip('bold', 'b')} icon="fas fa-bold" onclick={makeApplyStyle('bold')} />, 900);
+  items.add('italic', <MarkdownButton title={tooltip('italic', 'i')} icon="fas fa-italic" onclick={makeApplyStyle('italic')} />, 800);
+  items.add(
+    'strikethrough',
+    <MarkdownButton title={tooltip('strikethrough')} icon="fas fa-strikethrough" onclick={makeApplyStyle('strikethrough')} />,
+    700
+  );
+  items.add('quote', <MarkdownButton title={tooltip('quote')} icon="fas fa-quote-left" onclick={makeApplyStyle('quote')} />, 600);
+  items.add('spoiler', <MarkdownButton title={tooltip('spoiler')} icon="fas fa-exclamation-triangle" onclick={makeApplyStyle('spoiler')} />, 500);
+  items.add('code', <MarkdownButton title={tooltip('code')} icon="fas fa-code" onclick={makeApplyStyle('code')} />, 400);
+  items.add('link', <MarkdownButton title={tooltip('link')} icon="fas fa-link" onclick={makeApplyStyle('link')} />, 300);
+  items.add('image', <MarkdownButton title={tooltip('image')} icon="fas fa-image" onclick={makeApplyStyle('image')} />, 200);
+  items.add(
+    'unordered_list',
+    <MarkdownButton title={tooltip('unordered_list')} icon="fas fa-list-ul" onclick={makeApplyStyle('unordered_list')} />,
+    100
+  );
+  items.add('ordered_list', <MarkdownButton title={tooltip('ordered_list')} icon="fas fa-list-ol" onclick={makeApplyStyle('ordered_list')} />, 0);
+
+  return items;
+}
+
 app.initializers.add('flarum-markdown', function (app) {
   extend(BasicEditorDriver.prototype, 'keyHandlers', function (items) {
     items.add('bold', makeShortcut('bold', 'b', this));
     items.add('italic', makeShortcut('italic', 'i', this));
   });
 
+  if (TextEditor.prototype.markdownToolbarItems) {
+    override(TextEditor.prototype, 'markdownToolbarItems', markdownToolbarItems);
+  } else {
+    TextEditor.prototype.markdownToolbarItems = markdownToolbarItems;
+  }
+
   extend(TextEditor.prototype, 'toolbarItems', function (items) {
-    const tooltip = (name, hotkey) => {
-      return app.translator.trans(`flarum-markdown.forum.composer.${name}_tooltip`) + (hotkey ? ` <${modifierKey}-${hotkey}>` : '');
-    };
-
-    const makeApplyStyle = (id) => {
-      return () => applyStyle(id, this.attrs.composer.editor);
-    };
-
     items.add(
       'markdown',
       <MarkdownToolbar for={this.textareaId} setShortcutHandler={(handler) => (shortcutHandler = handler)}>
-        <MarkdownButton title={tooltip('header')} icon="fas fa-heading" onclick={makeApplyStyle('header')} />
-        <MarkdownButton title={tooltip('bold', 'b')} icon="fas fa-bold" onclick={makeApplyStyle('bold')} />
-        <MarkdownButton title={tooltip('italic', 'i')} icon="fas fa-italic" onclick={makeApplyStyle('italic')} />
-        <MarkdownButton title={tooltip('strikethrough')} icon="fas fa-strikethrough" onclick={makeApplyStyle('strikethrough')} />
-        <MarkdownButton title={tooltip('quote')} icon="fas fa-quote-left" onclick={makeApplyStyle('quote')} />
-        <MarkdownButton title={tooltip('spoiler')} icon="fas fa-exclamation-triangle" onclick={makeApplyStyle('spoiler')} />
-        <MarkdownButton title={tooltip('code')} icon="fas fa-code" onclick={makeApplyStyle('code')} />
-        <MarkdownButton title={tooltip('link')} icon="fas fa-link" onclick={makeApplyStyle('link')} />
-        <MarkdownButton title={tooltip('image')} icon="fas fa-image" onclick={makeApplyStyle('image')} />
-        <MarkdownButton title={tooltip('unordered_list')} icon="fas fa-list-ul" onclick={makeApplyStyle('unordered_list')} />
-        <MarkdownButton title={tooltip('ordered_list')} icon="fas fa-list-ol" onclick={makeApplyStyle('ordered_list')} />
+        {this.markdownToolbarItems().toArray()}
       </MarkdownToolbar>,
       100
     );