decorateCooked in theme vs HighlighJS

I’m using decorateCooked in my site’s theme to post-process HighlightJS code blocks for a particular language. It is working when ``` is used to indicate code in a post but It is failing when indentation is used to include code.

In the successful case the HighligtJS classes are present before my decorateCooked code is invoked and I can use JQuery to find code blocks carrying my language class (‘applescript’). In the failing case, it appears that HighlightJS is applying its magic after my plugin code runs because the HighlighJS classes (hljs applescript) are missing. But these classes are present when I later inspect the loaded page.

Here’s my code which is defined in the </HEAD> portion of my theme:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Only do this on the 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; // Don't do this in editor previews
            	}).each(function(index) {
   		            var src = encodeURIComponent(this.innerText);

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

Looking at the console log, I see that I’m finding the <code> blocks in my posts, but the class attribute is reported as undefined.

Is there a way of having my decorateCooked code run after HighlightJS has done its thing?

I’ve found a workaround for this problem using MutationObserver but I’m not sure this is the best approach to the problem:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // Only do this on the 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 + '">Open 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; // Don't do this in editor previews
            	}).each(function(index) {
   		            var src = encodeURIComponent(this.innerText);

        		    $('<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">Open in Script Debugger</a>' ).insertAfter($(this).parent());
        	    });
        	    
        	    //  Deal with the case where HighlightJS is applied *after* decorateCooked is called.  This happens for
        	    //  code blocks introduced using indentation rather than ```.
                $elem.find('code:not(.applescript,.lang-applescript)').filter(function () {
		            return $(this).parents('.d-editor-preview').length < 1; // Don't do this in editor previews
            	}).each(function () {
                    myObserver.observe(this, obsConfig);
                });
            },
            { id: 'applescript-decorator', onlyStream: true }
        );
    }
</script>

저도 같은 문제를 겪고 있어, 이 사용 사례를 처리하기 위해 api.registerHighlightJSPlugin이라는 새로운 API 기능을 추가했습니다.

이 기능에는 highlightjs 함수 기반 플러그인을 전달할 수 있으며, 관련 문서는 Plugin API — highlight.js 11.9.0 documentation 확인하실 수 있습니다.