I wanted to integrate
Alex Gorbatchev's SyntaxHighlihter to a blog article on
Blogger. There is a
multitude of instructions available but all of them have one thing in common:
modification of the blog page template to include all necessary scripts and stylesheets. It will enable the syntax highlighter on every page but also make every page always load it.
Well, if you don't use a code excerpt in every post, why should your every page load the syntax highlighting engine? It should be possible to enable it just for a particular post, shouldn't it?
Yes, it is possible - with an additional JavaScript code in your blog post. If you are familiar with the
usual blog template modification the following idea adds just
inserting stylesheets and scripts to the page head on-demand. When you're writing a blog article with some source code you'll enter the HTML editing mode, create a
<script type="text/javascript">...</script>
element in and put the following code to its body: (a double-click within the code will select it all to enable putting it to clipboard easily)
(function() {
function loadCss(url){
var head = document.getElementsByTagName("head")[0]
var styles = head.getElementsByTagName("link")
for (var i = 0; i < styles.length; ++i)
if (styles[i].href.indexOf(url) >= 0)
return
var style = document.createElement("link")
style.rel = "stylesheet"
style.type = "text/css"
style.href = url
head.appendChild(style)
}
function loadJs(url, after){
var head = document.getElementsByTagName("head")[0]
var scripts = head.getElementsByTagName("script")
var script
for (var i = 0; i < scripts.length; ++i) {
var current = scripts[i]
if (current.src.indexOf(url) >= 0) {
script = current
break
}
}
if (!script) {
script = document.createElement('script')
script.type = "text/javascript"
}
if (after)
if (script.readyState)
if (script.readyState == "loaded" ||
script.readyState == "complete") {
after()
} else {
var oldreadystatechange = script.onreadystatechange
script.onreadystatechange = function() {
if (script.readyState == "loaded" ||
script.readyState == "complete")
after()
if (oldreadystatechange)
oldreadystatechange()
}
}
else {
if (script.getAttribute("data-loaded")) {
after()
} else {
script.async = false
var oldload = script.onload
script.onload = function() {
script.setAttribute("data-loaded", "true")
after()
if (oldload)
oldload()
}
}
}
if (!script.src) {
script.src = url
head.appendChild(script)
}
}
function highlight(tags) {
SyntaxHighlighter.config.bloggerMode = true
for (var i = 0; i < tags.length; ++i) {
var tag = document.getElementById(tags[i])
SyntaxHighlighter.highlight(undefined, tag)
}
}
// Use a public hosting site of your choice instead of "...".
loadCss(".../shCore.css")
loadCss(".../shThemeDefault.css")
loadJs(".../shCore.js", function() {
// Add other brushes to this chain as necessary.
loadJs(".../shBrushJScript.js", function() {
// List IDs of elements to highlight their content.
highlight([ "js-sample1", "js-sample2" ])
})
})
}());
Notice the three comments above - those places you are supposed to modify according to your blog article.
1. The stylesheets and scripts must be
loaded from a publicly accessible URL. You can use
Alex's hosting but if you have a possibility to put the files onto your site you should prefer it; the bandwith of Alex's site is not unlimited... For example, if you have your pages on
Google Sites, which may be likely because both Blogger and Sites are provided by Google, you can upload the SyntaxHighlighter support there and refer to them from the script, for example:
https://sites.google.com/site/your_name/css/shCore.css
https://sites.google.com/site/your_name/css/shThemeDefault.css
https://sites.google.com/site/your_name/js/shCore.js
https://sites.google.com/site/your_name/js/shBrushJScript.js
2. If you need multiple languages (brushes) in your article you'll
load them in a chain of calls one after another. The following script is loaded first when the previous one has been finished; it would be done so anyway by the browser but it allows essentially the last expression that starts the highlighting to be executed after all scripts were processed: (see the latest list of
built-in brushes and also
additional ones)
loadJs(".../shCore.js", function() { // Common
loadJs(".../shBrushJScript.js", function() { // JavaScript
loadJs(".../shBrushCss.js", function() { // CSS
// Highlight the code; all brushes are loaded now.
highlight([ "js-sample1", "js-sample2" ])
})
})
})
3. When placing a code excerpt to the article, in addition to the usual attributes, you'll give the pre
element a unique ID that you include in the array of element IDs sent to the function highlight
as shown above:
<pre class="brush: js;" id="js-sample1">
...
</pre>
When writing HTML or XML samples, an
on-line HTML encoder may help you to escape special characters. (The brush for HTML is the shBrushXml.js, btw.) You can consider minifying the JavaScript code above and the external scripts you include by the
Google Closure Compiler or a similar tool. There are tools for minifying CSS files too, even
on-line. For example, this is the partially minified code I've used for my articles:
(function() {
function loadCss(d){for(var b=document.getElementsByTagName("head")[0],c=b.getElementsByTagName("link"),e=0;e<c.length;++e)if(0<=c[e].href.indexOf(d))return;c=document.createElement("link");c.rel="stylesheet";c.type="text/css";c.href=d;b.appendChild(c)}
function loadJs(d,b){for(var c=document.getElementsByTagName("head")[0],e=c.getElementsByTagName("script"),a,f=0;f<e.length;++f){var g=e[f];if(0<=g.src.indexOf(d)){a=g;break}}if(!a)a=document.createElement("script"),a.type="text/javascript";if(b)if(a.readyState)if("loaded"==a.readyState||"complete"==a.readyState)b();else{var h=a.onreadystatechange;a.onreadystatechange=function(){("loaded"==a.readyState||"complete"==a.readyState)&&b();h&&h()}}else if(a.getAttribute("data-loaded"))b();else{a.async=
!1;var i=a.onload;a.onload=function(){a.setAttribute("data-loaded","true");b();i&&i()}}if(!a.src)a.src=d,c.appendChild(a)}function highlight(d){SyntaxHighlighter.config.bloggerMode=!0;for(var b=0;b<d.length;++b){var c=document.getElementById(d[b]);SyntaxHighlighter.highlight(void 0,c)}};
loadCss("https://sites.google.com/site/your_name/styles/shCore.min.css")
loadCss("https://sites.google.com/site/your_name/styles/shThemeVisualStudioLike.min.css")
loadJs("https://sites.google.com/site/your_name/scripts/shCore.min.js", function() {
loadJs("https://sites.google.com/site/your_name/scripts/shBrushJScript.min.js", function() {
loadJs("https://sites.google.com/site/your_name/scripts/shBrushXml.min.js", function() {
highlight(["js-sh-loader", "js-sh-chain", "html-sh-sample", "js-sh-real"])
})
})
})
}());
Loading the syntax highlighting support only for articles that actually need it takes a little more care than having it loaded on all pages automatically, indeed. But you'll have your readers download less data and make fewer HTTP requests when browsing your regular pages. And when you replace you blog template with another one you won't need bother editing it to include your modifications; your blog articles will be encapsulated with all extras they need to be rendered.
Enjoy!