Skip to content

Commit a2a1924

Browse files
vanshika2720Vanshika
andauthored
Fix highlighter not loading in JS editor (#5335)
* Fix highlighter not loading in JS editor The issue occurred because hljs.highlightElement was being called before the highlight.js library finished loading. Since the script is loaded with the defer attribute, it may not be available when the JS editor widget opens. Added a check to verify that window.hljs exists and highlightElement is available before attempting to use it. This prevents the TypeError and allows the editor to work even if syntax highlighting hasn't loaded yet. * Enhance JS Editor highlight.js compatibility and async loading This commit improves the JS editor's syntax highlighting to address issues with highlight.js loading asynchronously and version compatibility. Key improvements: 1. Backward compatibility: Added fallback to highlightBlock() API for older highlight.js versions (v9-10) while maintaining support for the modern highlightElement() API (v11+) 2. Async loading handling: Implemented a retry mechanism that detects when highlight.js hasn't loaded yet and automatically re-applies highlighting once it becomes available (100ms retry interval) 3. Error resilience: Wrapped highlighting logic in try-catch to prevent editor crashes from highlighting errors, with console warnings for debugging 4. Independent error highlighting: Ensured syntax error highlighting works independently of highlight.js availability 5. Code quality: Applied ESLint auto-fixes for consistent formatting This ensures the JS editor works reliably across different highlight.js versions and loading scenarios, with syntax highlighting enabled once the library loads, without blocking editor functionality. Fixes #5334 * Fix Prettier formatting issues in jseditor.js * Improve highlight.js async loading with exponential backoff retry logic * Refactor highlighter retry logic to use closure variable and exponential backoff * Enhance hljs async loading with interval-based monitoring - Replace limited retry mechanism with persistent interval checking - Ensure syntax highlighting activates once hljs loads - Add proper cleanup to prevent memory leaks - Maintain support for both hljs v9-10 and v11+ APIs - Fix issue where highlighting wouldn't enable if hljs loaded late * Fix Prettier formatting issues * Fix syntax highlighting initialization in JS Editor - Add proper hljs availability check before highlighting - Ensure highlightElement is called only when hljs is fully loaded - Prevents 'hljs.highlightElement is not a function' error - Syntax highlighting now works reliably when hljs loads asynchronously Fixes #5335 * Fix Prettier formatting in jseditor.js * Use local highlight.pack.js instead of CDN for JS Editor - Switch from CDN highlight.js to local lib/codejar/highlight.pack.js - Fixes syntax highlighting not loading in JS Editor - As suggested by maintainer @walterbender Fixes #5335 --------- Co-authored-by: Vanshika <vanshika@198625@gmail.com>
1 parent e120bbb commit a2a1924

File tree

2 files changed

+86
-66
lines changed

2 files changed

+86
-66
lines changed

index.html

Lines changed: 62 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
<script src="lib/wheelnav.js" defer></script>
5353
<script src="lib/abc.min.js" defer></script>
5454
<script src="lib/codejar/codejar.min.js" defer></script>
55-
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js" defer></script>
55+
<script src="lib/codejar/highlight.pack.js" defer></script>
5656
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/atom-one-dark.min.css">
5757

5858
<!-- libgif.js (SuperGif) provides low-level GIF frame extraction.
@@ -101,7 +101,8 @@
101101
<div id="loading-image-container"
102102
style="position: fixed; top: 0; left: 0; width: 100%; height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; background-color: #FFFFFF; z-index: 9999; contain: paint;">
103103
<div id="loading-media" style="width: 100%; padding: 0 20px; box-sizing: border-box;"></div>
104-
<div class="loading-text" id="loadingText" style="color:#333; margin-top: 2rem; min-height: 1.5em; font-size: 1.2rem;">
104+
<div class="loading-text" id="loadingText"
105+
style="color:#333; margin-top: 2rem; min-height: 1.5em; font-size: 1.2rem;">
105106
</div>
106107
<a href="https://www.sugarlabs.org/" target="_blank" id="link-to-sugarLabs"
107108
style="position: fixed; bottom: 20px; right: 20px;">
@@ -226,7 +227,8 @@
226227
<div id="helpElem" tabindex="-1"></div>
227228

228229
<div id="wheelDiv" class="wheelNav"
229-
style=" display: none; background-size: contain;background-image: url(./images/gray.svg)" tabindex="-1"></div>
230+
style=" display: none; background-size: contain;background-image: url(./images/gray.svg)"
231+
tabindex="-1"></div>
230232

231233
<div id="wheelDiv2" class="wheelNav"
232234
style="display: none; background-size: contain;background-image: url(./images/gray.svg);visibility: hidden"
@@ -282,7 +284,7 @@
282284
</dialog>
283285
<div class="materialize-iso" tabindex="-1">
284286
<nav id="toolbars" class="nav-wrapper">
285-
<div class="blue nav-wrapper" tabindex="-1">
287+
<div class="blue nav-wrapper" tabindex="-1">
286288
<div id="mb-logo" class="logo left tooltipped"
287289
style="display: flex; align-items: center; line-height: 0; height: 100%; padding-right: 0;"
288290
data-position="bottom">
@@ -298,80 +300,81 @@
298300
<a id="stop" class="left tooltipped"><i class="material-icons main">stop</i></a>
299301
</li>
300302
<li>
301-
<a id="record" class="left tooltipped" data-tooltip="Record"></a>
303+
<a id="record" class="left tooltipped" data-tooltip="Record"></a>
302304
</li>
303305
</ul>
304306

305307
<ul class="main right">
306308
<li>
307309
<a id="FullScreen" class="FullScreen tooltipped dropdown-trigger" data-position="bottom"
308-
onclick="setIcon()">
309-
<i class="material-icons" id="FullScrIcon">fullscreen</i>
310-
</a>
310+
onclick="setIcon()">
311+
<i class="material-icons" id="FullScrIcon">fullscreen</i>
312+
</a>
311313
</li>
312314
<li>
313315
<a id="newFile" class="tooltipped dropdown-trigger" data-position="bottom"
314-
data-activates="newdropdown">
315-
<i class="material-icons md-48">note_add</i>
316-
</a>
316+
data-activates="newdropdown">
317+
<i class="material-icons md-48">note_add</i>
318+
</a>
317319
</li>
318320
<li>
319-
<a id="load" class="tooltipped" data-position="bottom">
320-
<i class="material-icons md-48">folder</i>
321-
</a>
321+
<a id="load" class="tooltipped" data-position="bottom">
322+
<i class="material-icons md-48">folder</i>
323+
</a>
322324
</li>
323325
<li>
324-
<a id="saveButton" class="tooltipped dropdown-trigger" data-position="bottom"
325-
data-activates="saveddropdownbeg">
326-
<i id="save1" class="material-icons md-48">save_alt</i>
327-
</a>
326+
<a id="saveButton" class="tooltipped dropdown-trigger" data-position="bottom"
327+
data-activates="saveddropdownbeg">
328+
<i id="save1" class="material-icons md-48">save_alt</i>
329+
</a>
328330
</li>
329331
<li>
330-
<a id="saveButtonAdvanced" style="display: none;" class="tooltipped dropdown-trigger"
331-
data-position="bottom" data-activates="saveddropdown">
332-
<i id="save2" class="material-icons md-48">save_alt</i>
333-
</a>
332+
<a id="saveButtonAdvanced" style="display: none;" class="tooltipped dropdown-trigger"
333+
data-position="bottom" data-activates="saveddropdown">
334+
<i id="save2" class="material-icons md-48">save_alt</i>
335+
</a>
334336
</li>
335337
<li>
336-
<a id="planetIcon" class="tooltipped" data-position="bottom">
337-
<i class="material-icons md-48">public</i>
338-
</a>
338+
<a id="planetIcon" class="tooltipped" data-position="bottom">
339+
<i class="material-icons md-48">public</i>
340+
</a>
339341
</li>
340342
<li>
341-
<a style="display: none;" id="planetIconDisabled" class="tooltipped" data-position="bottom">
342-
<i style="color: #a5acba;" class="material-icons md-48">public</i>
343-
</a>
343+
<a style="display: none;" id="planetIconDisabled" class="tooltipped"
344+
data-position="bottom">
345+
<i style="color: #a5acba;" class="material-icons md-48">public</i>
346+
</a>
344347
</li>
345348
<li>
346-
<a id="toggleAuxBtn" class="tooltipped" data-position="bottom">
347-
<i id="menu" class="animated-icon material-icons md-48">menu</i>
348-
</a>
349+
<a id="toggleAuxBtn" class="tooltipped" data-position="bottom">
350+
<i id="menu" class="animated-icon material-icons md-48">menu</i>
351+
</a>
349352
</li>
350353
<li>
351-
<a id="helpIcon" class="tooltipped" data-position="bottom">
352-
<i class="material-icons md-48">help</i>
353-
</a>
354+
<a id="helpIcon" class="tooltipped" data-position="bottom">
355+
<i class="material-icons md-48">help</i>
356+
</a>
354357
</li>
355358
</ul>
356359
</div>
357360
<div class="nav-wrapper" id="aux-toolbar" style="display: none;" tabindex="-1">
358361
<div class="blue darken-1 nav-wrapper" tabindex="-1">
359362
<ul class="aux left">
360363
<li>
361-
<a id="runSlowlyIcon" class="tooltipped" data-position="bottom" data-delay="10">
362-
<i class="material-icons md-48">play_circle_outline</i>
363-
</a>
364+
<a id="runSlowlyIcon" class="tooltipped" data-position="bottom" data-delay="10">
365+
<i class="material-icons md-48">play_circle_outline</i>
366+
</a>
364367
</li>
365368
<li>
366-
<a id="runStepByStepIcon" class="tooltipped" data-position="bottom" data-delay="10">
367-
<i class="material-icons md-48">video_library</i>
368-
</a>
369+
<a id="runStepByStepIcon" class="tooltipped" data-position="bottom" data-delay="10">
370+
<i class="material-icons md-48">video_library</i>
371+
</a>
369372
</li>
370373
</ul>
371374
<ul class="aux right">
372375
<li>
373-
<a id="displayStatsIcon" class="tooltipped" data-position="bottom" data-delay="10"><i
374-
class="material-icons md-48">poll</i></a>
376+
<a id="displayStatsIcon" class="tooltipped" data-position="bottom"
377+
data-delay="10"><i class="material-icons md-48">poll</i></a>
375378
</li>
376379
<li>
377380
<a id="loadPluginIcon" class="tooltipped" data-position="bottom" data-delay="10"><i
@@ -416,7 +419,8 @@
416419
</li>
417420

418421
<li>
419-
<a id="restoreIcon" class="tooltipped" data-position="bottom" data-tooltip="Restore"><i
422+
<a id="restoreIcon" class="tooltipped" data-position="bottom"
423+
data-tooltip="Restore"><i
420424
class="material-icons md-48">restore_from_trash</i></a>
421425
<div id="trashList"></div>
422426
</li>
@@ -429,9 +433,9 @@
429433
class="material-icons md-48">star_border</i></a>
430434
</li>
431435
<li>
432-
<a id="languageSelectIcon" class="tooltipped dropdown-trigger" data-position="bottom"
433-
data-activates="languagedropdown" data-tooltip="Select Language"><i
434-
class="material-icons md-48">translate</i></a>
436+
<a id="languageSelectIcon" class="tooltipped dropdown-trigger"
437+
data-position="bottom" data-activates="languagedropdown"
438+
data-tooltip="Select Language"><i class="material-icons md-48">translate</i></a>
435439
</li>
436440
</ul>
437441
</div>
@@ -504,15 +508,15 @@
504508

505509
<!-- Initialize Scripts -->
506510
<script>
507-
let canvas, stage;
508-
function init() {
509-
canvas = document.getElementById("canvas");
510-
stage = new createjs.Stage(canvas);
511-
512-
createjs.Ticker.framerate = 60;
513-
createjs.Ticker.addEventListener("tick", stage);
514-
}
515-
document.addEventListener("DOMContentLoaded", init);
511+
let canvas, stage;
512+
function init() {
513+
canvas = document.getElementById("canvas");
514+
stage = new createjs.Stage(canvas);
515+
516+
createjs.Ticker.framerate = 60;
517+
createjs.Ticker.addEventListener("tick", stage);
518+
}
519+
document.addEventListener("DOMContentLoaded", init);
516520
</script>
517521

518522
<script>
@@ -574,8 +578,8 @@
574578
}
575579

576580
const container = document.getElementById("loading-media");
577-
const content = lang.startsWith("ja")
578-
? `<img src="loading-animation-ja.svg" loading="eager" fetchpriority="high" style="width: 70%; height: 90%; object-fit: contain;" alt="Loading animation">`
581+
const content = lang.startsWith("ja")
582+
? `<img src="loading-animation-ja.svg" loading="eager" fetchpriority="high" style="width: 70%; height: 90%; object-fit: contain;" alt="Loading animation">`
579583
: `<video loop autoplay muted playsinline fetchpriority="high" style="width: 90%; height: 100%; object-fit: contain;">
580584
<source src="loading-animation.webm" type="video/webm">
581585
<source src="loading-animation.mp4" type="video/mp4">
@@ -824,4 +828,4 @@
824828

825829
</body>
826830

827-
</html>
831+
</html>

js/widgets/jseditor.js

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -550,15 +550,31 @@ class JSEditor {
550550
this._editor.appendChild(editorconsole);
551551

552552
const highlight = editor => {
553-
// Configure highlight.js for JavaScript
554-
hljs.configure({
555-
languages: ["javascript"]
556-
});
557-
558-
// Apply highlight.js syntax highlighting for JavaScript
559-
hljs.highlightElement(editor);
553+
// Apply syntax highlighting if highlight.js is available
554+
if (window.hljs) {
555+
try {
556+
// Remove any existing highlighting classes to ensure clean re-highlighting
557+
editor.removeAttribute("data-highlighted");
558+
559+
// Configure highlight.js for JavaScript
560+
hljs.configure({
561+
languages: ["javascript"]
562+
});
563+
564+
// Try modern API first (v11+), fallback to legacy API (v9-10)
565+
if (typeof hljs.highlightElement === "function") {
566+
hljs.highlightElement(editor);
567+
} else if (typeof hljs.highlightBlock === "function") {
568+
// Legacy API for older highlight.js versions
569+
hljs.highlightBlock(editor);
570+
}
571+
} catch (e) {
572+
// Silently handle highlighting errors to prevent editor crashes
573+
console.warn("Syntax highlighting failed:", e);
574+
}
575+
}
560576

561-
// Add error highlighting
577+
// Always add error highlighting (works independently of hljs)
562578
this._highlightErrors(editor);
563579
};
564580

0 commit comments

Comments
 (0)