diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.js b/app/assets/javascripts/discourse/app/lib/plugin-api.js index 6c4c308bde4..bb2dd1457bc 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.js +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.js @@ -100,7 +100,7 @@ import { addSectionLink } from "discourse/lib/sidebar/custom-topics-section-link // based on Semantic Versioning 2.0.0. Please update the changelog at // docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version // using the format described at https://keepachangelog.com/en/1.0.0/. -const PLUGIN_API_VERSION = "1.2.0"; +const PLUGIN_API_VERSION = "1.3.0"; // This helper prevents us from applying the same `modifyClass` over and over in test mode. function canModify(klass, type, resolverName, changes) { diff --git a/app/assets/javascripts/discourse/app/lib/to-markdown.js b/app/assets/javascripts/discourse/app/lib/to-markdown.js index df260ab55e2..95ead9c4ae6 100644 --- a/app/assets/javascripts/discourse/app/lib/to-markdown.js +++ b/app/assets/javascripts/discourse/app/lib/to-markdown.js @@ -11,6 +11,50 @@ const hasChild = (e, n) => { return (e.children || []).some((c) => c.name === n); }; +let tagDecorateCallbacks = []; +let blockDecorateCallbacks = []; + +/** + * Allows to add support for custom inline markdown/bbcode + * + * ``` + * addTagDecorateCallback(function (text) { + * if (this.element.attributes.class === "loud") { + * this.prefix = "^^"; + * this.suffix = "^^"; + * return text.toLowerCase(); + * } + * }); + * ``` + */ +export function addTagDecorateCallback(callback) { + tagDecorateCallbacks.push(callback); +} + +export function clearTagDecorateCallbacks() { + tagDecorateCallbacks = []; +} + +/** + * Allows to add support for custom block markdown/bbcode + * + * ``` + * addBlockDecorateCallback(function (text) { + * if (this.element.attributes.class === "spoiled") { + * this.prefix = "[spoiler]"; + * this.suffix = "[/spoiler]"; + * } + * }); + * ``` + */ +export function addBlockDecorateCallback(callback) { + blockDecorateCallbacks.push(callback); +} + +export function clearBlockDecorateCallbacks() { + blockDecorateCallbacks = []; +} + export class Tag { constructor(name, prefix = "", suffix = "", inline = false) { this.name = name; @@ -20,6 +64,14 @@ export class Tag { } decorate(text) { + for (const callback of tagDecorateCallbacks) { + const result = callback.call(this, text); + + if (typeof result !== "undefined") { + text = result; + } + } + if (this.prefix || this.suffix) { text = [this.prefix, text, this.suffix].join(""); } @@ -137,6 +189,14 @@ export class Tag { decorate(text) { const parent = this.element.parent; + for (const callback of blockDecorateCallbacks) { + const result = callback.call(this, text); + + if (typeof result !== "undefined") { + text = result; + } + } + if (this.name === "p" && parent && parent.name === "li") { // fix for google docs this.gap = ""; diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js index daa06030ec3..91077116d71 100644 --- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js +++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js @@ -64,6 +64,10 @@ import { } from "discourse/lib/user-presence"; import PreloadStore from "discourse/lib/preload-store"; import { resetDefaultSectionLinks as resetTopicsSectionLinks } from "discourse/lib/sidebar/custom-topics-section-links"; +import { + clearBlockDecorateCallbacks, + clearTagDecorateCallbacks, +} from "discourse/lib/to-markdown"; const LEGACY_ENV = !setupApplicationTest; @@ -188,6 +192,8 @@ function testCleanup(container, app) { } restoreBaseUri(); resetTopicsSectionLinks(); + clearTagDecorateCallbacks(); + clearBlockDecorateCallbacks(); } export function discourseModule(name, options) { diff --git a/app/assets/javascripts/discourse/tests/unit/lib/to-markdown-test.js b/app/assets/javascripts/discourse/tests/unit/lib/to-markdown-test.js index c5e7b68b43f..b873104ad11 100644 --- a/app/assets/javascripts/discourse/tests/unit/lib/to-markdown-test.js +++ b/app/assets/javascripts/discourse/tests/unit/lib/to-markdown-test.js @@ -1,5 +1,8 @@ import { module, test } from "qunit"; -import toMarkdown from "discourse/lib/to-markdown"; +import toMarkdown, { + addBlockDecorateCallback, + addTagDecorateCallback, +} from "discourse/lib/to-markdown"; module("Unit | Utility | to-markdown", function () { test("converts styles between normal words", function (assert) { @@ -458,4 +461,31 @@ test2 ''; assert.strictEqual(toMarkdown(html), "[image]"); }); + + test("addTagDecorateCallback", function (assert) { + const html = `HELLO THERE`; + + addTagDecorateCallback(function (text) { + if (this.element.attributes.class === "loud") { + this.prefix = "^^"; + this.suffix = "^^"; + return text.toLowerCase(); + } + }); + + assert.strictEqual(toMarkdown(html), "^^hello there^^"); + }); + + test("addBlockDecorateCallback", function (assert) { + const html = `