diff --git a/extensions/markdown/extend.php b/extensions/markdown/extend.php index 33baf0a84..77ba694a1 100644 --- a/extensions/markdown/extend.php +++ b/extensions/markdown/extend.php @@ -11,6 +11,9 @@ use Flarum\Extend; use s9e\TextFormatter\Configurator; return [ + (new Extend\Frontend('admin')) + ->js(__DIR__.'/js/dist/admin.js'), + (new Extend\Frontend('forum')) ->js(__DIR__.'/js/dist/forum.js') ->css(__DIR__.'/less/forum.less'), @@ -24,5 +27,7 @@ return [ $config->tags['ispoiler']->template = ''; }), - new Extend\Locales(__DIR__.'/locale') + new Extend\Locales(__DIR__.'/locale'), + + (new Extend\Settings)->serializeToForum('flarum-markdown.mdarea', 'flarum-markdown.mdarea', 'boolval', true) ]; diff --git a/extensions/markdown/js/admin.js b/extensions/markdown/js/admin.js new file mode 100644 index 000000000..3e69ff3b9 --- /dev/null +++ b/extensions/markdown/js/admin.js @@ -0,0 +1 @@ +export * from './src/admin'; diff --git a/extensions/markdown/js/forum.js b/extensions/markdown/js/forum.js index cc78f6edc..facb26fab 100644 --- a/extensions/markdown/js/forum.js +++ b/extensions/markdown/js/forum.js @@ -1,10 +1 @@ -/* - * This file is part of Flarum. - * - * (c) Toby Zerner - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - export * from './src/forum'; diff --git a/extensions/markdown/js/src/admin/index.js b/extensions/markdown/js/src/admin/index.js new file mode 100644 index 000000000..c312dfc22 --- /dev/null +++ b/extensions/markdown/js/src/admin/index.js @@ -0,0 +1,12 @@ +import app from 'flarum/app'; + +app.initializers.add('flarum-markdown', () => { + app.extensionData + .for('flarum-markdown') + .registerSetting({ + setting: 'flarum-markdown.mdarea', + type: 'boolean', + help: app.translator.trans('flarum-markdown.admin.settings.mdarea_help'), + label: app.translator.trans('flarum-markdown.admin.settings.mdarea_label') + }); +}); diff --git a/extensions/markdown/js/src/forum/index.js b/extensions/markdown/js/src/forum/index.js index 95057ff08..2a11b82d3 100644 --- a/extensions/markdown/js/src/forum/index.js +++ b/extensions/markdown/js/src/forum/index.js @@ -12,7 +12,7 @@ import TextEditor from 'flarum/components/TextEditor'; import MarkdownToolbar from './components/MarkdownToolbar'; import MarkdownButton from './components/MarkdownButton'; -import MarkdownAreaEditorDriver from './util/MarkdownAreaEditorDriver'; +import MarkdownEditorDriver from './util/MarkdownEditorDriver'; let shortcutHandler = () => { }; @@ -24,7 +24,7 @@ app.initializers.add('flarum-markdown', function (app) { }); override(TextEditor.prototype, 'buildEditor', function (_, dom) { - return new MarkdownAreaEditorDriver(dom, this.buildEditorParams()); + return new MarkdownEditorDriver(dom, this.buildEditorParams()); }); extend(TextEditor.prototype, 'buildEditorParams', function (params) { diff --git a/extensions/markdown/js/src/forum/util/MarkdownAreaEditorDriver.js b/extensions/markdown/js/src/forum/util/MarkdownAreaEditorDriver.js deleted file mode 100644 index e3fc288f4..000000000 --- a/extensions/markdown/js/src/forum/util/MarkdownAreaEditorDriver.js +++ /dev/null @@ -1,88 +0,0 @@ -import MarkdownArea from 'mdarea'; -import BasicEditorDriver from 'flarum/utils/BasicEditorDriver'; - -export class MarkdownEditorFlarumExtension { - constructor(oninput, callInputListeners, onsubmit) { - this.oninput = oninput; - this.callInputListeners = callInputListeners; - this.onsubmit = onsubmit; - } - - handleKey( - prefix, - selection, - postfix, - evt - ) { - // setTimeout executes after the call stack has cleared, - // so any DOM changes originating from mdarea (e.g. executing an undo) - // will be finished by then. At that time, `e.target.value` will represent - // the updated value of the textarea in response to the keypress. - // Unfortunately, this doesn't work without a value for mobile safari, - // so we need to set 25ms as an arbitrary timeout. - setTimeout(() => { - this.oninput(evt.target.value); - - if ((evt.metaKey || evt.ctrlKey) && evt.key === 'Enter') { - return this.onsubmit(); - } - - this.callInputListeners(evt); - }, 25); - } -} - -export default class MarkdownAreaEditorDriver extends BasicEditorDriver { - build(dom, params) { - this.el.className = params.classNames.join(' '); - this.el.disabled = params.disabled; - this.el.placeholder = params.placeholder; - this.el.value = params.value; - this.el.id = params.textareaId; - - dom.append(this.el); - - const callInputListeners = (e) => { - params.inputListeners.forEach((listener) => { - listener(); - }); - - e.redraw = false; - }; - - // We can't bind shortcutHandler directly in case `build` - // runs before MarkdownToolbar's `oninit`. - this.el.addEventListener('keydown', function (e) { - return params.shortcutHandler(...arguments); - }); - - // Our mdarea extension won't detect programmatic changes via - // the `app.composer.editor api. - this.el.addEventListener('input', function (e) { - if (e instanceof CustomEvent) { - params.oninput(e.target.value); - callInputListeners(e); - } - }); - - // This one can't be run through mdarea, but that doesn't matter - // because mdarea doesn't change value in response to clicks. - this.el.addEventListener('click', callInputListeners); - - this.mdarea = new MarkdownArea(this.el, { - keyMap: { - indent: ['Ctrl+m'], - outdent: ['Ctrl+M'], - inline: [] - }, - extensions: [ - new MarkdownEditorFlarumExtension(params.oninput, callInputListeners, params.onsubmit) - ] - }); - } - - destroy() { - this.mdarea.destroy(); - super.destroy(); - } -} diff --git a/extensions/markdown/js/src/forum/util/MarkdownEditorDriver.js b/extensions/markdown/js/src/forum/util/MarkdownEditorDriver.js new file mode 100644 index 000000000..a13621ccd --- /dev/null +++ b/extensions/markdown/js/src/forum/util/MarkdownEditorDriver.js @@ -0,0 +1,94 @@ +import MarkdownArea from 'mdarea'; +import BasicEditorDriver from 'flarum/utils/BasicEditorDriver'; + +export class MarkdownEditorFlarumExtension { + constructor(oninput, callInputListeners, onsubmit) { + this.oninput = oninput; + this.callInputListeners = callInputListeners; + this.onsubmit = onsubmit; + } + + handleKey( + prefix, + selection, + postfix, + evt + ) { + // setTimeout executes after the call stack has cleared, + // so any DOM changes originating from mdarea (e.g. executing an undo) + // will be finished by then. At that time, `e.target.value` will represent + // the updated value of the textarea in response to the keypress. + // Unfortunately, this doesn't work without a value for mobile safari, + // so we need to set 25ms as an arbitrary timeout. + setTimeout(() => { + this.oninput(evt.target.value); + + if ((evt.metaKey || evt.ctrlKey) && evt.key === 'Enter') { + return this.onsubmit(); + } + + this.callInputListeners(evt); + }, 25); + } +} + +export default class MarkdownEditorDriver extends BasicEditorDriver { + build(dom, params) { + if (app.forum.attribute('flarum-markdown.mdarea')) { + this.el.className = params.classNames.join(' '); + this.el.disabled = params.disabled; + this.el.placeholder = params.placeholder; + this.el.value = params.value; + + dom.append(this.el); + + const callInputListeners = (e) => { + params.inputListeners.forEach((listener) => { + listener(); + }); + + e.redraw = false; + }; + + // Our mdarea extension won't detect programmatic changes via + // the `app.composer.editor api. + this.el.addEventListener('input', function (e) { + if (e instanceof CustomEvent) { + params.oninput(e.target.value); + callInputListeners(e); + } + }); + + // This one can't be run through mdarea, but that doesn't matter + // because mdarea doesn't change value in response to clicks. + this.el.addEventListener('click', callInputListeners); + + this.mdarea = new MarkdownArea(this.el, { + keyMap: { + indent: ['Ctrl+m'], + outdent: ['Ctrl+M'], + inline: [] + }, + extensions: [ + new MarkdownEditorFlarumExtension(params.oninput, callInputListeners, params.onsubmit) + ] + }); + } else { + super.build(dom, params); + } + this.el.id = params.textareaId; + + // We can't bind shortcutHandler directly in case `build` + // runs before MarkdownToolbar's `oninit`. + this.el.addEventListener('keydown', function (e) { + return params.shortcutHandler(...arguments); + }); + } + + destroy() { + if (app.forum.attribute('flarum-markdown.mdarea')) { + this.mdarea.destroy(); + } + super.destroy(); + } +} diff --git a/extensions/markdown/locale/en.yml b/extensions/markdown/locale/en.yml index dd4ad1666..802de9e1f 100644 --- a/extensions/markdown/locale/en.yml +++ b/extensions/markdown/locale/en.yml @@ -1,13 +1,10 @@ flarum-markdown: + admin: + settings: + mdarea_help: mdarea is a textarea util that auto-continues lists, helps with code formatting, and assists with indentation. + mdarea_label: Enable mdarea? - ## - # UNIQUE KEYS - The following keys are used in only one location each. - ## - - # Translations in this namespace are used by the forum user interface. forum: - - # These translations are used by the composer (emoji autocompletion function). composer: bold_tooltip: Add bold text code_tooltip: Insert code diff --git a/extensions/markdown/migrations/2021_03_25_000000_default_settings.php b/extensions/markdown/migrations/2021_03_25_000000_default_settings.php new file mode 100644 index 000000000..261b2faa3 --- /dev/null +++ b/extensions/markdown/migrations/2021_03_25_000000_default_settings.php @@ -0,0 +1,14 @@ + true +]);