1
+ /*docmd
2
+ # Examples
3
+ To turn a code files comments in to a tutorial that will be parsed for markdown, simply include the ` ``data-tutorial="SEPARATOR"`` ` attribute on your` ` `pre`` ` element.
4
+ The ` ``SEPARATOR`` ` is any string of characters that you will append to the comment string to initiate it as a tutorial section. For example, if our separator was 'tutorial' and we were writing and inline comment in Javascript,
5
+ it would look like:
6
+ >
7
+ >
8
+ #### //tutorial # This would be an h1 element!
9
+ >
10
+ >
11
+ And a multiline comment in Javascript would like like:
12
+ ENDdocmd*/
13
+ /*tutorial
14
+ # I am an h1
15
+ ENDtutorial*/
16
+ //docmd ## Here is this plugins code:
17
+ ( function ( ) {
18
+ if ( typeof self === 'undefined' || ! self . Prism || ! self . document || ! document . querySelector ) {
19
+ return ;
20
+ }
21
+ var isTut = false
22
+ var tutSep ;
23
+ var commentArr = [ ]
24
+
25
+ var dataStarts = function ( text ) {
26
+ return findDataStarts ( text . trim ( ) , new RegExp ( '^[^A-Z^a-z]+[^\s+' + tutSep + ']' + tutSep , 'm' ) )
27
+ }
28
+ /*docmd
29
+ ## Built-in Markdown Parser: [Snarkdown](https://github.com/developit/snarkdown)
30
+ ### Snarkdown is a single function parser that minifies just under 2kb.
31
+ That's just small enough to build in to solutions like this.
32
+ >
33
+ >
34
+ **Note:** Snarkdown does not support tables!
35
+ ENDdocmd*/
36
+ var TAGS = {
37
+ '' : [ '<em>' , '</em>' ] ,
38
+ _ : [ '<strong>' , '</strong>' ] ,
39
+ '~' : [ '<s>' , '</s>' ] ,
40
+ '\n' : [ '<br />' ] ,
41
+ ' ' : [ '<br />' ] ,
42
+ '-' : [ '<hr />' ]
43
+ } ;
44
+
45
+ function outdent ( str ) {
46
+ return str . replace ( RegExp ( '^' + ( str . match ( / ^ ( \t | ) + / ) || '' ) [ 0 ] , 'gm' ) , '' ) ;
47
+ }
48
+
49
+ function encodeAttr ( str ) {
50
+ return ( str + '' ) . replace ( / " / g, '"' ) . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) ;
51
+ }
52
+
53
+ function parse ( md , prevLinks ) {
54
+ var tokenizer = / ( (?: ^ | \n + ) (?: \n - - - + | \* \* (?: \* ) + ) \n ) | (?: ^ ` ` ` * ( \w * ) \n ( [ \s \S ] * ?) \n ` ` ` $ ) | ( (?: (?: ^ | \n + ) (?: \t | { 2 , } ) .+ ) + \n * ) | ( (?: (?: ^ | \n ) ( [ > * + - ] | \d + \. ) \s + .* ) + ) | (?: \! \[ ( [ ^ \] ] * ?) \] \( ( [ ^ \) ] + ?) \) ) | ( \[ ) | ( \] (?: \( ( [ ^ \) ] + ?) \) ) ? ) | (?: (?: ^ | \n + ) ( [ ^ \s ] .* ) \n ( \- { 3 , } | = { 3 , } ) (?: \n + | $ ) ) | (?: (?: ^ | \n + ) ( # { 1 , 6 } ) \s * ( .+ ) (?: \n + | $ ) ) | (?: ` ( [ ^ ` ] .* ?) ` ) | ( \n \n * | \n { 2 , } | _ _ | \* \* | [ _ * ] | ~ ~ ) / gm,
55
+ context = [ ] ,
56
+ out = '' ,
57
+ links = prevLinks || { } ,
58
+ last = 0 ,
59
+ chunk , prev , token , inner , t ;
60
+
61
+ function tag ( token ) {
62
+ var desc = TAGS [ token . replace ( / \* / g, '_' ) [ 1 ] || '' ] ,
63
+ end = context [ context . length - 1 ] == token ;
64
+ if ( ! desc ) return token ;
65
+ if ( ! desc [ 1 ] ) return desc [ 0 ] ;
66
+ context [ end ? 'pop' : 'push' ] ( token ) ;
67
+ return desc [ end | 0 ] ;
68
+ }
69
+
70
+ function flush ( ) {
71
+ var str = '' ;
72
+ while ( context . length ) str += tag ( context [ context . length - 1 ] ) ;
73
+ return str ;
74
+ }
75
+
76
+ md = md . replace ( / ^ \[ ( .+ ?) \] : \s * ( .+ ) $ / gm, function ( s , name , url ) {
77
+ links [ name . toLowerCase ( ) ] = url ;
78
+ return '' ;
79
+ } ) . replace ( / ^ \n + | \n + $ / g, '' ) ;
80
+
81
+ while ( ( token = tokenizer . exec ( md ) ) ) {
82
+ prev = md . substring ( last , token . index ) ;
83
+ last = tokenizer . lastIndex ;
84
+ chunk = token [ 0 ] ;
85
+ if ( prev . match ( / [ ^ \\ ] ( \\ \\ ) * \\ $ / ) ) {
86
+ // escaped
87
+ } else if ( token [ 6 ] ) {
88
+ t = token [ 6 ] ;
89
+ if ( t . match ( / \. / ) ) {
90
+ token [ 5 ] = token [ 5 ] . replace ( / ^ \d + / gm, '' ) ;
91
+ }
92
+ inner = parse ( outdent ( token [ 5 ] . replace ( / ^ \s * [ > * + . - ] / gm, '' ) ) ) ;
93
+ if ( t === '>' ) t = 'blockquote' ;
94
+ else {
95
+ t = t . match ( / \. / ) ? 'ol' : 'ul' ;
96
+ inner = inner . replace ( / ^ ( .* ) ( \n | $ ) / gm, '<li>$1</li>' ) ;
97
+ }
98
+ chunk = '<' + t + '>' + inner + '</' + t + '>' ;
99
+ }
100
+ // Images:
101
+ else if ( token [ 8 ] ) {
102
+ chunk = '<img src="' + encodeAttr ( token [ 8 ] ) + '" alt="' + encodeAttr ( token [ 7 ] ) + '">' ;
103
+ }
104
+ // Links:
105
+ else if ( token [ 10 ] ) {
106
+ out = out . replace ( '<a>' , '<a href="' + encodeAttr ( token [ 11 ] || links [ prev . toLowerCase ( ) ] ) + '">' ) ;
107
+ chunk = flush ( ) + '</a>' ;
108
+ } else if ( token [ 9 ] ) {
109
+ chunk = '<a>' ;
110
+ }
111
+ // Headings:
112
+ else if ( token [ 12 ] || token [ 14 ] ) {
113
+ t = 'h' + ( token [ 14 ] ? token [ 14 ] . length : ( token [ 13 ] [ 0 ] === '=' ? 1 : 2 ) ) ;
114
+ chunk = '<' + t + '>' + parse ( token [ 12 ] || token [ 15 ] , links ) + '</' + t + '>' ;
115
+ }
116
+ // `code`:
117
+ else if ( token [ 16 ] ) {
118
+ chunk = '<code>' + encodeAttr ( token [ 16 ] ) + '</code>' ;
119
+ }
120
+ // Inline formatting: *em*, **strong** & friends
121
+ else if ( token [ 17 ] || token [ 1 ] ) {
122
+ chunk = tag ( token [ 17 ] || '--' ) ;
123
+ }
124
+ out += prev ;
125
+ out += chunk ;
126
+ }
127
+
128
+ return ( out + md . substring ( last ) + flush ( ) ) . trim ( ) ;
129
+ }
130
+
131
+ //docmd ### This is an inline comment using our defined separator.
132
+ function $$ ( expr , con ) {
133
+ return Array . prototype . slice . call ( ( con || document ) . querySelectorAll ( expr ) ) ;
134
+ }
135
+
136
+ //docmd ## Another inline comment but now an h2.
137
+ function findDataStarts ( text , splitter ) {
138
+ var indexes = [ ] ;
139
+ text = text . trim ( )
140
+ var lines = text . split ( '\n' )
141
+ for ( var j = 0 ; j < lines . length ; j ++ ) {
142
+ lines [ j ] . match ( splitter ) ? indexes . push ( j + 1 ) : null
143
+ }
144
+ if ( ! isNaN ( lines . length ) ) {
145
+ indexes . push ( lines . length )
146
+ }
147
+ var dataStarts = indexes . slice ( 0 , - 1 )
148
+ return dataStarts
149
+ }
150
+ /*docmd
151
+ # <h1>
152
+ ## <h2>
153
+ ### <h3>
154
+ #### <h4>
155
+ ##### <h5>
156
+ ###### <h6>
157
+ ### Below is a list
158
+ * Item 1
159
+ * * Item 1.1
160
+ * Item 2
161
+ * Item 3
162
+ There is a bug in Snarkdown that wont allow a blockquote underneath anything but a plain text line. Or, the regex I am made to sanitize the text may perhaps be buggy.
163
+ > ## I am a block quote
164
+ >
165
+ > Which can be used to separate paragraphs.
166
+ Now a regular line
167
+ >
168
+ >
169
+ See how I was separated by a blockquote?
170
+ ENDdocmd*/
171
+ Prism . hooks . add ( 'before-sanity-check' , function ( env ) {
172
+ var tutorialElement = env . element . parentNode . getAttribute ( 'data-tutorial' )
173
+ tutSep = tutorialElement
174
+ if ( tutorialElement !== null ) {
175
+ isTut = true
176
+ } else {
177
+ isTut = false
178
+ }
179
+ } ) ;
180
+
181
+ Prism . hooks . add ( 'wrap' , function ( env ) {
182
+ if ( isTut ) {
183
+ if ( env . type === 'comment' && env . content . match ( tutSep ) ) {
184
+ var lengthEnv = env . content . split ( '\n' )
185
+ commentArr . push ( lengthEnv . length )
186
+ env . tag = 'remove'
187
+ env . content = '%' + env . content . trim ( ) + ' \n%'
188
+ env . classes = [ ] ;
189
+ }
190
+ }
191
+ } ) ;
192
+
193
+ Prism . hooks . add ( 'before-insert' , function ( env ) {
194
+ if ( isTut ) {
195
+ var thisTUT = tutSep
196
+ var pre = env . element . parentNode ;
197
+ var lineNumTest = dataStarts ( env . code )
198
+ var sum = lineNumTest . map ( function ( num , idx ) {
199
+ return num + commentArr [ idx ] ;
200
+ } ) ;
201
+ var splitCode = env . highlightedCode . split ( / < r e m o v e .* > | % < \/ r e m o v e > / )
202
+ var x = 1 ;
203
+ splitCode . forEach ( function ( els ) {
204
+ if ( els . match ( / ^ % / ) ) {
205
+ var codeEl = document . createElement ( 'div' )
206
+ var regContent = els . replace ( new RegExp ( '^%.*' + thisTUT + '|.*' + thisTUT + '[^A-Z^a-z].*$' , 'gm' ) , '' )
207
+ . replace ( / ^ \s | \s * $ / gm, "" )
208
+ . replace ( / \n \s * \n / g, '\n' )
209
+ . replace ( / ^ \s | \s * $ / gm, "" )
210
+ codeEl . innerHTML = parse ( regContent . trim ( ) )
211
+ pre . before ( codeEl )
212
+ } else {
213
+ if ( ! els . trim ( ) ) {
214
+ return
215
+ }
216
+ var preEl = document . createElement ( 'pre' )
217
+ var codeNode = document . createElement ( 'code' )
218
+ preEl . className += "line-numbers language-" + env . language
219
+ preEl . setAttribute ( 'data-start' , parseInt ( sum [ x - 1 ] , 10 ) )
220
+ els = els . replace ( / ^ \s + | \s * $ / gm, "" ) ;
221
+ codeNode . innerHTML = els . trim ( )
222
+ console . log ( els )
223
+ preEl . appendChild ( codeNode )
224
+ pre . before ( preEl )
225
+ Prism . highlightAllUnder ( preEl )
226
+ x ++
227
+ }
228
+ } )
229
+ while ( pre . attributes . length > 0 )
230
+ pre . removeAttribute ( pre . attributes [ 0 ] . name ) ;
231
+ pre . innerHTML = ''
232
+ pre . id = 'remove'
233
+ document . getElementById ( 'remove' ) . remove ( )
234
+ }
235
+ } ) ;
236
+ } ) ( ) ;
0 commit comments