diff --git a/resources/js/markdown/actions.js b/resources/js/markdown/actions.js index 96f9b263c..c2c3409a5 100644 --- a/resources/js/markdown/actions.js +++ b/resources/js/markdown/actions.js @@ -326,6 +326,44 @@ export class Actions { return this.replaceLineStart(prefix); } + /** + * Cycles through the type of callout block within the selection. + * Creates a callout block if none existing, and removes it if cycling past the danger type. + */ + cycleCalloutTypeAtSelection() { + const selectionRange = this.editor.cm.listSelections()[0]; + const lineContent = this.editor.cm.getLine(selectionRange.anchor.line); + const lineLength = lineContent.length; + const contentRange = { + anchor: {line: selectionRange.anchor.line, ch: 0}, + head: {line: selectionRange.anchor.line, ch: lineLength}, + }; + + const formats = ['info', 'success', 'warning', 'danger']; + const joint = formats.join('|'); + const regex = new RegExp(`class="((${joint})\\s+callout|callout\\s+(${joint}))"`, 'i'); + const matches = regex.exec(lineContent); + const format = (matches ? (matches[2] || matches[3]) : '').toLowerCase(); + + if (format === formats[formats.length - 1]) { + this.wrapLine(`<p class="callout ${formats[formats.length - 1]}">`, '</p>'); + } else if (format === '') { + this.wrapLine('<p class="callout info">', '</p>'); + } else { + const newFormatIndex = formats.indexOf(format) + 1; + const newFormat = formats[newFormatIndex]; + const newContent = lineContent.replace(matches[0], matches[0].replace(format, newFormat)); + this.editor.cm.replaceRange(newContent, contentRange.anchor, contentRange.head); + + const chDiff = newContent.length - lineContent.length; + selectionRange.anchor.ch += chDiff; + if (selectionRange.anchor !== selectionRange.head) { + selectionRange.head.ch += chDiff; + } + this.editor.cm.setSelection(selectionRange.anchor, selectionRange.head); + } + } + /** * Handle image upload and add image into markdown content * @param {File} file @@ -404,7 +442,7 @@ export class Actions { const cursorPos = this.editor.cm.coordsChar({left: event.pageX, top: event.pageY}); this.editor.cm.setCursor(cursorPos); for (const image of images) { - this.editor.actions.uploadImage(image); + this.uploadImage(image); } } } \ No newline at end of file diff --git a/resources/js/markdown/shortcuts.js b/resources/js/markdown/shortcuts.js index 1249f7d60..17ffe2fb3 100644 --- a/resources/js/markdown/shortcuts.js +++ b/resources/js/markdown/shortcuts.js @@ -40,7 +40,7 @@ export function provide(editor, metaKey) { 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.wrapSelection('<p class="callout info">', '</p>'); + shortcuts[`${metaKey}-9`] = cm => editor.actions.cycleCalloutTypeAtSelection(); shortcuts[`${metaKey}-P`] = cm => editor.actions.replaceLineStart('-') shortcuts[`${metaKey}-O`] = cm => editor.actions.replaceLineStartForOrderedList()