diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..34b11d1
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,9 @@
+
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_style = space
+indent_size = 4
diff --git a/README.md b/README.md
index 1820f93..5c82fd8 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# highlightjs-line-numbers.js [](https://github.com/wcoder/highlightjs-line-numbers.js/archive/master.zip)
+# highlightjs-line-numbers.js [](https://github.com/wcoder/highlightjs-line-numbers.js/archive/master.zip)
Highlight.js line numbers plugin.
@@ -18,7 +18,7 @@ npm install highlightjs-line-numbers.js
#### Getting the library from CDN
```html
-
+
```
## Usage
diff --git a/bower.json b/bower.json
index 084c9e0..f3b3b75 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
{
"name": "highlightjs-line-numbers.js",
- "version": "2.1.0",
+ "version": "2.2.0",
"homepage": "https://github.com/wcoder/highlightjs-line-numbers.js",
"authors": [
"Yauheni Pakala "
diff --git a/dist/highlightjs-line-numbers.min.js b/dist/highlightjs-line-numbers.min.js
index 188f0b1..0ed4344 100644
--- a/dist/highlightjs-line-numbers.min.js
+++ b/dist/highlightjs-line-numbers.min.js
@@ -1 +1 @@
-!function(t,e){"use strict";function n(){var t=e.createElement("style");t.type="text/css",t.innerHTML=f(".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}",[o,h,u]),e.getElementsByTagName("head")[0].appendChild(t)}function r(n){"complete"===e.readyState?l(n):t.addEventListener("DOMContentLoaded",function(){l(n)})}function l(n){try{var r=e.querySelectorAll("code.hljs");for(var l in r)r.hasOwnProperty(l)&&s(r[l],n)}catch(i){t.console.error("LineNumbers error: ",i)}}function s(t,e){if("object"==typeof t){e=e||{singleLine:!1};var n=e.singleLine?0:1,r=i(t.innerHTML);if(r.length>n){for(var l="",s=0,g=r.length;s | {6} | ',[d,c,h,u,a,s+1,r[s].length>0?r[s]:" "]);t.innerHTML=f('',[o,l])}}}function i(t){return 0===t.length?[]:t.split(/\r\n|\r|\n/g)}var o="hljs-ln",c="hljs-ln-line",a="hljs-ln-code",d="hljs-ln-numbers",h="hljs-ln-n",u="data-line-number",f=function(t,e){return t.replace(/\{(\d+)\}/g,function(t,n){return e[n]?e[n]:t})};t.hljs?(t.hljs.initLineNumbersOnLoad=r,t.hljs.lineNumbersBlock=s,n()):t.console.error("highlight.js not detected!")}(window,document);
\ No newline at end of file
+!function(n,e){"use strict";function t(){var n=e.createElement("style");n.type="text/css",n.innerHTML=h(".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}",[f,m,j]),e.getElementsByTagName("head")[0].appendChild(n)}function r(t){"complete"===e.readyState?l(t):n.addEventListener("DOMContentLoaded",function(){l(t)})}function l(t){try{var r=e.querySelectorAll("code.hljs");for(var l in r)r.hasOwnProperty(l)&&i(r[l],t)}catch(o){n.console.error("LineNumbers error: ",o)}}function i(n,e){if("object"==typeof n){e=e||{singleLine:!1};var t=e.singleLine?0:1;u(function(){s(n),n.innerHTML=o(n.innerHTML,t)})}}function o(n,e){var t=c(n);if(t.length>e){for(var r="",l=0,i=t.length;l | {6} | ',[p,v,m,j,g,l+1,t[l].length>0?t[l]:" "]);return h('',[f,r])}return n}function s(n){var e=n.childNodes;for(var t in e)if(e.hasOwnProperty(t)){var r=e[t];d(r.textContent)>0&&(r.childNodes.length>0?s(r):a(r))}}function a(n){var e=n.parentNode.className;if(/hljs-/.test(e)){for(var t=c(n.textContent),r=0,l="";r{1}\n',[e,t[r]]);n.parentNode.innerHTML=l.trim()}}function c(n){return 0===n.length?[]:n.split(L)}function d(n){return(n.trim().match(L)||[]).length}function u(e){n.setTimeout(e,0)}function h(n,e){return n.replace(/\{(\d+)\}/g,function(n,t){return e[t]?e[t]:n})}var f="hljs-ln",v="hljs-ln-line",g="hljs-ln-code",p="hljs-ln-numbers",m="hljs-ln-n",j="data-line-number",L=/\r\n|\r|\n/g;n.hljs?(n.hljs.initLineNumbersOnLoad=r,n.hljs.lineNumbersBlock=i,t()):n.console.error("highlight.js not detected!")}(window,document);
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
index 358d5aa..e1848f0 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -4,11 +4,11 @@ var rename = require("gulp-rename");
var replace = require('gulp-replace');
gulp.task('build', function() {
- return gulp.src('src/*.js')
- .pipe(uglify())
- .pipe(replace('\\t', ''))
- .pipe(rename({
- extname: '.min.js'
- }))
- .pipe(gulp.dest('dist'));
-});
\ No newline at end of file
+ return gulp.src('src/*.js')
+ .pipe(uglify())
+ .pipe(replace(' ', ''))
+ .pipe(rename({
+ extname: '.min.js'
+ }))
+ .pipe(gulp.dest('dist'));
+});
diff --git a/package.json b/package.json
index a70c0d1..f5a54d0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "highlightjs-line-numbers.js",
- "version": "2.1.0",
+ "version": "2.2.0",
"description": "Highlight.js line numbers plugin.",
"main": "src/highlightjs-line-numbers.js",
"dependencies": {},
diff --git a/src/highlightjs-line-numbers.js b/src/highlightjs-line-numbers.js
index 8fcd3e2..d44dba1 100644
--- a/src/highlightjs-line-numbers.js
+++ b/src/highlightjs-line-numbers.js
@@ -1,113 +1,177 @@
+// jshint multistr:true
+
(function (w, d) {
- 'use strict';
-
- var TABLE_NAME = 'hljs-ln',
- LINE_NAME = 'hljs-ln-line',
- CODE_BLOCK_NAME = 'hljs-ln-code',
- NUMBERS_BLOCK_NAME = 'hljs-ln-numbers',
- NUMBER_LINE_NAME = 'hljs-ln-n',
- DATA_ATTR_NAME = 'data-line-number';
-
- // string format
- // https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript
- var format = function (str, args) {
- return str.replace(/\{(\d+)\}/g, function(m, n){
- return args[n] ? args[n] : m;
- });
- };
-
- if (w.hljs) {
- w.hljs.initLineNumbersOnLoad = initLineNumbersOnLoad;
- w.hljs.lineNumbersBlock = lineNumbersBlock;
-
- addStyles();
- } else {
- w.console.error('highlight.js not detected!');
- }
-
- function addStyles () {
- var css = d.createElement('style');
- css.type = 'text/css';
- css.innerHTML = format(
- '.{0}{border-collapse:collapse}\
- .{0} td{padding:0}\
- .{1}:before{content:attr({2})}',
- [
- TABLE_NAME,
- NUMBER_LINE_NAME,
- DATA_ATTR_NAME
- ]);
- d.getElementsByTagName('head')[0].appendChild(css);
- }
-
- function initLineNumbersOnLoad (options) {
- if (d.readyState === 'complete') {
- documentReady(options);
- } else {
- w.addEventListener('DOMContentLoaded', function () {
- documentReady(options);
- });
- }
- }
-
- function documentReady (options) {
- try {
- var blocks = d.querySelectorAll('code.hljs');
-
- for (var i in blocks) {
- if (blocks.hasOwnProperty(i)) {
- lineNumbersBlock(blocks[i], options);
- }
- }
- } catch (e) {
- w.console.error('LineNumbers error: ', e);
- }
- }
-
- function lineNumbersBlock (element, options) {
- if (typeof element !== 'object') return;
-
- // define options or set default
- options = options || {
- singleLine: false
- };
-
- // convert options
- var firstLineIndex = !!options.singleLine ? 0 : 1;
-
- var lines = getLines(element.innerHTML);
-
- if (lines.length > firstLineIndex) {
- var html = '';
-
- for (var i = 0, l = lines.length; i < l; i++) {
- html += format(
- '\
- \
- \
- | \
- \
- {6} \
- | \
-
',
- [
- NUMBERS_BLOCK_NAME,
- LINE_NAME,
- NUMBER_LINE_NAME,
- DATA_ATTR_NAME,
- CODE_BLOCK_NAME,
- i + 1,
- lines[i].length > 0 ? lines[i] : ' '
- ]);
- }
-
- element.innerHTML = format('', [ TABLE_NAME, html ]);
- }
- }
-
- function getLines(text) {
- if (text.length === 0) return [];
- return text.split(/\r\n|\r|\n/g);
- }
-
-}(window, document));
\ No newline at end of file
+ 'use strict';
+
+ var TABLE_NAME = 'hljs-ln',
+ LINE_NAME = 'hljs-ln-line',
+ CODE_BLOCK_NAME = 'hljs-ln-code',
+ NUMBERS_BLOCK_NAME = 'hljs-ln-numbers',
+ NUMBER_LINE_NAME = 'hljs-ln-n',
+ DATA_ATTR_NAME = 'data-line-number',
+ BREAK_LINE_REGEXP = /\r\n|\r|\n/g;
+
+ if (w.hljs) {
+ w.hljs.initLineNumbersOnLoad = initLineNumbersOnLoad;
+ w.hljs.lineNumbersBlock = lineNumbersBlock;
+
+ addStyles();
+ } else {
+ w.console.error('highlight.js not detected!');
+ }
+
+ function addStyles () {
+ var css = d.createElement('style');
+ css.type = 'text/css';
+ css.innerHTML = format(
+ '.{0}{border-collapse:collapse}\
+ .{0} td{padding:0}\
+ .{1}:before{content:attr({2})}',
+ [
+ TABLE_NAME,
+ NUMBER_LINE_NAME,
+ DATA_ATTR_NAME
+ ]);
+ d.getElementsByTagName('head')[0].appendChild(css);
+ }
+
+ function initLineNumbersOnLoad (options) {
+ if (d.readyState === 'complete') {
+ documentReady(options);
+ } else {
+ w.addEventListener('DOMContentLoaded', function () {
+ documentReady(options);
+ });
+ }
+ }
+
+ function documentReady (options) {
+ try {
+ var blocks = d.querySelectorAll('code.hljs');
+
+ for (var i in blocks) {
+ if (blocks.hasOwnProperty(i)) {
+ lineNumbersBlock(blocks[i], options);
+ }
+ }
+ } catch (e) {
+ w.console.error('LineNumbers error: ', e);
+ }
+ }
+
+ function lineNumbersBlock (element, options) {
+ if (typeof element !== 'object') return;
+
+ // define options or set default
+ options = options || {
+ singleLine: false
+ };
+
+ // convert options
+ var firstLineIndex = !!options.singleLine ? 0 : 1;
+
+ async(function () {
+
+ duplicateMultilineNodes(element);
+
+ element.innerHTML = addLineNumbersBlockFor(element.innerHTML, firstLineIndex);
+ });
+ }
+
+ function addLineNumbersBlockFor (inputHtml, firstLineIndex) {
+
+ var lines = getLines(inputHtml);
+
+ if (lines.length > firstLineIndex) {
+ var html = '';
+
+ for (var i = 0, l = lines.length; i < l; i++) {
+ html += format(
+ '\
+ \
+ \
+ | \
+ \
+ {6} \
+ | \
+
',
+ [
+ NUMBERS_BLOCK_NAME,
+ LINE_NAME,
+ NUMBER_LINE_NAME,
+ DATA_ATTR_NAME,
+ CODE_BLOCK_NAME,
+ i + 1,
+ lines[i].length > 0 ? lines[i] : ' '
+ ]);
+ }
+
+ return format('', [ TABLE_NAME, html ]);
+ }
+
+ return inputHtml;
+ }
+
+ /**
+ * Recursive method for fix multi-line elements implementation in highlight.js
+ * Doing deep passage on child nodes.
+ * @param {HTMLElement} element
+ */
+ function duplicateMultilineNodes (element) {
+ var nodes = element.childNodes;
+ for (var node in nodes){
+ if (nodes.hasOwnProperty(node)) {
+ var child = nodes[node];
+ if (getLinesCount(child.textContent) > 0) {
+ if (child.childNodes.length > 0) {
+ duplicateMultilineNodes(child);
+ } else {
+ duplicateMultilineNode(child);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Method for fix multi-line elements implementation in highlight.js
+ * @param {HTMLElement} element
+ */
+ function duplicateMultilineNode (element) {
+ var className = element.parentNode.className;
+
+ if ( ! /hljs-/.test(className)) return;
+
+ var lines = getLines(element.textContent);
+
+ for (var i = 0, result = ''; i < lines.length; i++) {
+ result += format('{1}\n', [ className, lines[i] ]);
+ }
+ element.parentNode.innerHTML = result.trim();
+ }
+
+ function getLines (text) {
+ if (text.length === 0) return [];
+ return text.split(BREAK_LINE_REGEXP);
+ }
+
+ function getLinesCount (text) {
+ return (text.trim().match(BREAK_LINE_REGEXP) || []).length;
+ }
+
+ function async (func) {
+ w.setTimeout(func, 0);
+ }
+
+ /**
+ * {@link https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript}
+ * @param {string} format
+ * @param {array} args
+ */
+ function format (format, args) {
+ return format.replace(/\{(\d+)\}/g, function(m, n){
+ return args[n] ? args[n] : m;
+ });
+ }
+
+}(window, document));