Browse Source
Achieved using Prism.js (MIT licensed) library and its language addons. Website: http://prismjs.com/master
3 changed files with 159 additions and 0 deletions
@ -0,0 +1,157 @@
@@ -0,0 +1,157 @@
|
||||
/** |
||||
* Highlight Module |
||||
* |
||||
* |
||||
* High Level API: |
||||
* |
||||
* // Load basic dependencies and language support for present code tags
|
||||
* |
||||
* highlight.init() |
||||
* |
||||
* |
||||
* // Function that loads additional languages support
|
||||
* // Useful when markdown has been parsed again
|
||||
* // and new language occurred in the output for example
|
||||
* |
||||
* highlight.update(); |
||||
* |
||||
* |
||||
* Hooks To: |
||||
* |
||||
* 'document:loaded' ~> highlight.init(); |
||||
* 'content:rendered' ~> highlight.update(); |
||||
* |
||||
*/ |
||||
(function (global) { |
||||
|
||||
// Simplified debounce version (no args support)
|
||||
function debounce(callback, milliseconds) { |
||||
var timeout; |
||||
|
||||
return function () { |
||||
clearTimeout(timeout); |
||||
|
||||
timeout = setTimeout(function () { |
||||
callback(); |
||||
}, milliseconds); |
||||
}; |
||||
} |
||||
|
||||
// Converts arguments-like / querySelector results data to a simple array
|
||||
function toArray(data) { |
||||
return [].slice.call(data); |
||||
} |
||||
|
||||
// Highlight callback
|
||||
function highlight() { |
||||
if (!('Prism' in global)) { |
||||
throw new Error( |
||||
'[Highlight] Prism not detected. Please run `highlight.init` to load all dependencies' |
||||
); |
||||
} |
||||
|
||||
global.Prism.highlightAll(); |
||||
} |
||||
|
||||
// Debounced highlight callback
|
||||
var debouncedHighlight = debounce(highlight, 300); |
||||
|
||||
// Collect a list of unique langages to be highlighted
|
||||
function collectLanguages() { |
||||
return [] |
||||
.concat(toArray(document.querySelectorAll('code[class*="lang-"]'))) |
||||
.concat(toArray(document.querySelectorAll('code[class*="language-"]'))) |
||||
.map(function (element) { |
||||
// Collect languages from code elements, e.g. `lang-css`, `language-javascript`
|
||||
// and then remove `lang-` and `language-` parts
|
||||
return (element.className.match(/lang(uage)?\-\w+/g) || []) |
||||
.map(function (languageClass) { |
||||
return languageClass.replace(/lang(uage)?\-/g, '').trim(); |
||||
}) |
||||
.map(function (language) { |
||||
// Common language abbreviations mapped to full language names
|
||||
var mappings = { |
||||
js: 'javascript', |
||||
}; |
||||
|
||||
return mappings[language] || language; |
||||
}); |
||||
}) |
||||
.reduce(function (uniqueLanguages, elementLanguages) { |
||||
elementLanguages.forEach(function (language) { |
||||
// Add language to the pool if not detected already
|
||||
if (uniqueLanguages.indexOf(language) === -1) { |
||||
uniqueLanguages.push(language); |
||||
} |
||||
}); |
||||
|
||||
return uniqueLanguages; |
||||
}, []); |
||||
} |
||||
|
||||
// Load scripts for additional languages support
|
||||
function loadAdditionalLanguageSupport() { |
||||
collectLanguages() |
||||
.forEach(function (language) { |
||||
var resource = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/components/prism-%s.min.js' |
||||
.replace('%s', language); |
||||
|
||||
// Escape early if language support is already loaded
|
||||
if (document.querySelector('script[src="' + resource + '"]')) { |
||||
debouncedHighlight(); |
||||
return; |
||||
} |
||||
|
||||
// Load language support file otherwise
|
||||
var script = document.createElement('script'); |
||||
|
||||
script.src = resource; |
||||
|
||||
script.addEventListener('load', debouncedHighlight); |
||||
script.addEventListener('error', function (event) { |
||||
// Remove element that wasn't successful
|
||||
document.body.removeChild(event.srcElement); |
||||
|
||||
// Highlight code anyway
|
||||
debouncedHighlight(); |
||||
}); |
||||
|
||||
document.body.appendChild(script); |
||||
}); |
||||
} |
||||
|
||||
// Load minimal requirements
|
||||
function loadInitialScriptsAndStyles() { |
||||
var link = document.createElement('link'); |
||||
var script = document.createElement('script'); |
||||
|
||||
link.rel = 'stylesheet'; |
||||
link.href = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/themes/prism.min.css'; |
||||
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.5.1/prism.min.js'; |
||||
|
||||
script.addEventListener('load', global.highlight.update); |
||||
|
||||
document.head.appendChild(link); |
||||
document.body.appendChild(script); |
||||
} |
||||
|
||||
// High Level API
|
||||
global.highlight = global.highlight || { |
||||
|
||||
init: function () { |
||||
loadInitialScriptsAndStyles(); |
||||
}, |
||||
|
||||
update: function () { |
||||
loadAdditionalLanguageSupport(); |
||||
}, |
||||
|
||||
}; |
||||
|
||||
// Hooks
|
||||
if ('events' in global) { |
||||
events.subscribe('document:loaded', global.highlight.init); |
||||
events.subscribe('content:rendered', global.highlight.update); |
||||
} |
||||
|
||||
}(window)); |
||||
Loading…
Reference in new issue