Commit e86ec01f8924a2bd77fe8c82f28441f81c7eae21

Andreas Rohner 2016-01-07T10:39:37

Add whitespace-normalizer plugin This plugin normalizes whitespace in code blocks. It can perform various operations. The user can configure them through the plugin object located at Prism.plugins.NormalizeWhitespace. Prism.plugins.NormalizeWhitespace.setDefaults({ 'remove-trailing': true, 'remove-indent': true, 'left-trim': true, 'right-trim': true, /*'indent': 2, 'remove-initial-line-feed': false, 'tabs-to-spaces': 4, 'spaces-to-tabs': 4*/ }); The plugin can be disabled for certain code blocks, by adding the class "no-whitespace-normalization" to it. There is also a HTML-interface using the parse-settings plugin.

diff --git a/components.js b/components.js
index b407c14..6c86766 100644
--- a/components.js
+++ b/components.js
@@ -607,6 +607,11 @@ var components = {
 		"command-line": {
 			"title": "Command Line",
 			"owner": "chriswells0"
+		},
+		"normalize-whitespace": {
+			"title": "Normalize Whitespace",
+			"owner": "zeitgeist87",
+			"noCSS": true
 		}
 	}
 };
diff --git a/plugins/normalize-whitespace/demo.html b/plugins/normalize-whitespace/demo.html
new file mode 100644
index 0000000..34e06f4
--- /dev/null
+++ b/plugins/normalize-whitespace/demo.html
@@ -0,0 +1,29 @@
+<body data-prism data-remove-trailing="true">
+<section id="main" class="language-javascript" data-right-trim="true">
+
+<pre>
+
+	<code data-left-trim="true">
+
+
+		var example = {
+			foo: true,
+
+			bar: false
+		};
+
+
+	</code>
+
+</pre>
+
+</section>
+<script src="plugins/normalize-whitespace/prism-normalize-whitespace.js"></script>
+<script type="text/javascript">
+Prism.plugins.NormalizeWhitespace.setDefaults({
+	'remove-trailing': false,
+	'left-trim': false,
+	'right-trim': false
+});
+</script>
+</body>
\ No newline at end of file
diff --git a/plugins/normalize-whitespace/index.html b/plugins/normalize-whitespace/index.html
new file mode 100644
index 0000000..02a000f
--- /dev/null
+++ b/plugins/normalize-whitespace/index.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+
+	<meta charset="utf-8" />
+	<link rel="shortcut icon" href="favicon.png" />
+	<title>Normalize Whitespace ▲ Prism plugins</title>
+	<base href="../.." />
+	<link rel="stylesheet" href="style.css" />
+	<link rel="stylesheet" href="themes/prism.css" data-noprefix />
+	<script src="prefixfree.min.js"></script>
+
+	<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
+	<script src="http://www.google-analytics.com/ga.js" async></script>
+</head>
+<body>
+
+<header>
+	<div class="intro" data-src="templates/header-plugins.html" data-type="text/html"></div>
+
+	<h2>Normalize Whitespace</h2>
+	<p>Supports multiple operations to normalize whitespace in code blocks.</p>
+</header>
+
+<section class="language-markup">
+	<h1>How to use</h1>
+
+	<p>Obviously, this is supposed to work only for code blocks (<code>&lt;pre>&lt;code></code>) and not for inline code.</p>
+	<p>By default the plugin trims all leading and trailing whitespace of every code block.
+	It also removes extra indents and trailing whitespace on every line.</p>
+
+	<p>The plugin uses the <a href="plugins/parse-settings/">Parse Settings</a> plugin to get its settings.
+	The default settings can be overridden with the <code class="language-javascript">setDefaults()</code> method
+	like so:</p>
+
+	<pre class="language-javascript"><code>
+Prism.plugins.NormalizeWhitespace.setDefaults({
+	'remove-trailing': true,
+	'remove-indent': true,
+	'left-trim': true,
+	'right-trim': true,
+	/*'indent': 2,
+	'remove-initial-line-feed': false,
+	'tabs-to-spaces': 4,
+	'spaces-to-tabs': 4*/
+});
+</code></pre>
+
+	<p>It is also possible to change the default settings with <code>data-*</code>-attributes.</p>
+
+	<pre><code>&lt;code data-left-trim="false">...&lt;/code></code></pre>
+
+	<p>The class <code>no-whitespace-normalization</code> or the corresponding
+	data-attribute can be used to disable the normalization for a particular
+	code block.</p>
+
+	<pre><code>&lt;code class="no-whitespace-normalization"
+	data-whitespace-normalization="false">
+...
+&lt;/code></code></pre>
+</section>
+
+<section class="language-markup">
+	<h1>Examples</h1>
+
+	<p>The following example shows some of the possible ways of configuring this plugin:</p>
+
+	<pre data-src="plugins/normalize-whitespace/demo.html"></pre>
+
+	<p>The result looks like this:</p>
+
+<pre class="language-javascript">
+
+	<code>
+
+
+		var example = {
+			foo: true,
+
+			bar: false
+		};
+
+
+	</code>
+
+</pre>
+
+</section>
+
+<footer data-src="templates/footer.html" data-type="text/html"></footer>
+
+<script src="prism.js"></script>
+<script src="plugins/parse-settings/prism-parse-settings.js"></script>
+<script src="plugins/normalize-whitespace/prism-normalize-whitespace.js"></script>
+<script src="utopia.js"></script>
+<script src="components.js"></script>
+<script src="code.js"></script>
+
+
+</body>
+</html>
diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.js b/plugins/normalize-whitespace/prism-normalize-whitespace.js
new file mode 100644
index 0000000..f868e11
--- /dev/null
+++ b/plugins/normalize-whitespace/prism-normalize-whitespace.js
@@ -0,0 +1,129 @@
+(function() {
+
+if (typeof self === 'undefined' || !self.Prism || !self.document) {
+	return;
+}
+
+var assign = Object.assign || function (obj1, obj2) {
+	for (var name in obj2) {
+		if (obj2.hasOwnProperty(name))
+			obj1[name] = obj2[name];
+	}
+	return obj1;
+}
+
+function NormalizeWhitespace(defaults) {
+	this.defaults = assign({}, defaults);
+}
+
+function toCamelCase(value) {
+	return value.replace(/-(\w)/g, function(match, firstChar) {
+		return firstChar.toUpperCase();
+	});
+}
+
+NormalizeWhitespace.prototype = {
+	setDefaults: function (defaults) {
+		this.defaults = assign(this.defaults, defaults);
+	},
+	normalize: function (input, settings) {
+		settings = assign(this.defaults, settings);
+
+		for (var name in settings) {
+			var methodName = toCamelCase(name);
+			if (name !== "normalize" && methodName !== 'setDefaults' &&
+					settings[name] && this[methodName]) {
+				input = this[methodName].call(this, input, settings[name]);
+			}
+		}
+
+		return input;
+	},
+
+	/*
+	 * Normalization methods
+	 */
+	leftTrim: function (input) {
+		return input.replace(/^\s+/, '');
+	},
+	rightTrim: function (input) {
+		return input.replace(/\s+$/, '');
+	},
+	tabsToSpaces: function (input, spaces) {
+		spaces = spaces|0 || 4;
+		return input.replace(/\t/g, new Array(++spaces).join(' '));
+	},
+	spacesToTabs: function (input, spaces) {
+		spaces = spaces|0 || 4;
+		return input.replace(new RegExp(' {' + spaces + '}', 'g'), '\t');
+	},
+	removeTrailing: function (input) {
+		return input.replace(/\s*?$/gm, '');
+	},
+	// Support for deprecated plugin remove-initial-line-feed
+	removeInitialLineFeed: function (input) {
+		return input.replace(/^(?:\r?\n|\r)/, '');
+	},
+	removeIndent: function (input) {
+		var indents = input.match(/^[^\S\n\r]*(?=\S)/gm);
+
+		if (!indents || !indents[0].length)
+			return input;
+
+		indents.sort(function(a, b){return a.length - b.length; });
+
+		if (!indents[0].length)
+			return input;
+
+		return input.replace(new RegExp('^' + indents[0], 'gm'), '');
+	},
+	indent: function (input, tabs) {
+		return input.replace(/^[^\S\n\r]*(?=\S)/gm, new Array(++tabs).join('\t') + '$&');
+	}
+};
+
+Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({
+	'remove-trailing': true,
+	'remove-indent': true,
+	'left-trim': true,
+	'right-trim': true,
+	/*'indent': 2,
+	'remove-initial-line-feed': false,
+	'tabs-to-spaces': 4,
+	'spaces-to-tabs': 4*/
+});
+
+Prism.hooks.add('before-highlight', function (env) {
+	var pre = env.element.parentNode;
+	if (!env.code || !pre || pre.nodeName.toLowerCase() !== 'pre' ||
+			(env.settings && env.settings['whitespace-normalization'] === false))
+		return;
+
+	var children = pre.childNodes,
+	    before = '',
+	    after = '',
+	    codeFound = false;
+
+	// Move surrounding whitespace from the <pre> tag into the <code> tag
+	for (var i = 0; i < children.length; ++i) {
+		var node = children[i];
+
+		if (node == env.element) {
+			codeFound = true;
+		} else if (node.nodeName === "#text") {
+			if (codeFound) {
+				after += node.nodeValue;
+			} else {
+				before += node.nodeValue;
+			}
+
+			pre.removeChild(node);
+			--i;
+		}
+	}
+	env.code = before + env.code + after;
+
+	env.code = Prism.plugins.NormalizeWhitespace.normalize(env.code, env.settings);
+});
+
+}());
\ No newline at end of file
diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.min.js b/plugins/normalize-whitespace/prism-normalize-whitespace.min.js
new file mode 100644
index 0000000..d0131cf
--- /dev/null
+++ b/plugins/normalize-whitespace/prism-normalize-whitespace.min.js
@@ -0,0 +1 @@
+!function(){function e(e){this.defaults=t({},e)}function n(e){return e.replace(/-(\w)/g,function(e,n){return n.toUpperCase()})}if("undefined"!=typeof self&&self.Prism&&self.document){var t=Object.assign||function(e,n){for(var t in n)n.hasOwnProperty(t)&&(e[t]=n[t]);return e};e.prototype={setDefaults:function(e){this.defaults=t(this.defaults,e)},normalize:function(e,r){r=t(this.defaults,r);for(var i in r){var o=n(i);"normalize"!==i&&"setDefaults"!==o&&r[i]&&this[o]&&(e=this[o].call(this,e,r[i]))}return e},leftTrim:function(e){return e.replace(/^\s+/,"")},rightTrim:function(e){return e.replace(/\s+$/,"")},tabsToSpaces:function(e,n){return n=0|n||4,e.replace(/\t/g,new Array(++n).join(" "))},spacesToTabs:function(e,n){return n=0|n||4,e.replace(new RegExp(" {"+n+"}","g"),"	")},removeTrailing:function(e){return e.replace(/\s*?$/gm,"")},removeInitialLineFeed:function(e){return e.replace(/^(?:\r?\n|\r)/,"")},removeIndent:function(e){var n=e.match(/^[^\S\n\r]*(?=\S)/gm);return n&&n[0].length?(n.sort(function(e,n){return e.length-n.length}),n[0].length?e.replace(new RegExp("^"+n[0],"gm"),""):e):e},indent:function(e,n){return e.replace(/^[^\S\n\r]*(?=\S)/gm,new Array(++n).join("	")+"$&")}},Prism.plugins.NormalizeWhitespace=new e({"remove-trailing":!0,"remove-indent":!0,"left-trim":!0,"right-trim":!0}),Prism.hooks.add("before-highlight",function(e){var n=e.element.parentNode;if(e.code&&n&&"pre"===n.nodeName.toLowerCase()&&(!e.settings||e.settings["whitespace-normalization"]!==!1)){for(var t=n.childNodes,r="",i="",o=!1,a=0;a<t.length;++a){var s=t[a];s==e.element?o=!0:"#text"===s.nodeName&&(o?i+=s.nodeValue:r+=s.nodeValue,n.removeChild(s),--a)}e.code=r+e.code+i,e.code=Prism.plugins.NormalizeWhitespace.normalize(e.code,e.settings)}})}}();
\ No newline at end of file
diff --git a/plugins/remove-initial-line-feed/index.html b/plugins/remove-initial-line-feed/index.html
index d981fbb..3c05bbc 100644
--- a/plugins/remove-initial-line-feed/index.html
+++ b/plugins/remove-initial-line-feed/index.html
@@ -23,8 +23,9 @@
 </header>
 
 <section class="language-markup">
-	<h1>How to use</h1>
+	<h1>How to use (DEPRECATED)</h1>
 
+	<p>This plugin will be removed in the future. Please use the general purpose <a href="plugins/normalize-whitespace/">Normalize Whitespace</a> plugin instead.</p>
 	<p>Obviously, this is supposed to work only for code blocks (<code>&lt;pre>&lt;code></code>) and not for inline code.</p>
 	<p>With this plugin included, any initial line feed will be removed by default.</p>
 	<p>To bypass this behaviour, you may add the class <strong>keep-initial-line-feed</strong> to your desired <code>&lt;pre></code>.</p>