How to reinitialize highlight.js?
Asked Answered
E

5

23

My website is generating some content dynamically, so I have to somehow launch the highlight.js plugin again after loading it.

This code is used to launch the highlighter:

hljs.initHighlightingOnLoad();

I tried to do something like hljs.initHighlighting(); to do this again but it does not work.

Embranchment answered 26/10, 2012 at 21:16 Comment(1)
Are you using Turbolinks? Because if you are, I'm pretty sure that's the delimiter. I can't get the two to work together (something to do with the hljs's asynchronousity). Turbolinks is infamous for causing problems and complications.Nanice
L
47

You must set called to false first:

hljs.initHighlighting.called = false;
hljs.initHighlighting();
Loop answered 2/2, 2014 at 12:4 Comment(2)
Isn't this what initHighlightingOnLoad() is for?Nanice
Nice, but this solution has problem it reset highlighted object cursor to 0,0. If you try to invoke on a contenteditable element you fill find yourself writing backward.Gleaning
E
6

You can reinitialize all of the codeblocks like this.

$(document).ready(function() {
   $('pre code').each(function(i, e) {hljs.highlightBlock(e)});
});

or if you have a div with an ID of myBlock, you can do this.

$(document).ready(function() {
   $('#myBlock').each(function(i, e) {hljs.highlightBlock(e)});
});
Existence answered 2/3, 2013 at 17:21 Comment(3)
Does Sergey's answer not apply it for all the blocks?Plutonic
Also there's no reason to believe the questioner is using jQuery, unless I'm missing something?Gujral
Thank you for your answer! I use this in my react application to update the components when the state is changed. it can be called in componentDidUpdate() with the follow code. var blocks = document.querySelectorAll('pre code:not(.hljs)'); Array.prototype.forEach.call(blocks, hljs.highlightBlock);Decipher
N
0

i hope this could solve your problem.. you have to use

hljs.highlightAll()

since, hljs.initHighlightingOnLoad() is deprecated since version 10.6.

if you're using react, you could apply at componentdidMount..

  useEffect(() => {
    hljs.highlightAll()
  }, []);

or, if another framework, please call that function when page loaded. more: https://highlightjs.readthedocs.io/en/latest/api.html

Natation answered 12/3, 2022 at 14:1 Comment(0)
D
0

If you using react hooks please follow this;

I get the solution by integrate react-highlight.

You can use innerHtml to true on the property.

import Highlight from "react-highlight"
import "highlight.js/styles/gradient-dark.css"; // import style on the root file
import JSONViewer from "./JSONViewer"

<Highlight innerHTML className="w-full">
  <JSONViewer content={yourContentHere} />
</Highlight>

Set innerHTML=true to highlight multiple code snippets at a time. This is especially usefull if html with multiple code snippets is generated from preprocesser tools like markdown.

Warning: If innerHTML is set to true, make sure the html generated with code snippets is from trusted source.

Trying to forcing it on useEffect?

Using hljs.registerLanguage("json", json); or hljs.initHighlightingOnLoad(); will getting a problem by rerendering react. It's not recall when using dependency but useEffect without dependency like this it works.

useEffect(() => {
  hljs.initHighlightingOnLoad(); // it works, but bad for performance because will call every single time re-rendering.
})

useEffect(() => {
  hljs.initHighlightingOnLoad(); // it doesn't works
}, [])

Driver answered 8/10, 2023 at 3:43 Comment(1)
Don't you want to re-call it on every render, the one you say is "bad for performance"? With [] as the useEffect dependency array, it seems like freshly rendered <code> elements the component renders won't be highlighted. Better for performance, sure, but also potentially incorrect logic.Polyclitus
P
0

Calling hljs.highlightAll() or hljs.highlightElement(e) multiple times on already-highlighted elements results in an annoying warning:

Element previously highlighted. To highlight again, first unset dataset.highlighted.

hljs.highlightAll();
setTimeout(() => hljs.highlightAll(), 0);
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<pre><code>console.log("hello" + 42);</code></pre>

But unsetting dataset.highlighted doesn't really seem to work, unless I'm missing something, because it doesn't remove the HTML elements hljs added to facilitate its highlighting:

const highlightAll = () => {
  document.querySelectorAll("code").forEach((e) => {
    delete e.dataset.highlighted;
    hljs.highlightElement(e);
  });

  // fails too when used instead of highlightElement:
  // hljs.highlightAll();
};

highlightAll();
setTimeout(highlightAll, 0);
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<pre><code>console.log("hello" + 42);</code></pre>

An approach that circumvents this is to skip highlighting anything that's already highlighted:

const highlightAll = () => {
  document.querySelectorAll("code").forEach((e) => {
    if (!e.dataset.highlighted) {
      hljs.highlightElement(e);
    }
  });
};

highlightAll();
setTimeout(highlightAll, 0);
<link
  rel="stylesheet"
  href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs2015.min.css"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<pre><code>console.log("hello" + 42);</code></pre>

As far as I can tell, if you need to re-highlight rather than skip, you'll need to replace all of the HTML with the original text content before calling hljs.highlightElement(element).

Polyclitus answered 7/6 at 9:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.