Commit 849f1d636c12b2552319fcd3d42a9a70e120bfa1

Golmote 2017-09-09T11:07:02

Merge branch 'gh-pages' of https://github.com/VitaliyR/prism into VitaliyR-gh-pages # Conflicts: # plugins/line-numbers/index.html # plugins/line-numbers/prism-line-numbers.js

diff --git a/plugins/line-numbers/index.html b/plugins/line-numbers/index.html
index 2d01694..1453762 100644
--- a/plugins/line-numbers/index.html
+++ b/plugins/line-numbers/index.html
@@ -29,6 +29,7 @@
   <p>Obviously, this is supposed to work only for code blocks (<code>&lt;pre>&lt;code></code>) and not for inline code.</p>
   <p>Add class <strong>line-numbers</strong> to your desired <code>&lt;pre></code> and line-numbers plugin will take care.</p>
   <p>Optional: You can specify the <code>data-start</code> (Number) attribute on the <code>&lt;pre></code> element. It will shift the line counter.</p>
+  <p>Optional: To support multiline line numbers using soft wrap add css <code>white-space</code> to <code>pre-line</code> or <code>pre-wrap</code>.</p>
 </section>
 
 <section>
@@ -49,6 +50,10 @@
 is not highlighted
 but it still has
 lines numbers</code></pre>
+
+  <h2>Soft wrap support</h2>
+  <pre class="line-numbers" data-src="plugins/line-numbers/index.html" data-start="-5" style="white-space:pre-wrap;"></pre>
+
 </section>
 
 <footer data-src="templates/footer.html" data-type="text/html"></footer>
diff --git a/plugins/line-numbers/prism-line-numbers.css b/plugins/line-numbers/prism-line-numbers.css
index 284cc0a..e32989b 100644
--- a/plugins/line-numbers/prism-line-numbers.css
+++ b/plugins/line-numbers/prism-line-numbers.css
@@ -6,6 +6,8 @@ pre.line-numbers {
 
 pre.line-numbers > code {
 	position: relative;
+    display: inline-block;
+    white-space: inherit;
 }
 
 .line-numbers .line-numbers-rows {
diff --git a/plugins/line-numbers/prism-line-numbers.js b/plugins/line-numbers/prism-line-numbers.js
index b01ce6f..09dc2c7 100644
--- a/plugins/line-numbers/prism-line-numbers.js
+++ b/plugins/line-numbers/prism-line-numbers.js
@@ -1,57 +1,114 @@
-(function() {
+(function () {
 
-if (typeof self === 'undefined' || !self.Prism || !self.document) {
-	return;
-}
-
-Prism.hooks.add('complete', function (env) {
-	if (!env.code) {
+	if (typeof self === 'undefined' || !self.Prism || !self.document) {
 		return;
 	}
 
-	// works only for <code> wrapped inside <pre> (not inline)
-	var pre = env.element.parentNode;
-	var clsReg = /\s*\bline-numbers\b\s*/;
-	if (
-		!pre || !/pre/i.test(pre.nodeName) ||
+	/**
+	 * Class name for <pre> which is activating the plugin
+	 * @type {String}
+	 */
+	var PLUGIN_CLASS = 'line-numbers';
+
+	/**
+	 * Resizes line numbers spans according to height of line of code
+	 * @param  {Element} element <pre> element
+	 */
+	var _resizeElement = function (element) {
+		var codeStyles = getStyles(element);
+		var whiteSpace = codeStyles['white-space'];
+
+		if (whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line') {
+			var codeElement = element.querySelector('code');
+			var lineNumbersWrapper = element.querySelector('.line-numbers-rows');
+			var lineNumberSizer = element.querySelector('.line-numbers-sizer');
+			var codeLines = element.textContent.split('\n');
+
+			if (!lineNumberSizer) {
+				lineNumberSizer = document.createElement('span');
+				lineNumberSizer.className = 'line-numbers-sizer';
+
+				codeElement.appendChild(lineNumberSizer);
+			}
+
+			lineNumberSizer.style.display = 'block';
+
+			codeLines.forEach(function (line, lineNumber) {
+				lineNumberSizer.textContent = line || '\n';
+				var lineSize = lineNumberSizer.getBoundingClientRect().height;
+				lineNumbersWrapper.children[lineNumber].style.height = lineSize + 'px';
+			});
+
+			lineNumberSizer.textContent = '';
+			lineNumberSizer.style.display = 'none';
+		}
+	};
+
+	/**
+	 * Returns style declarations for the element
+	 * @param {Element} element
+	 */
+	var getStyles = function (element) {
+		if (!element) {
+			return null;
+		}
+
+		return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null);
+	};
+
+	window.addEventListener('resize', function () {
+		Array.prototype.forEach.call(document.querySelectorAll('pre.' + PLUGIN_CLASS), _resizeElement);
+	});
+
+	Prism.hooks.add('complete', function (env) {
+		if (!env.code) {
+			return;
+		}
+
+		// works only for <code> wrapped inside <pre> (not inline)
+		var pre = env.element.parentNode;
+		var clsReg = /\s*\bline-numbers\b\s*/;
+		if (
+			!pre || !/pre/i.test(pre.nodeName) ||
 			// Abort only if nor the <pre> nor the <code> have the class
-		(!clsReg.test(pre.className) && !clsReg.test(env.element.className))
-	) {
-		return;
-	}
+			(!clsReg.test(pre.className) && !clsReg.test(env.element.className))
+		) {
+			return;
+		}
 
-	if (env.element.querySelector(".line-numbers-rows")) {
-		// Abort if line numbers already exists
-		return;
-	}
+		if (env.element.querySelector(".line-numbers-rows")) {
+			// Abort if line numbers already exists
+			return;
+		}
 
-	if (clsReg.test(env.element.className)) {
-		// Remove the class "line-numbers" from the <code>
-		env.element.className = env.element.className.replace(clsReg, '');
-	}
-	if (!clsReg.test(pre.className)) {
-		// Add the class "line-numbers" to the <pre>
-		pre.className += ' line-numbers';
-	}
+		if (clsReg.test(env.element.className)) {
+			// Remove the class "line-numbers" from the <code>
+			env.element.className = env.element.className.replace(clsReg, '');
+		}
+		if (!clsReg.test(pre.className)) {
+			// Add the class "line-numbers" to the <pre>
+			pre.className += ' line-numbers';
+		}
 
-	var match = env.code.match(/\n(?!$)/g);
-	var linesNum = match ? match.length + 1 : 1;
-	var lineNumbersWrapper;
+		var match = env.code.match(/\n(?!$)/g);
+		var linesNum = match ? match.length + 1 : 1;
+		var lineNumbersWrapper;
 
-	var lines = new Array(linesNum + 1);
-	lines = lines.join('<span></span>');
+		var lines = new Array(linesNum + 1);
+		lines = lines.join('<span></span>');
 
-	lineNumbersWrapper = document.createElement('span');
-	lineNumbersWrapper.setAttribute('aria-hidden', 'true');
-	lineNumbersWrapper.className = 'line-numbers-rows';
-	lineNumbersWrapper.innerHTML = lines;
+		lineNumbersWrapper = document.createElement('span');
+		lineNumbersWrapper.setAttribute('aria-hidden', 'true');
+		lineNumbersWrapper.className = 'line-numbers-rows';
+		lineNumbersWrapper.innerHTML = lines;
 
-	if (pre.hasAttribute('data-start')) {
-		pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
-	}
+		if (pre.hasAttribute('data-start')) {
+			pre.style.counterReset = 'linenumber ' + (parseInt(pre.getAttribute('data-start'), 10) - 1);
+		}
 
-	env.element.appendChild(lineNumbersWrapper);
+		env.element.appendChild(lineNumbersWrapper);
 
-});
+		_resizeElement(pre);
+	});
 
 }());
\ No newline at end of file