|
/* ********************************************** |
|
Begin prism-core.js |
|
********************************************** */ |
|
|
|
/** |
|
* Prism: Lightweight, robust, elegant syntax highlighting |
|
* MIT license http://www.opensource.org/licenses/mit-license.php/ |
|
* @author Lea Verou http://lea.verou.me |
|
*/ |
|
|
|
(function(){ |
|
|
|
// Private helper vars |
|
var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i; |
|
|
|
var _ = self.Prism = { |
|
util: { |
|
type: function (o) { |
|
return Object.prototype.toString.call(o).match(/\[object (\w+)\]/)[1]; |
|
}, |
|
|
|
// Deep clone a language definition (e.g. to extend it) |
|
clone: function (o) { |
|
var type = _.util.type(o); |
|
|
|
switch (type) { |
|
case 'Object': |
|
var clone = {}; |
|
|
|
for (var key in o) { |
|
if (o.hasOwnProperty(key)) { |
|
clone[key] = _.util.clone(o[key]); |
|
} |
|
} |
|
|
|
return clone; |
|
|
|
case 'Array': |
|
return o.slice(); |
|
} |
|
|
|
return o; |
|
} |
|
}, |
|
|
|
languages: { |
|
extend: function (id, redef) { |
|
var lang = _.util.clone(_.languages[id]); |
|
|
|
for (var key in redef) { |
|
lang[key] = redef[key]; |
|
} |
|
|
|
return lang; |
|
}, |
|
|
|
// Insert a token before another token in a language literal |
|
insertBefore: function (inside, before, insert, root) { |
|
root = root || _.languages; |
|
var grammar = root[inside]; |
|
var ret = {}; |
|
|
|
for (var token in grammar) { |
|
|
|
if (grammar.hasOwnProperty(token)) { |
|
|
|
if (token == before) { |
|
|
|
for (var newToken in insert) { |
|
|
|
if (insert.hasOwnProperty(newToken)) { |
|
ret[newToken] = insert[newToken]; |
|
} |
|
} |
|
} |
|
|
|
ret[token] = grammar[token]; |
|
} |
|
} |
|
|
|
return root[inside] = ret; |
|
}, |
|
|
|
// Traverse a language definition with Depth First Search |
|
DFS: function(o, callback) { |
|
for (var i in o) { |
|
callback.call(o, i, o[i]); |
|
|
|
if (_.util.type(o) === 'Object') { |
|
_.languages.DFS(o[i], callback); |
|
} |
|
} |
|
} |
|
}, |
|
|
|
highlightAll: function(async, callback) { |
|
var elements = document.querySelectorAll('code[class*="language-"], [class*="language-"] code, code[class*="lang-"], [class*="lang-"] code'); |
|
|
|
for (var i=0, element; element = elements[i++];) { |
|
_.highlightElement(element, async === true, callback); |
|
} |
|
}, |
|
|
|
highlightElement: function(element, async, callback) { |
|
// Find language |
|
var language, grammar, parent = element; |
|
|
|
while (parent && !lang.test(parent.className)) { |
|
parent = parent.parentNode; |
|
} |
|
|
|
if (parent) { |
|
language = (parent.className.match(lang) || [,''])[1]; |
|
grammar = _.languages[language]; |
|
} |
|
|
|
if (!grammar) { |
|
return; |
|
} |
|
|
|
// Set language on the element, if not present |
|
element.className = element.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; |
|
|
|
// Set language on the parent, for styling |
|
parent = element.parentNode; |
|
|
|
if (/pre/i.test(parent.nodeName)) { |
|
parent.className = parent.className.replace(lang, '').replace(/\s+/g, ' ') + ' language-' + language; |
|
} |
|
|
|
var code = element.textContent; |
|
|
|
if(!code) { |
|
return; |
|
} |
|
|
|
code = code.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); |
|
|
|
var env = { |
|
element: element, |
|
language: language, |
|
grammar: grammar, |
|
code: code |
|
}; |
|
|
|
_.hooks.run('before-highlight', env); |
|
|
|
if (async && self.Worker) { |
|
var worker = new Worker(_.filename); |
|
|
|
worker.onmessage = function(evt) { |
|
env.highlightedCode = Token.stringify(JSON.parse(evt.data), language); |
|
|
|
_.hooks.run('before-insert', env); |
|
|
|
env.element.innerHTML = env.highlightedCode; |
|
|
|
callback && callback.call(env.element); |
|
_.hooks.run('after-highlight', env); |
|
}; |
|
|
|
worker.postMessage(JSON.stringify({ |
|
language: env.language, |
|
code: env.code |
|
})); |
|
} |
|
else { |
|
env.highlightedCode = _.highlight(env.code, env.grammar, env.language) |
|
|
|
_.hooks.run('before-insert', env); |
|
|
|
env.element.innerHTML = env.highlightedCode; |
|
|
|
callback && callback.call(element); |
|
|
|
_.hooks.run('after-highlight', env); |
|
} |
|
}, |
|
|
|
highlight: function (text, grammar, language) { |
|
return Token.stringify(_.tokenize(text, grammar), language); |
|
}, |
|
|
|
tokenize: function(text, grammar, language) { |
|
var Token = _.Token; |
|
|
|
var strarr = [text]; |
|
|
|
var rest = grammar.rest; |
|
|
|
if (rest) { |
|
for (var token in rest) { |
|
grammar[token] = rest[token]; |
|
} |
|
|
|
delete grammar.rest; |
|
} |
|
|
|
tokenloop: for (var token in grammar) { |
|
if(!grammar.hasOwnProperty(token) || !grammar[token]) { |
|
continue; |
|
} |
|
|
|
var pattern = grammar[token], |
|
inside = pattern.inside, |
|
lookbehind = !!pattern.lookbehind, |
|
lookbehindLength = 0; |
|
|
|
pattern = pattern.pattern || pattern; |
|
|
|
for (var i=0; i<strarr.length; i++) { // Don’t cache length as it changes during the loop |
|
|
|
var str = strarr[i]; |
|
|
|
if (strarr.length > text.length) { |
|
// Something went terribly wrong, ABORT, ABORT! |
|
break tokenloop; |
|
} |
|
|
|
if (str instanceof Token) { |
|
continue; |
|
} |
|
|
|
pattern.lastIndex = 0; |
|
|
|
var match = pattern.exec(str); |
|
|
|
if (match) { |
|
if(lookbehind) { |
|
lookbehindLength = match[1].length; |
|
} |
|
|
|
var from = match.index - 1 + lookbehindLength, |
|
match = match[0].slice(lookbehindLength), |
|
len = match.length, |
|
to = from + len, |
|
before = str.slice(0, from + 1), |
|
after = str.slice(to + 1); |
|
|
|
var args = [i, 1]; |
|
|
|
if (before) { |
|
args.push(before); |
|
} |
|
|
|
var wrapped = new Token(token, inside? _.tokenize(match, inside) : match); |
|
|
|
args.push(wrapped); |
|
|
|
if (after) { |
|
args.push(after); |
|
} |
|
|
|
Array.prototype.splice.apply(strarr, args); |
|
} |
|
} |
|
} |
|
|
|
return strarr; |
|
}, |
|
|
|
hooks: { |
|
all: {}, |
|
|
|
add: function (name, callback) { |
|
var hooks = _.hooks.all; |
|
|
|
hooks[name] = hooks[name] || []; |
|
|
|
hooks[name].push(callback); |
|
}, |
|
|
|
run: function (name, env) { |
|
var callbacks = _.hooks.all[name]; |
|
|
|
if (!callbacks || !callbacks.length) { |
|
return; |
|
} |
|
|
|
for (var i=0, callback; callback = callbacks[i++];) { |
|
callback(env); |
|
} |
|
} |
|
} |
|
}; |
|
|
|
var Token = _.Token = function(type, content) { |
|
this.type = type; |
|
this.content = content; |
|
}; |
|
|
|
Token.stringify = function(o, language, parent) { |
|
if (typeof o == 'string') { |
|
return o; |
|
} |
|
|
|
if (Object.prototype.toString.call(o) == '[object Array]') { |
|
return o.map(function(element) { |
|
return Token.stringify(element, language, o); |
|
}).join(''); |
|
} |
|
|
|
var env = { |
|
type: o.type, |
|
content: Token.stringify(o.content, language, parent), |
|
tag: 'span', |
|
classes: ['token', o.type], |
|
attributes: {}, |
|
language: language, |
|
parent: parent |
|
}; |
|
|
|
if (env.type == 'comment') { |
|
env.attributes['spellcheck'] = 'true'; |
|
} |
|
|
|
_.hooks.run('wrap', env); |
|
|
|
var attributes = ''; |
|
|
|
for (var name in env.attributes) { |
|
attributes += name + '="' + (env.attributes[name] || '') + '"'; |
|
} |
|
|
|
return '<' + env.tag + ' class="' + env.classes.join(' ') + '" ' + attributes + '>' + env.content + '</' + env.tag + '>'; |
|
|
|
}; |
|
|
|
if (!self.document) { |
|
// In worker |
|
self.addEventListener('message', function(evt) { |
|
var message = JSON.parse(evt.data), |
|
lang = message.language, |
|
code = message.code; |
|
|
|
self.postMessage(JSON.stringify(_.tokenize(code, _.languages[lang]))); |
|
self.close(); |
|
}, false); |
|
|
|
return; |
|
} |
|
|
|
// Get current script and highlight |
|
var script = document.getElementsByTagName('script'); |
|
|
|
script = script[script.length - 1]; |
|
|
|
if (script) { |
|
_.filename = script.src; |
|
|
|
if (document.addEventListener && !script.hasAttribute('data-manual')) { |
|
document.addEventListener('DOMContentLoaded', _.highlightAll); |
|
} |
|
} |
|
|
|
})(); |
|
|
|
/* ********************************************** |
|
Begin prism-markup.js |
|
********************************************** */ |
|
|
|
Prism.languages.markup = { |
|
'comment': /<!--[\w\W]*?-->/g, |
|
'prolog': /<\?.+?\?>/, |
|
'doctype': /<!DOCTYPE.+?>/, |
|
'cdata': /<!\[CDATA\[[\w\W]*?]]>/i, |
|
'tag': { |
|
pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|\w+))?\s*)*\/?>/gi, |
|
inside: { |
|
'tag': { |
|
pattern: /^<\/?[\w:-]+/i, |
|
inside: { |
|
'punctuation': /^<\/?/, |
|
'namespace': /^[\w-]+?:/ |
|
} |
|
}, |
|
'attr-value': { |
|
pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi, |
|
inside: { |
|
'punctuation': /=|>|"/g |
|
} |
|
}, |
|
'punctuation': /\/?>/g, |
|
'attr-name': { |
|
pattern: /[\w:-]+/g, |
|
inside: { |
|
'namespace': /^[\w-]+?:/ |
|
} |
|
} |
|
|
|
} |
|
}, |
|
'entity': /&#?[\da-z]{1,8};/gi |
|
}; |
|
|
|
// Plugin to make entity title show the real entity, idea by Roman Komarov |
|
Prism.hooks.add('wrap', function(env) { |
|
|
|
if (env.type === 'entity') { |
|
env.attributes['title'] = env.content.replace(/&/, '&'); |
|
} |
|
}); |
|
|
|
/* ********************************************** |
|
Begin prism-css.js |
|
********************************************** */ |
|
|
|
Prism.languages.css = { |
|
'comment': /\/\*[\w\W]*?\*\//g, |
|
'atrule': { |
|
pattern: /@[\w-]+?.*?(;|(?=\s*{))/gi, |
|
inside: { |
|
'punctuation': /[;:]/g |
|
} |
|
}, |
|
'url': /url\((["']?).*?\1\)/gi, |
|
'selector': /[^\{\}\s][^\{\};]*(?=\s*\{)/g, |
|
'property': /(\b|\B)[\w-]+(?=\s*:)/ig, |
|
'string': /("|')(\\?.)*?\1/g, |
|
'important': /\B!important\b/gi, |
|
'ignore': /&(lt|gt|amp);/gi, |
|
'punctuation': /[\{\};:]/g |
|
}; |
|
|
|
if (Prism.languages.markup) { |
|
Prism.languages.insertBefore('markup', 'tag', { |
|
'style': { |
|
pattern: /(<|<)style[\w\W]*?(>|>)[\w\W]*?(<|<)\/style(>|>)/ig, |
|
inside: { |
|
'tag': { |
|
pattern: /(<|<)style[\w\W]*?(>|>)|(<|<)\/style(>|>)/ig, |
|
inside: Prism.languages.markup.tag.inside |
|
}, |
|
rest: Prism.languages.css |
|
} |
|
} |
|
}); |
|
} |
|
|
|
/* ********************************************** |
|
Begin prism-clike.js |
|
********************************************** */ |
|
|
|
Prism.languages.clike = { |
|
'comment': { |
|
pattern: /(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g, |
|
lookbehind: true |
|
}, |
|
'string': /("|')(\\?.)*?\1/g, |
|
'class-name': { |
|
pattern: /((?:class|interface|extends|implements|trait|instanceof|new)\s+)[a-z0-9_\.\\]+/ig, |
|
lookbehind: true, |
|
inside: { |
|
punctuation: /(\.|\\)/ |
|
} |
|
}, |
|
'keyword': /\b(if|else|while|do|for|return|in|instanceof|function|new|try|catch|finally|null|break|continue)\b/g, |
|
'boolean': /\b(true|false)\b/g, |
|
'function': { |
|
pattern: /[a-z0-9_]+\(/ig, |
|
inside: { |
|
punctuation: /\(/ |
|
} |
|
}, |
|
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g, |
|
'operator': /[-+]{1,2}|!|=?<|=?>|={1,2}|(&){1,2}|\|?\||\?|\*|\/|\~|\^|\%/g, |
|
'ignore': /&(lt|gt|amp);/gi, |
|
'punctuation': /[{}[\];(),.:]/g |
|
}; |
|
|
|
/* ********************************************** |
|
Begin prism-javascript.js |
|
********************************************** */ |
|
|
|
Prism.languages.javascript = Prism.languages.extend('clike', { |
|
'keyword': /\b(var|let|if|else|while|do|for|return|in|instanceof|function|new|with|typeof|try|catch|finally|null|break|continue)\b/g, |
|
'number': /\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g |
|
}); |
|
|
|
Prism.languages.insertBefore('javascript', 'keyword', { |
|
'regex': { |
|
pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g, |
|
lookbehind: true |
|
} |
|
}); |
|
|
|
if (Prism.languages.markup) { |
|
Prism.languages.insertBefore('markup', 'tag', { |
|
'script': { |
|
pattern: /(<|<)script[\w\W]*?(>|>)[\w\W]*?(<|<)\/script(>|>)/ig, |
|
inside: { |
|
'tag': { |
|
pattern: /(<|<)script[\w\W]*?(>|>)|(<|<)\/script(>|>)/ig, |
|
inside: Prism.languages.markup.tag.inside |
|
}, |
|
rest: Prism.languages.javascript |
|
} |
|
} |
|
}); |
|
} |
|
|
|
/* ********************************************** |
|
Begin prism-file-highlight.js |
|
********************************************** */ |
|
|
|
(function(){ |
|
|
|
if (!self.Prism || !self.document || !document.querySelector) { |
|
return; |
|
} |
|
|
|
var Extensions = { |
|
'js': 'javascript', |
|
'html': 'markup', |
|
'svg': 'markup' |
|
}; |
|
|
|
Array.prototype.slice.call(document.querySelectorAll('pre[data-src]')).forEach(function(pre) { |
|
var src = pre.getAttribute('data-src'); |
|
var extension = (src.match(/\.(\w+)$/) || [,''])[1]; |
|
var language = Extensions[extension] || extension; |
|
|
|
var code = document.createElement('code'); |
|
code.className = 'language-' + language; |
|
|
|
pre.textContent = ''; |
|
|
|
code.textContent = 'Loading…'; |
|
|
|
pre.appendChild(code); |
|
|
|
var xhr = new XMLHttpRequest(); |
|
|
|
xhr.open('GET', src, true); |
|
|
|
xhr.onreadystatechange = function() { |
|
if (xhr.readyState == 4) { |
|
|
|
if (xhr.status < 400 && xhr.responseText) { |
|
code.textContent = xhr.responseText; |
|
|
|
Prism.highlightElement(code); |
|
} |
|
else if (xhr.status >= 400) { |
|
code.textContent = '✖ Error ' + xhr.status + ' while fetching file: ' + xhr.statusText; |
|
} |
|
else { |
|
code.textContent = '✖ Error: File does not exist or is empty'; |
|
} |
|
} |
|
}; |
|
|
|
xhr.send(null); |
|
}); |
|
|
|
})(); |