@@ -26,46 +26,30 @@ window.addEventListener('DOMContentLoaded', function() {
2626
2727 window . addEventListener ( "hashchange" , highlightHash ) ;
2828
29- const elements = [
30- ...document . getElementsByClassName ( "code-line" ) ,
31- ] ;
32-
33- // Unfortunately a standard document tree walker doesn't work here - it misses quite a lot of nodes.
34- // ¯\_(ツ)_/¯
35-
36- /** @param {Node } el */
37- const getTextNodes = ( el ) => {
38- const nodes = [ ] ;
39-
40- for ( const child of el . childNodes ) {
41- if (
42- child . nodeType == Node . ELEMENT_NODE &&
43- child . classList . contains ( "highlighted" )
44- ) continue ;
45-
46- if ( child . nodeType == Node . TEXT_NODE ) {
47- nodes . push ( child ) ;
48- } else {
49- nodes . push ( ...getTextNodes ( child ) ) ;
50- }
51- }
52-
53- return nodes ;
29+ // We want to apply syntax highlighting. We have two problems.
30+ //
31+ // First, we have annotations that we want to preserve and not highlight.
32+ // So we can't just let highlight.js go to town, we have to be careful.
33+ //
34+ // Second, the natural approach of calling replaceWith() on text nodes
35+ // is extremely slow for large pages like gml_GlobalScript_scr_text,
36+ // locking up the browser for ten seconds or more. Firefox spends >80%
37+ // of its runtime just calling replaceWith().
38+ //
39+ // So we process the HTML manually, as text, and set innerHTML a single
40+ // time at the end. This also lets us use a web worker to highlight
41+ // in the background without blocking the main thread. (You can't send
42+ // DOM nodes to web workers.)
43+ //
44+ // See script-highlighter.js for the gory details.
45+
46+ const table = document . querySelector ( "table.code" ) ;
47+ const worker = new Worker ( "/static/script-highlighter.js" ) ;
48+ /** @param {MessageEvent<string> } event */
49+ worker . onmessage = function ( event ) {
50+ table . innerHTML = event . data ;
51+ highlightHash ( ) ;
52+ worker . terminate ( ) ;
5453 } ;
55-
56- for ( const el of elements ) {
57- // Highlighting has to be done super carefully and manually like this, otherwise
58- // the annotations won't show up and get overwritten by highlight.js.
59-
60- for ( const node of getTextNodes ( el ) ) {
61- if ( node . textContent . trim ( ) == "" ) continue ;
62-
63- const replacement = document . createElement ( "code" ) ;
64-
65- replacement . classList . add ( "highlighted" ) ;
66- replacement . innerHTML = hljs . highlight ( node . textContent , { language : "gml" } ) . value ;
67-
68- node . replaceWith ( replacement ) ;
69- }
70- }
54+ worker . postMessage ( table . innerHTML ) ;
7155} ) ;
0 commit comments