decorateCooked in tema vs HighlightJS

Sto usando decorateCooked nel tema del mio sito per post-elaborare i blocchi di codice HighlightJS per un linguaggio specifico. Funziona quando si usano i ``` per indicare il codice in un post, ma fallisce quando si usa l’indentazione per includere il codice.

Nel caso di successo, le classi di HighlightJS sono presenti prima che venga invocato il mio codice decorateCooked, quindi posso usare jQuery per trovare i blocchi di codice che contengono la mia classe (‘applescript’). Nel caso fallito, sembra che HighlightJS applichi la sua magia dopo l’esecuzione del mio codice plugin, perché le classi di HighlightJS (hljs applescript) sono assenti. Tuttavia, queste classi sono presenti quando ispeziono successivamente la pagina caricata.

Ecco il mio codice, definito nella sezione </HEAD> del mio tema:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Esegui solo su Mac
        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; // Non farlo nelle anteprime dell'editor
            	}).each(function(index) {
   		            var src = encodeURIComponent(this.innerText);

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

Dall’output del log della console, vedo che riesco a trovare i blocchi <code> nei miei post, ma l’attributo class viene riportato come undefined.

Esiste un modo per far eseguire il mio codice decorateCooked dopo che HighlightJS ha completato il suo lavoro?

Ho trovato una soluzione alternativa per questo problema utilizzando MutationObserver, ma non sono sicuro che sia l’approccio migliore:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Esegui solo su Mac
        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 + '">Apri in Script Debugger</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; // Non eseguire nelle anteprime dell'editor
                }).each(function(index) {
                    var src = encodeURIComponent(this.innerText);

                    $('<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">Apri in Script Debugger</a>').insertAfter($(this).parent());
                });
                
                // Gestisci il caso in cui HighlightJS viene applicato *dopo* l'esecuzione di decorateCooked. Questo accade per
                // i blocchi di codice inseriti tramite indentazione invece che con ```.                $elem.find('code:not(.applescript,.lang-applescript)').filter(function () {
                    return $(this).parents('.d-editor-preview').length < 1; // Non eseguire nelle anteprime dell'editor
                }).each(function () {
                    myObserver.observe(this, obsConfig);
                });
            },
            { id: 'applescript-decorator', onlyStream: true }
        );
    }
</script>

Ho appena avuto la stessa sfida, quindi ho aggiunto una nuova funzionalità API per gestire questo caso d’uso: api.registerHighlightJSPlugin.

Puoi passarle plugin basati su funzioni highlightjs, come documentato su Plugin API — highlight.js 11.9.0 documentation