decorateCookedElement für jeden Seitenwechsel?

Ich versuche, die Mediaelement.js-Bibliothek zu verwenden, um den benutzerdefinierten Audio-Onebox zu überschreiben, und es funktioniert, wenn die Seite geladen/aktualisiert wird. Wenn ich jedoch von einem Thema zum anderen navigiere, scheint sie nicht neu geladen zu werden und zeigt stattdessen die native Discourse-Audio-Onebox an.

Beim Laden/Aktualisieren:

Wenn ich dann zu einem anderen Thema navigiere:

Ich bin mir ziemlich sicher, dass ich etwas falsch mache beim Laden von mejs, aber ich dachte, vielleicht nicht und dass ich etwas Besonderes mit onPageChange oder so machen muss.

<html>


let loadScript = require('discourse/lib/load-script').default;

    api.decorateCookedElement(
      element => {
        const audioplayers = element.querySelectorAll('audio');
        // console.log("player: " + audioplayers[0]);
        if (Object.entries(audioplayers).length > 0) {
            // console.log("audioplayers has length");
            loadScript(
                `https://cdnjs.cloudflare.com/ajax/libs/mediaelement/5.0.4/mediaelement.min.js`
            );
            loadScript(
                `https://cdnjs.cloudflare.com/ajax/libs/mediaelement/5.0.4/mediaelement-and-player.min.js`
            );
        }

        audioplayers.forEach(function (el) {
            el.classList.add("mejs__player");
            const controls = settings.theme_uploads.mejs-controls;
            // console.log("controls: " + controls);
            el.setAttribute("data-mejsoptions",
                `{
                    "pluginPath": "https://cdnjs.cloudflare.com/ajax/libs/mediaelement/5.0.4/",
                    "iconSprite": "https://friends.jimkleiber.com/uploads/default/original/1X/a17d9708a19654d9155dd9b79a79a05dea580067.svg",
                    "alwaysShowControls": "true",
                    "features": ["playpause", "current", "progress", "duration", "volume"]
                }`
            );
            el.setAttribute("preload", "auto");            
        });            
      },
      { id: "mediaelement-js", onlyStream: true}
    );

css

@import "https://cdnjs.cloudflare.com/ajax/libs/mediaelement/5.0.4/mediaelementplayer.min.css";

Hat jemand Vorschläge, wie ich es so anpassen könnte, dass es automatisch neu geladen wird, wenn jede Seite geladen wird?

Dieser Beitrag wird etwas lang, da du im #dev-Bereich gepostet hast. Allerdings ist der Inhalt sehr allgemein gehalten und dreht sich mehr darum, die Muster zu erklären, die in Discourse unabhängig von der zu integrierenden Bibliothek oder den anzusteuierenden Post-Elementen verwendet werden sollen. Es fällt nur sozusagen zusammen, dass das von dir gewählte Skript als Hauptbeispiel dient.

MediaElement bietet dir also ein paar Möglichkeiten, einen neuen Audioplayer zu initialisieren:

  1. Du kannst dem Element eine CSS-Klasse und ein paar Attribute hinzufügen, und das Skript kümmert sich dann automatisch darum.

  2. Du initialisierst es manuell.

Derzeit nutzt du Variante 1, also schauen wir uns das einmal genauer an. Wenn ein Skript dir eine „automatische Initialisierung an einem Element

Es sind Momente wie diese, in denen ich mir wünschte, Meta würde Discourse Reactions verwenden, denn ein Herz reicht nicht aus für die Liebe und die reine Dankbarkeit, die ich gerade empfinde.

Ich hatte gehofft, dass mir jemand zumindest einen Tipp geben würde, und doch hast du dir die Zeit genommen, eine sehr gründliche Erklärung zu schreiben, wie ich zu dem Punkt gekommen bin, an dem ich war, und mir gezeigt, wie ich es zum Laufen bringe, und mir dabei viel beigebracht (sogar mit den kleinen Details über Jitter!)

Ich lerne, wie die Struktur von Discourse dazu beitragen kann, ein solches Verhalten zu fördern, indem sie bedeutet, dass, wenn ich es einmal gut beantworte, andere es sehen können und ich es nicht noch einmal beantworten muss – was mich ermutigt, weiterhin Gemeinschaften damit aufzubauen; und doch glaube ich nicht, dass dies vollständig erklärt, warum du das für mich aufgeschrieben hast, und deine Bereitschaft dazu könnte mich ermutigen, diese Plattform noch mehr zu nutzen.

Danke.


Was Mediaelement betrifft, ja, es ist alt, aber es passt gut zu meiner Wordpress-Seite, und ich habe es dort viel angepasst, um dem Benutzer ein vertrautes Aussehen zu bieten (und auch, weil ich im Moment keine weitere Bibliothek lernen möchte :smiley:)

Eine Nachfrage und vielleicht eine dumme Frage: Ich versuche gerade, mehrere Skripte zu laden, da Mediaelement Plugin-Skripte zulässt. Ich möchte sicherstellen, dass alle Skripte geladen werden, bevor das Promise zurückgegeben wird.

Ich habe versucht, dies zu tun, indem ich durch die Konstanten der Skriptquellen iteriere und dann ein Array von Promises erstelle, dann Promise.all() für die Initialisierung der Player verwende, und trotzdem bekomme ich einen Fehler, dass mejs nicht gefunden wird, was meiner Meinung nach der Namespace oder etwas Ähnliches ist, um verschiedene Funktionen innerhalb von mediaelement-and-player aufzurufen.

      let scripts_loaded = [];

      MEDIA_ELEMENT_SCRIPTS.forEach(function (src, index){
          scripts_loaded[index] = loadScript(src);
      });

      Promise.all(scripts_loaded).then(() => {
            audioplayers.forEach(function (el) {
              new MediaElementPlayer(el, MEDIA_ELEMENT_CONFIG);
            });
      });

Wenn ich sie jedoch manuell verknüpfe, scheint es zu funktionieren, wie folgt:

      loadScript(MEDIA_ELEMENT_SRC).then(() => {
          loadScript(MEDIA_ELEMENT_SPEED_SRC).then(() => {
            loadScript(MEDIA_ELEMENT_SKIP_BACK_SRC).then(() => {
                loadScript(MEDIA_ELEMENT_JUMP_FORWARD_SRC).then(() => {
                    audioplayers.forEach(function (el) {
                        new MediaElementPlayer(el, MEDIA_ELEMENT_CONFIG);
                    });
                });
            });
        });
      });

In diesem Fall verwende ich nur eine Handvoll Skripte, daher habe ich sie alle manuell eingegeben. Ich war nur neugierig, ob ich etwas Offensichtliches an der Promise.all()-Funktion übersehe oder ob es eine Discourse-Funktion gibt, mit der ich mehrere Skripte aus einem Array laden kann.

Ihr Code sollte einwandfrei funktionieren. Sie sind gerade auf einen Fehler in Discourse gestoßen.

loadScript() setzt das async-Attribut für die von ihm geladenen Skripte nicht. Daher ist es standardmäßig async="true", was Ihre Ladeordnung durcheinanderbringt. Das ist eine Eigenart des Browsers. Sie müssen async="false" für mit JS geladene Skripte erzwingen.

Plugins sind kleiner, daher laden sie schneller als das Hauptpaket, aber da sie async sind, respektieren sie die Ladeordnung nicht mehr – sie warten, bis das Hauptpaket geladen und ausgeführt wurde, bevor sie selbst ausgeführt werden.

Das ist wahrscheinlich unbemerkt geblieben, weil loadScript meines Wissens nirgendwo im Kern verschachtelt ist. Normalerweise würden Sie Dateien bündeln, die zusammenarbeiten müssen. Um Ihre andere Frage zu beantworten: Nein, es gibt keine Discourse-Funktionen, die diese Art von Dingen handhaben.

Ihr anderer Snippet sollte ebenfalls funktionieren. Um ihn etwas leichter lesbar zu machen, versuchen Sie vielleicht, sie zu verketten, anstatt sie zu verschachteln.

// Dies kommt außerhalb des Decorators
const PLUGINS = {
  speed: "https://example.com/foo.js",
  skipBack: "https://example.com/bar.js",
  jumpForward: "https://example.com/baz.js"
};

// Dann erledigen Sie Ihre Arbeit innerhalb des Decorators
loadScript(MEDIA_ELEMENT_SRC)
  .then(() => loadScript(PLUGINS.speed))
  .then(() => loadScript(PLUGINS.skipBack))
  .then(() => loadScript(PLUGINS.jumpForward))
  .then(() => {
    audioplayers.forEach(function (el) {
      new MediaElementPlayer(el, MEDIA_ELEMENT_CONFIG);
    });
  });

Oh Gott, danke, dass du mir Bescheid gibst!

Ok, klingt gut.

Wow, ich weiß das sehr zu schätzen. Viel, viel sauberer. Nochmals vielen Dank :pray: