1+ // jshint multistr:true
2+
13( function ( w , d ) {
2- 'use strict' ;
3-
4- var TABLE_NAME = 'hljs-ln' ,
5- LINE_NAME = 'hljs-ln-line' ,
6- CODE_BLOCK_NAME = 'hljs-ln-code' ,
7- NUMBERS_BLOCK_NAME = 'hljs-ln-numbers' ,
8- NUMBER_LINE_NAME = 'hljs-ln-n' ,
9- DATA_ATTR_NAME = 'data-line-number' ;
10-
11- // string format
12- // https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript
13- var format = function ( str , args ) {
14- return str . replace ( / \{ ( \d + ) \} / g, function ( m , n ) {
15- return args [ n ] ? args [ n ] : m ;
16- } ) ;
17- } ;
18-
19- if ( w . hljs ) {
20- w . hljs . initLineNumbersOnLoad = initLineNumbersOnLoad ;
21- w . hljs . lineNumbersBlock = lineNumbersBlock ;
22-
23- addStyles ( ) ;
24- } else {
25- w . console . error ( 'highlight.js not detected!' ) ;
26- }
27-
28- function addStyles ( ) {
29- var css = d . createElement ( 'style' ) ;
30- css . type = 'text/css' ;
31- css . innerHTML = format (
32- '.{0}{border-collapse:collapse}\
33- .{0} td{padding:0}\
34- .{1}:before{content:attr({2})}' ,
35- [
36- TABLE_NAME ,
37- NUMBER_LINE_NAME ,
38- DATA_ATTR_NAME
39- ] ) ;
40- d . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( css ) ;
41- }
42-
43- function initLineNumbersOnLoad ( options ) {
44- if ( d . readyState === 'complete' ) {
45- documentReady ( options ) ;
46- } else {
47- w . addEventListener ( 'DOMContentLoaded' , function ( ) {
48- documentReady ( options ) ;
49- } ) ;
50- }
51- }
52-
53- function documentReady ( options ) {
54- try {
55- var blocks = d . querySelectorAll ( 'code.hljs' ) ;
56-
57- for ( var i in blocks ) {
58- if ( blocks . hasOwnProperty ( i ) ) {
59- lineNumbersBlock ( blocks [ i ] , options ) ;
60- }
61- }
62- } catch ( e ) {
63- w . console . error ( 'LineNumbers error: ' , e ) ;
64- }
65- }
66-
67- function lineNumbersBlock ( element , options ) {
68- if ( typeof element !== 'object' ) return ;
69-
70- // define options or set default
71- options = options || {
72- singleLine : false
73- } ;
74-
75- // convert options
76- var firstLineIndex = ! ! options . singleLine ? 0 : 1 ;
77-
78- var lines = getLines ( element . innerHTML ) ;
79-
80- if ( lines . length > firstLineIndex ) {
81- var html = '' ;
82-
83- for ( var i = 0 , l = lines . length ; i < l ; i ++ ) {
84- html += format (
85- '<tr>\
86- <td class="{0}">\
87- <div class="{1} {2}" {3}="{5}"></div>\
88- </td>\
89- <td class="{4}">\
90- <div class="{1}">{6}</div>\
91- </td>\
92- </tr>' ,
93- [
94- NUMBERS_BLOCK_NAME ,
95- LINE_NAME ,
96- NUMBER_LINE_NAME ,
97- DATA_ATTR_NAME ,
98- CODE_BLOCK_NAME ,
99- i + 1 ,
100- lines [ i ] . length > 0 ? lines [ i ] : ' '
101- ] ) ;
102- }
103-
104- element . innerHTML = format ( '<table class="{0}">{1}</table>' , [ TABLE_NAME , html ] ) ;
105- }
106- }
107-
108- function getLines ( text ) {
109- if ( text . length === 0 ) return [ ] ;
110- return text . split ( / \r \n | \r | \n / g) ;
111- }
112-
113- } ( window , document ) ) ;
4+ 'use strict' ;
5+
6+ var TABLE_NAME = 'hljs-ln' ,
7+ LINE_NAME = 'hljs-ln-line' ,
8+ CODE_BLOCK_NAME = 'hljs-ln-code' ,
9+ NUMBERS_BLOCK_NAME = 'hljs-ln-numbers' ,
10+ NUMBER_LINE_NAME = 'hljs-ln-n' ,
11+ DATA_ATTR_NAME = 'data-line-number' ,
12+ BREAK_LINE_REGEXP = / \r \n | \r | \n / g;
13+
14+ if ( w . hljs ) {
15+ w . hljs . initLineNumbersOnLoad = initLineNumbersOnLoad ;
16+ w . hljs . lineNumbersBlock = lineNumbersBlock ;
17+
18+ addStyles ( ) ;
19+ } else {
20+ w . console . error ( 'highlight.js not detected!' ) ;
21+ }
22+
23+ function addStyles ( ) {
24+ var css = d . createElement ( 'style' ) ;
25+ css . type = 'text/css' ;
26+ css . innerHTML = format (
27+ '.{0}{border-collapse:collapse}\
28+ .{0} td{padding:0}\
29+ .{1}:before{content:attr({2})}' ,
30+ [
31+ TABLE_NAME ,
32+ NUMBER_LINE_NAME ,
33+ DATA_ATTR_NAME
34+ ] ) ;
35+ d . getElementsByTagName ( 'head' ) [ 0 ] . appendChild ( css ) ;
36+ }
37+
38+ function initLineNumbersOnLoad ( options ) {
39+ if ( d . readyState === 'complete' ) {
40+ documentReady ( options ) ;
41+ } else {
42+ w . addEventListener ( 'DOMContentLoaded' , function ( ) {
43+ documentReady ( options ) ;
44+ } ) ;
45+ }
46+ }
47+
48+ function documentReady ( options ) {
49+ try {
50+ var blocks = d . querySelectorAll ( 'code.hljs' ) ;
51+
52+ for ( var i in blocks ) {
53+ if ( blocks . hasOwnProperty ( i ) ) {
54+ lineNumbersBlock ( blocks [ i ] , options ) ;
55+ }
56+ }
57+ } catch ( e ) {
58+ w . console . error ( 'LineNumbers error: ' , e ) ;
59+ }
60+ }
61+
62+ function lineNumbersBlock ( element , options ) {
63+ if ( typeof element !== 'object' ) return ;
64+
65+ // define options or set default
66+ options = options || {
67+ singleLine : false
68+ } ;
69+
70+ // convert options
71+ var firstLineIndex = ! ! options . singleLine ? 0 : 1 ;
72+
73+ async ( function ( ) {
74+
75+ duplicateMultilineNodes ( element ) ;
76+
77+ element . innerHTML = addLineNumbersBlockFor ( element . innerHTML , firstLineIndex ) ;
78+ } ) ;
79+ }
80+
81+ function addLineNumbersBlockFor ( inputHtml , firstLineIndex ) {
82+
83+ var lines = getLines ( inputHtml ) ;
84+
85+ if ( lines . length > firstLineIndex ) {
86+ var html = '' ;
87+
88+ for ( var i = 0 , l = lines . length ; i < l ; i ++ ) {
89+ html += format (
90+ '<tr>\
91+ <td class="{0}">\
92+ <div class="{1} {2}" {3}="{5}"></div>\
93+ </td>\
94+ <td class="{4}">\
95+ <div class="{1}">{6}</div>\
96+ </td>\
97+ </tr>' ,
98+ [
99+ NUMBERS_BLOCK_NAME ,
100+ LINE_NAME ,
101+ NUMBER_LINE_NAME ,
102+ DATA_ATTR_NAME ,
103+ CODE_BLOCK_NAME ,
104+ i + 1 ,
105+ lines [ i ] . length > 0 ? lines [ i ] : ' '
106+ ] ) ;
107+ }
108+
109+ return format ( '<table class="{0}">{1}</table>' , [ TABLE_NAME , html ] ) ;
110+ }
111+
112+ return inputHtml ;
113+ }
114+
115+ /**
116+ * Recursive method for fix multi-line elements implementation in highlight.js
117+ * Doing deep passage on child nodes.
118+ * @param {HTMLElement } element
119+ */
120+ function duplicateMultilineNodes ( element ) {
121+ var nodes = element . childNodes ;
122+ for ( var node in nodes ) {
123+ if ( nodes . hasOwnProperty ( node ) ) {
124+ var child = nodes [ node ] ;
125+ if ( getLinesCount ( child . textContent ) > 0 ) {
126+ if ( child . childNodes . length > 0 ) {
127+ duplicateMultilineNodes ( child ) ;
128+ } else {
129+ duplicateMultilineNode ( child ) ;
130+ }
131+ }
132+ }
133+ }
134+ }
135+
136+ /**
137+ * Method for fix multi-line elements implementation in highlight.js
138+ * @param {HTMLElement } element
139+ */
140+ function duplicateMultilineNode ( element ) {
141+ var className = element . parentNode . className ;
142+
143+ if ( ! / h l j s - / . test ( className ) ) return ;
144+
145+ var lines = getLines ( element . textContent ) ;
146+
147+ for ( var i = 0 , result = '' ; i < lines . length ; i ++ ) {
148+ result += format ( '<span class="{0}">{1}</span>\n' , [ className , lines [ i ] ] ) ;
149+ }
150+ element . parentNode . innerHTML = result . trim ( ) ;
151+ }
152+
153+ function getLines ( text ) {
154+ if ( text . length === 0 ) return [ ] ;
155+ return text . split ( BREAK_LINE_REGEXP ) ;
156+ }
157+
158+ function getLinesCount ( text ) {
159+ return ( text . trim ( ) . match ( BREAK_LINE_REGEXP ) || [ ] ) . length ;
160+ }
161+
162+ function async ( func ) {
163+ w . setTimeout ( func , 0 ) ;
164+ }
165+
166+ /**
167+ * {@link https://wcoder.github.io/notes/string-format-for-string-formating-in-javascript }
168+ * @param {string } format
169+ * @param {array } args
170+ */
171+ function format ( format , args ) {
172+ return format . replace ( / \{ ( \d + ) \} / g, function ( m , n ) {
173+ return args [ n ] ? args [ n ] : m ;
174+ } ) ;
175+ }
176+
177+ } ( window , document ) ) ;
0 commit comments