Riconfezionare un'estensione markdown-it come plugin Discourse

markdown.it il motore CommonMark utilizzato da Discourse ha una vasta gamma di plugin

Ancore per intestazioni, liste di definizioni, frecce intelligenti e l’elenco continua all’infinito.

Prima un avvertimento

:warning: CommonMark è pensato per essere… Comune. Più ti allontani dalla specifica, meno comune sarà il tuo Markdown. Può rendere più difficile la portabilità verso altre soluzioni e, se non si fa attenzione, causare incongruenze interne nell’analisi sintattica. Prima di rielaborare qualsiasi cosa, assicurati di rispondere alla domanda “voglio davvero rielaborare questo?”.

Ho appena finito di rielaborare Discourse Footnote e ho alcune lezioni da condividere su come farlo bene.

Passaggi per i pigri

Se sei pigro e vuoi semplicemente iniziare, il modo più semplice è forcare le note a piè di pagina e scambiare file e nomi di variabili. Sono stato abbastanza attento a garantire che segua le migliori pratiche, quindi dovresti avere un solido esempio.

Mosse di apertura, un riconfezionamento minimo

Da quello che ho capito, la maggior parte dei plugin di markdown.it viene distribuita come file js vanilla. In molti casi, i plugin vengono semplicemente distribuiti come un singolo file js, come questo: markdown-it-mark.js.

Idealmente, vuoi lasciare l’originale intatto, il che significa che puoi semplicemente copiare una versione aggiornata del file nel tuo plugin senza dover armeggiare con il plugin esistente.

Il primo problema che incontrerai è che devi insegnare al tuo plugin a caricare questo JavaScript sul server poiché anche il motore Markdown viene eseguito sul server. Per farlo, puoi semplicemente copiare il file così com’è in assets/javascripts/vendor/original-plugin.js quindi nel tuo file plugin.rb dovresti aggiungere:

# questo insegna al nostro motore markdown a caricare il tuo file js vanilla
register_asset "javascripts/vendor/original-plugin.js", :vendored_pretty_text

Una volta incluso il corpo effettivo del plugin, devi insegnare alla nostra pipeline come caricarlo e inizializzarlo:

Crea un file chiamato assets/javascripts/lib/discourse-markdown/your-extension.js

Questo file verrà caricato automaticamente perché termina con .js E si trova nella directory discourse-markdown.

Un semplice esempio può essere:

export function setup(helper) {
  // questo ti permette di caricare la tua estensione solo se un'impostazione del sito è abilitata
  helper.registerOptions((opts, siteSettings) => {
    opts.features["your-extension"] = !!siteSettings.enable_my_plugin;
  });

  // metti in whitelist qualsiasi attributo che devi supportare,
  // altrimenti il nostro sanificatore li rimuoverà
  helper.whiteList(["div.amazingness"]);

  // puoi anche fare cose fantastiche come questa
  helper.whiteList({
    custom(tag, name, value) {
      if ((tag === "a" || tag === "li") && name === "id") {
        return !!value.match(/^fn(ref)?\d+$/);
      }
    },
  });

  // infine questa è la magia che useresti per registrare l'estensione nel
  // nostro pipeline. whateverGlobal è il nome del globale che il plugin espone
  // prende una singola variabile (md) che viene poi usata per modificare la pipeline
  helper.registerPlugin(window.whateverGlobal);
}

Sii sempre in fase di test

Il bin/rake autospec di Discourse è consapevole dei plugin :innocent:

Ciò significa che quando aggiungi il file spec/pretty_text_spec.rb ogni volta che lo salvi, il file di test del plugin verrà eseguito.

Lo uso ampiamente perché rende il lavoro molto più veloce.

Diciamo che hai aggiunto un plugin che cambia ogni numero in un post in un cerchio 8, puoi chiamarlo discourse-magic-8-ball.

Ecco come strutturerei i test:

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

Potrebbe essere necessario “decorare i post”

In alcuni casi, i plugin funzionano meglio quando aggiungono funzionalità extra “dinamiche” ai tuoi post. Esempi di ciò sono il plugin poll o il plugin footnotes che aggiunge un “…” che mostra dinamicamente un tooltip.

se hai bisogno di “decorare” i post aggiungi assets/javascripts/api-initializers/your-initializer.js

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) => {
    // la tua incredibile magia va qui
  });
});

Potrebbe essere necessario “post-elaborare” i post

In alcuni casi potresti aver bisogno di “post-elaborare” i post, il motore di rendering markdown, per progettazione, non è a conoscenza di alcune informazioni come, ad esempio, post_id. In alcuni casi potresti voler accedere lato server al post e all’HTML “cotto”, questo può permetterti di fare cose come attivare processi in background, sincronizzare campi personalizzati o “correggere” l’HTML generato automaticamente.

Per le note a piè di pagina avevo bisogno di un id distinto per ogni nota a piè di pagina, il che significava che avevo bisogno di accesso a post_id, quindi sono stato costretto a apportare modifiche all’HTML nel post processor (che viene eseguito in sidekiq)

Per agganciarti, aggiungeresti quanto segue al tuo file plugin.rb:

DiscourseEvent.on(:before_post_process_cooked) do |doc, post|
  doc.css("a.always-bing").each do |a|
    # questo dovrebbe sempre andare a bing
    a["href"] = "https://bing.com"
  end
end

Potrebbe essere necessario del CSS personalizzato

Se vuoi distribuire CSS personalizzato, assicurati di registrare il file in plugin.rb

Aggiungi il tuo css a assets/stylesheets/magic.scss e poi esegui

register_asset "stylesheets/magic.scss"

Ricorda che “ricarichiamo automaticamente” le modifiche in modo che tu possa modificare il CSS del tuo plugin e vedere le modifiche al volo durante lo sviluppo.

Buona fortuna con le tue avventure di riconfezionamento :four_leaf_clover:


Questo documento è controllato tramite versione - suggerisci modifiche su github.

29 Mi Piace

Vedo alcuni strumenti superset che estendono Markdown, come Quarkdown che sembra essere molto potente.

Esiste un modo per sostituire l’estensione markdown-it con strumenti come Quarkdown?