decorateCooked 主题与 HighlightJS 对比

我在网站主题中使用 decorateCooked 对 HighlightJS 代码块进行特定语言的后期处理。当使用 ``` 标记代码时,它能正常工作;但当使用缩进方式包含代码时,它会失败。

在成功的情况下,HighlightJS 的类在我调用 decorateCooked 代码之前就已经存在,我可以使用 jQuery 找到带有目标语言类(‘applescript’)的代码块。而在失败的情况下,似乎 HighlightJS 是在我的插件代码运行之后才应用其功能的,因为 HighlightJS 的类(hljs applescript)缺失。不过,当我稍后检查已加载的页面时,这些类又出现了。

以下是我的代码,它定义在主题的 </HEAD> 部分:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // 仅在 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; // 不要在编辑器预览中执行此操作
            	}).each(function(index) {
   		            var src = encodeURIComponent(this.innerText);

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

查看控制台日志,我发现我找到了帖子中的 <code> 块,但 class 属性被报告为 undefined

有没有办法让我的 decorateCooked 代码在 HighlightJS 完成其工作之后运行?

我找到了一个使用 MutationObserver 的变通方案来解决这个问题,但我不确定这是否是最佳方法:

<script type="text/discourse-plugin" version="0.1">
    if (navigator.appVersion.indexOf('Mac') >= 0) { // 仅在 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 + '">在 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; // 不要在编辑器预览中执行此操作
                }).each(function(index) {
                    var src = encodeURIComponent(this.innerText);

                    $('<a class="widget-button btn btn-default" href="sdapplescript://com.apple.scripteditor?action=new&script=' + src + '">在 Script Debugger 中打开</a>').insertAfter($(this).parent());
                });
                
                // 处理 HighlightJS 在 decorateCooked 调用之后才应用的情况。这通常发生在
                // 通过缩进而非 ``` 引入的代码块中。
                $elem.find('code:not(.applescript,.lang-applescript)').filter(function () {
                    return $(this).parents('.d-editor-preview').length < 1; // 不要在编辑器预览中执行此操作
                }).each(function () {
                    myObserver.observe(this, obsConfig);
                });
            },
            { id: 'applescript-decorator', onlyStream: true }
        );
    }
</script>

我遇到了同样的挑战,所以我添加了一个新的 API 功能来处理这种情况:api.registerHighlightJSPlugin

您可以将基于函数的 highlightjs 插件传递给它,相关文档位于 Plugin API — highlight.js 11.9.0 documentation