markdown.it ist die von Discourse verwendete CommonMark-Engine und verfügt über eine breite Palette von Plugins
Header-Anker, Definitionslisten, Smart-Pfeile und die Liste geht weiter und weiter.
Zuerst eine Warnung
CommonMark soll… Common sein. Je weiter Sie sich von der Spezifikation entfernen, desto weniger Common wird Ihr Markdown. Dies kann den Port zu anderen Lösungen erschweren und, wenn Sie nicht vorsichtig sind, zu internen Inkonsistenzen beim Parsen führen. Bevor Sie etwas neu verpacken, stellen Sie sicher, dass Sie die Frage beantworten: „Möchte ich das wirklich neu verpacken?“
Ich habe gerade Discourse Footnote neu verpackt und habe einige Lektionen darüber zu teilen, wie man dies richtig macht.
Schritte für Faule
Wenn Sie faul sind und einfach nur loslegen möchten, ist der einfachste Weg, Footnotes zu forken und Dateien und Variablennamen auszutauschen. Ich war sehr darauf bedacht, sicherzustellen, dass es Best Practices folgt, sodass Sie ein solides Beispiel haben sollten.
Eröffnungszüge, eine minimale Neuverpackung
Soweit ich das beurteilen kann, werden die meisten markdown.it-Plugins als Vanilla-JS-Dateien ausgeliefert. In vielen Fällen werden Plugins einfach als einzelne JS-Datei ausgeliefert, wie diese: markdown-it-mark.js.
Idealerweise möchten Sie das Original intakt lassen. Das bedeutet, Sie können einfach eine aktualisierte Version der Datei in Ihr Plugin kopieren, ohne sich mit dem vorhandenen Plugin herumschlagen zu müssen.
Das erste Problem, auf das Sie stoßen werden, ist, dass Sie Ihrem Plugin beibringen müssen, dieses JavaScript auf dem Server zu laden, da die Markdown-Engine auch auf dem Server läuft. Dazu können Sie die Datei einfach unverändert in assets/javascripts/vendor/original-plugin.js kopieren. Dann würden Sie in Ihrer plugin.rb-Datei Folgendes hinzufügen:
# dies lehrt unsere Markdown-Engine, Ihre Vanilla-JS-Datei zu laden
register_asset "javascripts/vendor/original-plugin.js", :vendored_pretty_text
Sobald Sie den eigentlichen Inhalt des Plugins eingebunden haben, müssen Sie unserer Pipeline beibringen, wie sie es lädt und initialisiert:
Erstellen Sie eine Datei namens assets/javascripts/lib/discourse-markdown/your-extension.js
Diese Datei wird automatisch geladen, da sie auf .js endet UND sich im Verzeichnis discourse-markdown befindet.
Ein einfaches Beispiel könnte sein:
export function setup(helper) {
// dies ermöglicht es Ihnen, Ihre Erweiterung nur zu laden, wenn eine Site-Einstellung aktiviert ist
helper.registerOptions((opts, siteSettings) => {
opts.features["your-extension"] = !!siteSettings.enable_my_plugin;
});
// Whitelisten Sie alle Attribute, die Sie unterstützen müssen,
// andernfalls entfernt unser Sanitäter sie
helper.whiteList(["div.amazingness"]);
// Sie können auch so etwas Schönes machen
helper.whiteList({
custom(tag, name, value) {
if ((tag === "a" || tag === "li") && name === "id") {
return !!value.match(/^fn(ref)?\d+$/);
}
},
});
// Schließlich ist dies die Magie, die Sie verwenden würden, um die Erweiterung in
// unserer Pipeline zu registrieren. whateverGlobal ist der Name des Globals, das das Plugin bereitstellt
// es nimmt eine einzelne (md) Variable entgegen, die dann verwendet wird, um die Pipeline zu ändern
helper.registerPlugin(window.whateverGlobal);
}
Immer testen
Discourse’s bin/rake autospec ist Plugin-bewusst ![]()
Das bedeutet, dass jedes Mal, wenn Sie die Datei spec/pretty_text_spec.rb hinzufügen und speichern, die Plugin-Testdatei ausgeführt wird.
Ich benutze dies ausgiebig, da es die Arbeit so viel schneller macht.
Angenommen, Sie haben ein Plugin hinzugefügt, das jede Zahl in einem Beitrag in eine 8 verwandelt, Sie können es discourse-magic-8-ball nennen.
So würde ich die Tests strukturieren:
require "rails_helper"
describe PrettyText do
it "can be disabled" do
SiteSetting.enable_magic_8_ball = false
markdown = <<-MD
1 thing
MD
html = <<-HTML
<p>1 thing</p>
HTML
cooked = PrettyText.cook markdown.strip
expect(cooked).to eq(html.strip)
end
it "supports magic 8 ball" do
markdown = <<-MD
1 thing
MD
html = <<-HTML
<p>8 circle thing</p>
HTML
cooked = PrettyText.cook markdown.strip
expect(cooked).to eq(html.strip)
end
end
Möglicherweise müssen Sie Beiträge „dekorieren“
In manchen Fällen funktionieren Plugins am besten, wenn sie Ihren Beiträgen zusätzliche „dynamische“ Funktionen hinzufügen. Beispiele hierfür sind das poll-Plugin oder das footnotes-Plugin, das ein „…“ hinzufügt, das dynamisch einen Tooltip anzeigt.
Wenn Sie Beiträge „dekorieren“ müssen, fügen Sie assets/javascripts/api-initializers/your-initializer.js hinzu
import { apiInitializer } from "discourse/lib/api";
export default apiInitializer((api) => {
const siteSettings = api.container.lookup("service:site-settings");
if (!siteSettings.enable_magic_8_ball) {
return;
}
api.decorateCookedElement((elem) => {
// Ihre erstaunliche Magie kommt hierher
});
});
Möglicherweise müssen Sie die Beiträge „nachbearbeiten“
In manchen Fällen müssen Sie Beiträge „nachbearbeiten“. Die Markdown-Rendering-Engine weiß bauartbedingt nichts von bestimmten Informationen wie zum Beispiel post_id. In manchen Fällen möchten Sie serverseitigen Zugriff auf den Beitrag und den „gekochten“ HTML-Code haben. Dies kann Ihnen Dinge wie das Auslösen von Hintergrundjobs, das Synchronisieren benutzerdefinierter Felder oder das „Korrigieren“ automatisch generierter HTML-Codes ermöglichen.
Für Fußnoten benötigte ich eine eindeutige id für jede Fußnote, was bedeutete, dass ich Zugriff auf die post_id benötigte. Daher war ich gezwungen, Änderungen am HTML im Post-Prozessor (der in sidekiq läuft) vorzunehmen.
Um sich einzuklinken, würden Sie Folgendes zu Ihrer plugin.rb-Datei hinzufügen:
DiscourseEvent.on(:before_post_process_cooked) do |doc, post|
doc.css("a.always-bing").each do |a|
# dies sollte immer zu bing gehen
a["href"] = "https://bing.com"
end
end
Möglicherweise benötigen Sie benutzerdefiniertes CSS
Wenn Sie benutzerdefiniertes CSS versenden möchten, stellen Sie sicher, dass Sie die Datei in plugin.rb registrieren.
Fügen Sie Ihr CSS zu assets/stylesheets/magic.scss hinzu und führen Sie dann
register_asset "stylesheets/magic.scss"
Denken Sie daran, dass wir Änderungen „automatisch neu laden“, sodass Sie Ihr Plugin-CSS ändern und die Änderungen während der Entwicklung sofort sehen können.
Viel Glück bei Ihren Neuverpackungsabenteuern ![]()
Dieses Dokument wird versioniert – schlagen Sie Änderungen auf github vor.