Attach oninput, inputListeners, onsubmit via mdarea extension

Recent versions of mdarea are quite powerful, and have internal state data structures. As a result, updating current editor value via `oninput` event listeners isn't reliable. Instead, we can use the mdarea extension API to handle keypresses exactly when markdownarea wants us to.

This also removes the `super` call from `build`, and directly creates/configures the applicable DOM elements. Since the mdarea editor driver's initialization is already quite different from BasicEditorDriver, it should fully own this step.
This commit is contained in:
Alexander Skvortsov 2021-02-27 16:05:25 -05:00
parent aa62e69dab
commit 09b14b980a

View File

@ -1,23 +1,72 @@
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 without a time 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.
setTimeout(() => {
this.oninput(evt.target.value);
if ((evt.metaKey || evt.ctrlKey) && evt.key === 'Enter') {
return this.onsubmit();
}
this.callInputListeners(evt);
});
}
}
export default class MarkdownAreaEditorDriver extends BasicEditorDriver {
build(dom, params) {
super.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);
// We can't bind shortcutHandler directly in case `build`
// runs before MarkdownToolbar's `oninit`.
this.el.addEventListener('keydown', function (e) {
return params.shortcutHandler(...arguments);
});
const callInputListeners = (e) => {
params.inputListeners.forEach((listener) => {
listener();
});
e.redraw = false;
};
// 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)
]
});
}