-import {EditorView} from "@codemirror/view"
+import {EditorView, keymap} from "@codemirror/view"
import Clipboard from "clipboard/dist/clipboard.min";
// Modes
* @param {HTMLElement} elem
* @param {function} onChange
* @param {object} domEventHandlers
+ * @param {Array} keyBindings
* @returns {*}
*/
-export function markdownEditor(elem, onChange, domEventHandlers) {
+export function markdownEditor(elem, onChange, domEventHandlers, keyBindings) {
const content = elem.textContent;
// TODO - Change to pass something else that's useful, probably extension array?
onChange(v);
}),
EditorView.domEventHandlers(domEventHandlers),
+ keymap.of(keyBindings),
],
});
elem.style.display = 'none';
return ev;
-}
-
-/**
- * Get the 'meta' key dependent on the user's system.
- * @returns {string}
- */
-export function getMetaKey() {
- // TODO - Redo, Is needed? No CodeMirror instance to use.
- const mac = CodeMirror.keyMap["default"] == CodeMirror.keyMap.macDefault;
- return mac ? "Cmd" : "Ctrl";
}
\ No newline at end of file
window.$events.emitPublic(this.elem, 'editor-markdown::setup', {
markdownIt: this.editor.markdown.getRenderer(),
displayEl: this.display,
- // TODO
+ // TODO - change to codeMirrorView?
// codeMirrorInstance: this.editor.cm,
});
}
if (button === null) return;
const action = button.getAttribute('data-action');
- if (action === 'insertImage') this.editor.actions.insertImage();
+ if (action === 'insertImage') this.editor.actions.showImageInsert();
if (action === 'insertLink') this.editor.actions.showLinkSelector();
if (action === 'insertDrawing' && (event.ctrlKey || event.metaKey)) {
this.editor.actions.showImageManager();
return this.lastContent;
}
- insertImage() {
+ showImageInsert() {
+ // TODO
const cursorPos = this.editor.cm.getCursor('from');
/** @type {ImageManager} **/
const imageManager = window.$components.first('image-manager');
}, 'gallery');
}
+ insertImage() {
+ // TODO
+ const selectedText = this.editor.cm.getSelection();
+ const newText = ``;
+ const cursorPos = this.editor.cm.getCursor('from');
+ this.editor.cm.replaceSelection(newText);
+ this.editor.cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1);
+ }
+
insertLink() {
+ // TODO
const cursorPos = this.editor.cm.getCursor('from');
const selectedText = this.editor.cm.getSelection() || '';
const newText = `[${selectedText}]()`;
}
showImageManager() {
+ // TODO
const cursorPos = this.editor.cm.getCursor('from');
/** @type {ImageManager} **/
const imageManager = window.$components.first('image-manager');
// Show the popup link selector and insert a link when finished
showLinkSelector() {
+ // TODO
const cursorPos = this.editor.cm.getCursor('from');
/** @type {EntitySelectorPopup} **/
const selector = window.$components.first('entity-selector-popup');
// Show draw.io if enabled and handle save.
startDrawing() {
+ // TODO
const url = this.editor.config.drawioUrl;
if (!url) return;
}
insertDrawing(image, originalCursor) {
+ // TODO
const newText = `<div drawio-diagram="${image.id}"><img src="${image.url}"></div>`;
this.editor.cm.focus();
this.editor.cm.replaceSelection(newText);
// Show draw.io if enabled and handle save.
editDrawing(imgContainer) {
+ // TODO
const drawioUrl = this.editor.config.drawioUrl;
if (!drawioUrl) {
return;
}
handleDrawingUploadError(error) {
+ // TODO
if (error.status === 413) {
window.$events.emit('error', this.editor.config.text.serverUploadLimit);
} else {
// Make the editor full screen
fullScreen() {
+ // TODO
const container = this.editor.config.container;
const alreadyFullscreen = container.classList.contains('fullscreen');
container.classList.toggle('fullscreen', !alreadyFullscreen);
// Scroll to a specified text
scrollToText(searchText) {
+ // TODO
if (!searchText) {
return;
}
}
focus() {
+ // TODO
this.editor.cm.focus();
}
* @param {String} content
*/
insertContent(content) {
+ // TODO
this.editor.cm.replaceSelection(content);
}
* @param {String} content
*/
prependContent(content) {
+ // TODO
const cursorPos = this.editor.cm.getCursor('from');
const newContent = content + '\n' + this.editor.cm.getValue();
this.editor.cm.setValue(newContent);
* @param {String} content
*/
appendContent(content) {
+ // TODO
const cursorPos = this.editor.cm.getCursor('from');
const newContent = this.editor.cm.getValue() + '\n' + content;
this.editor.cm.setValue(newContent);
* @param {String} content
*/
replaceContent(content) {
+ // TODO
this.editor.cm.setValue(content);
}
* @param {String} replace
*/
findAndReplaceContent(search, replace) {
+ // TODO
const text = this.editor.cm.getValue();
const cursor = this.editor.cm.listSelections();
this.editor.cm.setValue(text.replace(search, replace));
* @param {String} newStart
*/
replaceLineStart(newStart) {
+ // TODO
const cursor = this.editor.cm.getCursor();
let lineContent = this.editor.cm.getLine(cursor.line);
const lineLen = lineContent.length;
* @param {String} end
*/
wrapLine(start, end) {
+ // TODO
const cursor = this.editor.cm.getCursor();
const lineContent = this.editor.cm.getLine(cursor.line);
const lineLen = lineContent.length;
* @param {String} end
*/
wrapSelection(start, end) {
+ // TODO
const selection = this.editor.cm.getSelection();
if (selection === '') return this.wrapLine(start, end);
}
replaceLineStartForOrderedList() {
+ // TODO
const cursor = this.editor.cm.getCursor();
const prevLineContent = this.editor.cm.getLine(cursor.line - 1) || '';
const listMatch = prevLineContent.match(/^(\s*)(\d)([).])\s/) || [];
* Creates a callout block if none existing, and removes it if cycling past the danger type.
*/
cycleCalloutTypeAtSelection() {
+ // TODO
const selectionRange = this.editor.cm.listSelections()[0];
const lineContent = this.editor.cm.getLine(selectionRange.anchor.line);
const lineLength = lineContent.length;
* @param {File} file
*/
uploadImage(file) {
+ // TODO
if (file === null || file.type.indexOf('image') !== 0) return;
let ext = 'png';
* @param {Number} posY
*/
insertTemplate(templateId, posX, posY) {
+ // TODO
const cursorPos = this.editor.cm.coordsChar({left: posX, top: posY});
this.editor.cm.setCursor(cursorPos);
window.$http.get(`/templates/${templateId}`).then(resp => {
* @param {File[]} images
*/
insertClipboardImages(images) {
+ // TODO
const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY});
this.editor.cm.setCursor(cursorPos);
for (const image of images) {
-import {provide as provideShortcuts} from "./shortcuts";
+import {provideKeyBindings} from "./shortcuts";
import {debounce} from "../services/util";
import Clipboard from "../services/clipboard";
scroll: (event) => syncActive && onScrollDebounced(event)
}
- const cm = Code.markdownEditor(editor.config.inputEl, onViewUpdate, domEventHandlers);
+ const cm = Code.markdownEditor(
+ editor.config.inputEl,
+ onViewUpdate,
+ domEventHandlers,
+ provideKeyBindings(editor),
+ );
window.cm = cm;
// Will force to remain as ltr for now due to issues when HTML is in editor.
// TODO
// cm.setOption('direction', 'ltr');
- // Register shortcuts
- // TODO
- // cm.setOption('extraKeys', provideShortcuts(editor, Code.getMetaKey()));
// Handle image paste
/**
- * Provide shortcuts for the given codemirror instance.
+ * Provide shortcuts for the editor instance.
* @param {MarkdownEditor} editor
- * @param {String} metaKey
* @returns {Object<String, Function>}
*/
-export function provide(editor, metaKey) {
+function provide(editor) {
const shortcuts = {};
// Insert Image shortcut
- shortcuts[`${metaKey}-Alt-I`] = function(cm) {
- const selectedText = cm.getSelection();
- const newText = ``;
- const cursorPos = cm.getCursor('from');
- cm.replaceSelection(newText);
- cm.setCursor(cursorPos.line, cursorPos.ch + newText.length -1);
- };
+ shortcuts['Mod-Alt-i'] = () => editor.actions.insertImage();
// Save draft
- shortcuts[`${metaKey}-S`] = cm => window.$events.emit('editor-save-draft');
+ shortcuts['Mod-s'] = cm => window.$events.emit('editor-save-draft');
// Save page
- shortcuts[`${metaKey}-Enter`] = cm => window.$events.emit('editor-save-page');
+ shortcuts['Mod-Enter'] = cm => window.$events.emit('editor-save-page');
// Show link selector
- shortcuts[`Shift-${metaKey}-K`] = cm => editor.actions.showLinkSelector();
+ shortcuts['Shift-Mod-k'] = cm => editor.actions.showLinkSelector();
// Insert Link
- shortcuts[`${metaKey}-K`] = cm => editor.actions.insertLink();
+ shortcuts['Mod-k'] = cm => editor.actions.insertLink();
// FormatShortcuts
- shortcuts[`${metaKey}-1`] = cm => editor.actions.replaceLineStart('##');
- shortcuts[`${metaKey}-2`] = cm => editor.actions.replaceLineStart('###');
- shortcuts[`${metaKey}-3`] = cm => editor.actions.replaceLineStart('####');
- shortcuts[`${metaKey}-4`] = cm => editor.actions.replaceLineStart('#####');
- shortcuts[`${metaKey}-5`] = cm => editor.actions.replaceLineStart('');
- shortcuts[`${metaKey}-D`] = cm => editor.actions.replaceLineStart('');
- shortcuts[`${metaKey}-6`] = cm => editor.actions.replaceLineStart('>');
- shortcuts[`${metaKey}-Q`] = cm => editor.actions.replaceLineStart('>');
- shortcuts[`${metaKey}-7`] = cm => editor.actions.wrapSelection('\n```\n', '\n```');
- shortcuts[`${metaKey}-8`] = cm => editor.actions.wrapSelection('`', '`');
- shortcuts[`Shift-${metaKey}-E`] = cm => editor.actions.wrapSelection('`', '`');
- shortcuts[`${metaKey}-9`] = cm => editor.actions.cycleCalloutTypeAtSelection();
- shortcuts[`${metaKey}-P`] = cm => editor.actions.replaceLineStart('-')
- shortcuts[`${metaKey}-O`] = cm => editor.actions.replaceLineStartForOrderedList()
+ shortcuts['Mod-1'] = cm => editor.actions.replaceLineStart('##');
+ shortcuts['Mod-2'] = cm => editor.actions.replaceLineStart('###');
+ shortcuts['Mod-3'] = cm => editor.actions.replaceLineStart('####');
+ shortcuts['Mod-4'] = cm => editor.actions.replaceLineStart('#####');
+ shortcuts['Mod-5'] = cm => editor.actions.replaceLineStart('');
+ shortcuts['Mod-d'] = cm => editor.actions.replaceLineStart('');
+ shortcuts['Mod-6'] = cm => editor.actions.replaceLineStart('>');
+ shortcuts['Mod-q'] = cm => editor.actions.replaceLineStart('>');
+ shortcuts['Mod-7'] = cm => editor.actions.wrapSelection('\n```\n', '\n```');
+ shortcuts['Mod-8'] = cm => editor.actions.wrapSelection('`', '`');
+ shortcuts['Shift-Mod-e'] = cm => editor.actions.wrapSelection('`', '`');
+ shortcuts['Mod-9'] = cm => editor.actions.cycleCalloutTypeAtSelection();
+ shortcuts['Mod-p'] = cm => editor.actions.replaceLineStart('-')
+ shortcuts['Mod-o'] = cm => editor.actions.replaceLineStartForOrderedList()
return shortcuts;
+}
+
+/**
+ * Get the editor shortcuts in CodeMirror keybinding format.
+ * @param {MarkdownEditor} editor
+ * @return {{key: String, run: function, preventDefault: boolean}[]}
+ */
+export function provideKeyBindings(editor) {
+ const shortcuts= provide(editor);
+ const keyBindings = [];
+
+ for (const [shortcut, action] of Object.entries(shortcuts)) {
+ keyBindings.push({key: shortcut, run: action, preventDefault: true});
+ }
+
+ return keyBindings;
}
\ No newline at end of file