1
+ // jshint multistr:true
2
+
1
3
( 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