decorateCooked im Theme im Vergleich zu HighlighJS

Ich verwende decorateCooked im Theme meiner Website, um Code-Blöcke von HighlightJS für eine bestimmte Sprache nachzubearbeiten. Es funktioniert, wenn ``` verwendet wird, um Code in einem Beitrag zu kennzeichnen, schlägt jedoch fehl, wenn Einrückungen verwendet werden, um Code einzuschließen.

Im erfolgreichen Fall sind die HighlightJS-Klassen vorhanden, bevor mein decorateCooked-Code ausgeführt wird, und ich kann mit JQuery Code-Blöcke finden, die meine Sprachklasse (‘applescript’) tragen. Im fehlerhaften Fall scheint HighlightJS seine Magie erst nach der Ausführung meines Plugin-Codes anzuwenden, da die HighlightJS-Klassen (hljs applescript) fehlen. Diese Klassen sind jedoch vorhanden, wenn ich die geladene Seite später inspiziere.

Hier ist mein Code, der im <HEAD>-Bereich meines Themes definiert ist:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Nur auf dem Mac ausführen
        api.decorateCooked(
            $elem => {
                console.log($elem.find('code'));
                console.log($elem.find('code').attr('class'));
                $elem.find('.lang-applescript, .applescript').filter(function () {
		            return $(this).parents('.d-editor-preview').length < 1; // Nicht in Editor-Vorschauen ausführen
            	}).each(function(index) {
   		            var src = encodeURIComponent(this.innerText);

        		    $( '<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">In Script Debugger öffnen</a>' ).insertAfter($(this).parent());
        	    });
            },
            { id: 'applescript-decorator' }
        );
    }
</script>

In der Konsolenprotokollausgabe sehe ich, dass ich die <code>-Blöcke in meinen Beiträgen finde, aber das class-Attribut wird als undefined gemeldet.

Gibt es eine Möglichkeit, meinen decorateCooked-Code nach der Ausführung von HighlightJS laufen zu lassen?

Ich habe eine Lösung für dieses Problem mit MutationObserver gefunden, bin mir aber nicht sicher, ob dies der beste Ansatz ist:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Dies nur auf dem Mac ausführen
        if (typeof myObserver == 'undefined') {
            var MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
            var myObserver = new MutationObserver(function (mutations) {
                mutations.forEach(function (mutation) {
                    var target = $(mutation.target);
                    
                    if (target.hasClass('applescript')) {
                        var src = encodeURIComponent(mutation.target.innerText);

                        $('<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">In Script Debugger öffnen</a>').insertAfter(target.parent());
                    }
                });
            });
            var obsConfig = { childList: false, characterData: false, attributes: true, subtree: false };
        }

        api.decorateCooked(
            $elem => {
                $elem.find('.lang-applescript, .applescript').filter(function () {
                    return $(this).parents('.d-editor-preview').length < 1; // Dies nicht in Editor-Vorschauen ausführen
                }).each(function(index) {
                    var src = encodeURIComponent(this.innerText);

                    $('<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">In Script Debugger öffnen</a>').insertAfter($(this).parent());
                });
                
                // Fall abdecken, in dem HighlightJS *nach* dem Aufruf von decorateCooked angewendet wird. Dies tritt bei
                // Codeblöcken auf, die durch Einrückung statt durch ``` eingefügt wurden.
                $elem.find('code:not(.applescript,.lang-applescript)').filter(function () {
                    return $(this).parents('.d-editor-preview').length < 1; // Dies nicht in Editor-Vorschauen ausführen
                }).each(function () {
                    myObserver.observe(this, obsConfig);
                });
            },
            { id: 'applescript-decorator', onlyStream: true }
        );
    }
</script>

Ich hatte gerade die gleiche Herausforderung, also habe ich eine neue API-Funktion hinzugefügt, um diesen Anwendungsfall zu behandeln: api.registerHighlightJSPlugin.

Sie können highlightjs-basierte Plugins übergeben, was unter Plugin API — highlight.js 11.9.0 documentation dokumentiert ist.