I have this fiddle. I am trying to format some code and am having trouble inserting and removing line numbers dynamically. It seems on the first page load the line numbers appear but once I click run then I can't get them back. On my website they don't show at all. I would like to let users click a button and turn on/off the line numbers dynamically:
<body>
<pre id="pre">
<script type="text/javascript">
// Say hello world until the user starts questioning
// the meaningfulness of their existence.
function helloWorld(world) {
for (var i = 42; --i >= 0;) {
alert('Hello ' + String(world));
}
}
</script>
<style>
p { color: pink }
b { color: blue }
u { color: "umber" }
</style>
</pre>
<button id="button">My button</button>
</body>
$(document).ready(function(){
$("#button").on("click", function(){
$("#pre").addClass("prettyprint").addClass("linenums").addClass("lang-js");
$("#pre").html(PR.prettyPrintOne($("#pre").html()));
});
});
Thanks!
EDIT: Note that this is different than How to add line numbers to all lines in Google Prettify?. In mine, the line numbers show up at first if I add linenums
class to the pre
tag manually. Problem is turning them on/off with jquery doesn't work.
By calling prettyPrintOne
you're essentially circumventing the class based initialisation. That method has arguments that tell prettify how to behave.
You're trying to modify how prettify behaves with classes but prettify ignores that because it only cares about the arguments which are null, therefore they fallback to internal defaults.
See the source documenting the method:
/**
* Pretty print a chunk of code.
* @param {string} sourceCodeHtml The HTML to pretty print.
* @param {string} opt_langExtension The language name to use.
* Typically, a filename extension like 'cpp' or 'java'.
* @param {number|boolean} opt_numberLines True to number lines,
* or the 1-indexed number of the first line in sourceCodeHtml.
* @return {string} code as html, but prettier
*/
prettyPrintOne
is essentially for parsing some code passed to it as a string, and returning the result, with the options controlled by those arguments. Conversely prettyPrint
will traverse the DOM looking for the classes you're adding, behaving according to the classes it finds. As you want to toggle, you'll want to keep using prettyPrintOne
so that we can have control of when to show prettified output, and when to show the original - more on that later.
As an aside, you're telling prettify to format JS when what you've got there is HTML including JS in script tags and CSS in style tags. So you'll want to use HTML as the lang extension, not JS.
Anyway, all you need to do is adjust your call to the below, additionally adding the prettify
class solely so your prettify theme CSS applies:
$("#pre").html( PR.prettyPrintOne($("#pre").html(), "html", true) )
.addClass("prettyprint");
Et voila:
As for toggling, you just need to adjust the logic so that you store the original HTML somewhere on prettify-ing and restore it next time the button is clicked:
$("#button").on("click", function() {
// Cache jquery object
var $pre = $("#pre");
// If the element has a prettyprint class, it's already been manually
// prettified
if (!$pre.hasClass("prettyprint")) {
// Element hasn't been prettified, store the html in jQuery data
$pre.data("original-html", $pre.html());
// Manually prettify
$pre.html(PR.prettyPrintOne($pre.html(), "html", true))
.addClass("prettyprint");
} else {
// Element has been prettified, restore the orginal html stored in jQuery
// data and remove the prettyprint class, back to where we started
$pre.html($pre.data("original-html"))
.removeClass("prettyprint");
// Remove the jQuery data entry for our original HTML, so next time we
// start fresh
$pre.data("original-html", null);
}
});
Here's a jsfiddle showing that in action: https://jsfiddle.net/joshdavenport/68thqus1/27/