diff --git a/components.js b/components.js index b422f92273..80110d348a 100644 --- a/components.js +++ b/components.js @@ -610,6 +610,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 0000000000..34e06f47c3 --- /dev/null +++ b/plugins/normalize-whitespace/demo.html @@ -0,0 +1,29 @@ + +
+ +
+
+	
+
+
+		var example = {
+			foo: true,
+
+			bar: false
+		};
+
+
+	
+
+
+ +
+ + + \ 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 0000000000..02a000f180 --- /dev/null +++ b/plugins/normalize-whitespace/index.html @@ -0,0 +1,101 @@ + + + + + + + Normalize Whitespace ▲ Prism plugins + + + + + + + + + + +
+
+ +

Normalize Whitespace

+

Supports multiple operations to normalize whitespace in code blocks.

+
+ +
+

How to use

+ +

Obviously, this is supposed to work only for code blocks (<pre><code>) and not for inline code.

+

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.

+ +

The plugin uses the Parse Settings plugin to get its settings. + The default settings can be overridden with the setDefaults() method + like so:

+ +

+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*/
+});
+
+ +

It is also possible to change the default settings with data-*-attributes.

+ +
<code data-left-trim="false">...</code>
+ +

The class no-whitespace-normalization or the corresponding + data-attribute can be used to disable the normalization for a particular + code block.

+ +
<code class="no-whitespace-normalization"
+	data-whitespace-normalization="false">
+...
+</code>
+
+ +
+

Examples

+ +

The following example shows some of the possible ways of configuring this plugin:

+ +

+
+	

The result looks like this:

+ +
+
+	
+
+
+		var example = {
+			foo: true,
+
+			bar: false
+		};
+
+
+	
+
+
+ +
+ + + + + + + + + + + + + diff --git a/plugins/normalize-whitespace/prism-normalize-whitespace.js b/plugins/normalize-whitespace/prism-normalize-whitespace.js new file mode 100644 index 0000000000..f2df35f638 --- /dev/null +++ b/plugins/normalize-whitespace/prism-normalize-whitespace.js @@ -0,0 +1,162 @@ +(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(); + }); +} + +function tabLen(str) { + var res = 0; + for (var i = 0; i < str.length; ++i) { + if (str.charCodeAt(i) == '\t'.charCodeAt(0)) + res += 3; + } + return str.length + res; +} + +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') + '$&'); + }, + breakLines: function (input, characters) { + characters = (characters === true) ? 80 : characters|0 || 80; + + var lines = input.split('\n'); + for (var i = 0; i < lines.length; ++i) { + if (tabLen(lines[i]) <= characters) + continue; + + var line = lines[i].split(/(\s+)/g), + len = 0; + + for (var j = 0; j < line.length; ++j) { + var tl = tabLen(line[j]); + len += tl; + if (len > characters) { + line[j] = '\n' + line[j]; + len = tl; + } + } + lines[i] = line.join(''); + } + return lines.join('\n'); + } +}; + +Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({ + 'remove-trailing': true, + 'remove-indent': true, + 'left-trim': true, + 'right-trim': true, + /*'break-lines': 80, + '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
 tag into the  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 0000000000..11669d7dd8
--- /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()})}function r(e){for(var n=0,r=0;rn&&(o[s]="\n"+o[s],a=l)}t[i]=o.join("")}return t.join("\n")}},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 r=n.childNodes,t="",i="",o=!1,a=0;aRemove initial line feed
 
 
 
-

How to use

+

How to use (DEPRECATED)

+

This plugin will be removed in the future. Please use the general purpose Normalize Whitespace plugin instead.

Obviously, this is supposed to work only for code blocks (<pre><code>) and not for inline code.

With this plugin included, any initial line feed will be removed by default.

To bypass this behaviour, you may add the class keep-initial-line-feed to your desired <pre>.