diff options
| author | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-03-22 01:14:35 +0100 | 
|---|---|---|
| committer | Andreas Stöckel <astoecke@techfak.uni-bielefeld.de> | 2015-03-22 01:14:35 +0100 | 
| commit | 93119091893c2f2bf396785e6bd7dcbb9b4f207d (patch) | |
| tree | 408e37ec0bf4ebb1e5427f37b1e12344f70eae9c /script | |
| parent | f6fc9fa292e8da56fe7078f9ac5bdfefa55abe94 (diff) | |
* Implement code highlighting using Prism
* Automatically build ousia.js
Diffstat (limited to 'script')
| -rw-r--r-- | script/highlight.js | 29 | ||||
| -rw-r--r-- | script/prism.js | 428 | ||||
| -rw-r--r-- | script/prism_bash.js (renamed from script/ousia.js) | 19 | 
3 files changed, 466 insertions, 10 deletions
| diff --git a/script/highlight.js b/script/highlight.js new file mode 100644 index 0000000..c50c172 --- /dev/null +++ b/script/highlight.js @@ -0,0 +1,29 @@ +// @license magnet:?xt=urn:btih:5305d91886084f776adcf57509a648432709a7c7&dn=x11.txt +/* + * Ousía Website JS + * + * (c) Andreas Stöckel, 2015 + * + * This work is licensed under the X11 (MIT) license. + * http://www.opensource.org/licenses/mit-license.php + */ +(function () { +	"use strict"; + +	/* Enable code highlighting (this will eventually be natively supported by +	   Ousía) */ +	document.addEventListener("DOMContentLoaded", function(event) { +		var codeBlocks = document.querySelectorAll("pre.code[data-lang]"); +		for (var i = 0; i < codeBlocks.length; i++) { +			var block = codeBlocks[i]; +			var lang = block.getAttribute("data-lang"); +			var text = block.textContent; +			if (lang in Prism.languages) { +				var res = Prism.highlight(text, Prism.languages[lang]); +				block.innerHTML = res; +			} +		} +	}); +})(); +// @license-end + diff --git a/script/prism.js b/script/prism.js new file mode 100644 index 0000000..fc62daa --- /dev/null +++ b/script/prism.js @@ -0,0 +1,428 @@ +/* http://prismjs.com/download.html?themes=prism */ +self = (typeof window !== 'undefined') +	? window   // if in browser +	: ( +		(typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) +		? self // if in worker +		: {}   // if in node js +	); + +/** + * Prism: Lightweight, robust, elegant syntax highlighting + * MIT license http://www.opensource.org/licenses/mit-license.php/ + * @author Lea Verou http://lea.verou.me + */ + +var Prism = (function(){ + +// Private helper vars +var lang = /\blang(?:uage)?-(?!\*)(\w+)\b/i; + +var _ = self.Prism = { +	util: { +		encode: function (tokens) { +			if (tokens instanceof Token) { +				return new Token(tokens.type, _.util.encode(tokens.content), tokens.alias); +			} else if (_.util.type(tokens) === 'Array') { +				return tokens.map(_.util.encode); +			} else { +				return tokens.replace(/&/g, '&').replace(/</g, '<').replace(/\u00a0/g, ' '); +			} +		}, + +		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.map(function(v) { return _.util.clone(v); }); +			} + +			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 +		 * As this needs to recreate the object (we cannot actually insert before keys in object literals), +		 * we cannot just provide an object, we need anobject and a key. +		 * @param inside The key (or language id) of the parent +		 * @param before The key to insert before. If not provided, the function appends instead. +		 * @param insert Object with the key/value pairs to insert +		 * @param root The object that contains `inside`. If equal to Prism.languages, it can be omitted. +		 */ +		insertBefore: function (inside, before, insert, root) { +			root = root || _.languages; +			var grammar = root[inside]; +			 +			if (arguments.length == 2) { +				insert = arguments[1]; +				 +				for (var newToken in insert) { +					if (insert.hasOwnProperty(newToken)) { +						grammar[newToken] = insert[newToken]; +					} +				} +				 +				return grammar; +			} +			 +			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]; +				} +			} +			 +			// Update references in other language definitions +			_.languages.DFS(_.languages, function(key, value) { +				if (value === root[inside] && key != inside) { +					this[key] = ret; +				} +			}); + +			return root[inside] = ret; +		}, + +		// Traverse a language definition with Depth First Search +		DFS: function(o, callback, type) { +			for (var i in o) { +				if (o.hasOwnProperty(i)) { +					callback.call(o, i, o[i], type || i); + +					if (_.util.type(o[i]) === 'Object') { +						_.languages.DFS(o[i], callback); +					} +					else if (_.util.type(o[i]) === 'Array') { +						_.languages.DFS(o[i], callback, i); +					} +				} +			} +		} +	}, + +	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(/^(?:\r?\n|\r)/,''); + +		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) { +		var tokens = _.tokenize(text, grammar); +		return Token.stringify(_.util.encode(tokens), 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 patterns = grammar[token]; +			patterns = (_.util.type(patterns) === "Array") ? patterns : [patterns]; + +			for (var j = 0; j < patterns.length; ++j) { +				var pattern = patterns[j], +					inside = pattern.inside, +					lookbehind = !!pattern.lookbehind, +					lookbehindLength = 0, +					alias = pattern.alias; + +				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, alias); + +						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, alias) { +	this.type = type; +	this.content = content; +	this.alias = alias; +}; + +Token.stringify = function(o, language, parent) { +	if (typeof o == 'string') { +		return o; +	} + +	if (_.util.type(o) === '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'; +	} + +	if (o.alias) { +		var aliases = _.util.type(o.alias) === 'Array' ? o.alias : [o.alias]; +		Array.prototype.push.apply(env.classes, aliases); +	} + +	_.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) { +	if (!self.addEventListener) { +		// in Node.js +		return self.Prism; +	} + 	// In worker +	self.addEventListener('message', function(evt) { +		var message = JSON.parse(evt.data), +		    lang = message.language, +		    code = message.code; + +		self.postMessage(JSON.stringify(_.util.encode(_.tokenize(code, _.languages[lang])))); +		self.close(); +	}, false); + +	return self.Prism; +} + +// 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); +	} +} + +return self.Prism; + +})(); + +if (typeof module !== 'undefined' && module.exports) { +	module.exports = Prism; +} +; diff --git a/script/ousia.js b/script/prism_bash.js index 0ef203a..24d5025 100644 --- a/script/ousia.js +++ b/script/prism_bash.js @@ -7,16 +7,15 @@   * This work is licensed under the X11 (MIT) license.   * http://www.opensource.org/licenses/mit-license.php   */ +  (function () { -	"use strict"; -	var header = document.querySelector("header"); -	window.addEventListener("scroll", function () { -		if (window.pageYOffset > 40) { -			header.className = "scrolled"; -		} else { -			header.className = ""; -		} -	}); +"use strict"; +Prism.languages.bash = { +	'comment': /#.*$/, +	'string': /("|')(\\\n|\\?.)*?\1/, +	'url': /http:\/\/[^\s]*/, +	'keyword': /(^| )(cd|mkdir|git|echo|clone|sudo|yum|apt-get|cmake|make|install)( |$)/ +};  })(); -// @license-end +// @license-end | 
