decorateCooked en thème vs HighlightJS

J’utilise decorateCooked dans le thème de mon site pour traiter les blocs de code HighlightJS après coup pour un langage particulier. Cela fonctionne lorsque ``` est utilisé pour indiquer du code dans un message, mais cela échoue lorsque l’indentation est utilisée pour inclure du code.

Dans le cas réussi, les classes HighlightJS sont présentes avant que mon code decorateCooked ne soit invoqué, et je peux utiliser JQuery pour trouver les blocs de code portant ma classe de langage (‘applescript’). Dans le cas qui échoue, il semble que HighlightJS applique ses effets magiques après l’exécution de mon code de plugin, car les classes HighlightJS (hljs applescript) sont absentes. Mais ces classes sont présentes lorsque j’examine ultérieurement la page chargée.

Voici mon code, défini dans la partie </HEAD> de mon thème :

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Ne faire cela que sur 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; // Ne pas faire cela dans les aperçus de l'éditeur
            	}).each(function(index) {
   		            var src = encodeURIComponent(this.innerText);

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

En regardant le journal de la console, je vois que je trouve bien les blocs <code> dans mes messages, mais l’attribut class est signalé comme undefined.

Existe-t-il un moyen de faire en sorte que mon code decorateCooked s’exécute après que HighlightJS ait fait son travail ?

J’ai trouvé une solution de contournement pour ce problème en utilisant MutationObserver, mais je ne suis pas sûr que ce soit la meilleure approche :

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Ne faire cela que sur 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 + '">Ouvrir dans 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; // Ne pas faire cela dans les aperçus de l'éditeur
			}).each(function(index) {
				    var src = encodeURIComponent(this.innerText);

			    $('<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">Ouvrir dans Script Debugger</a>' ).insertAfter($(this).parent());
		    });
		    
		    // Gérer le cas où HighlightJS est appliqué *après* l'appel à decorateCooked. Cela se produit pour
		    // les blocs de code introduits par indentation plutôt que par ```.
                $elem.find('code:not(.applescript,.lang-applescript)').filter(function () {
			            return $(this).parents('.d-editor-preview').length < 1; // Ne pas faire cela dans les aperçus de l'éditeur
			}).each(function () {
                    myObserver.observe(this, obsConfig);
                });
            },
            { id: 'applescript-decorator', onlyStream: true }
        );
    }
</script>

J’ai eu le même problème, j’ai donc ajouté une nouvelle fonctionnalité API pour gérer ce cas d’utilisation : api.registerHighlightJSPlugin.

Vous pouvez lui passer des plugins basés sur des fonctions highlightjs, ce qui est documenté sur Plugin API — highlight.js 11.9.0 documentation