Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Avatar for KuCalc : devops.
Download
50654 views
1
/* global CodeMirror */
2
(function( mod ) { mod( CodeMirror ); })(function( CodeMirror ) {
3
'use strict';
4
5
function eatMnemonic( stream, style, mnemonicStyle ) {
6
var ok;
7
if ( stream.eat( '#' ) ) {
8
if (stream.eat( 'x' ) ) {
9
ok = stream.eatWhile( /[a-fA-F\d]/ ) && stream.eat( ';');
10
} else {
11
ok = stream.eatWhile( /[\d]/ ) && stream.eat( ';' );
12
}
13
} else {
14
ok = stream.eatWhile( /[\w\.\-:]/ ) && stream.eat( ';' );
15
}
16
if ( ok ) {
17
mnemonicStyle += ' mw-mnemonic';
18
return mnemonicStyle;
19
}
20
return style;
21
}
22
23
CodeMirror.defineMode( 'mediawiki', function( config/*, parserConfig */ ) {
24
25
var urlProtocols = new RegExp( config.mwextUrlProtocols, 'i' );
26
var permittedHtmlTags = {'b': true, 'bdi': true, 'del': true, 'i': true, 'ins': true,
27
'u': true, 'font': true, 'big': true, 'small': true, 'sub': true, 'sup': true,
28
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true, 'cite': true,
29
'code': true, 'em': true, 's': true, 'strike': true, 'strong': true, 'tt': true,
30
'var': true, 'div': true, 'center': true, 'blockquote': true, 'ol': true, 'ul': true,
31
'dl': true, 'table': true, 'caption': true, 'pre': true, 'ruby': true, 'rb': true,
32
'rp': true, 'rt': true, 'rtc': true, 'p': true, 'span': true, 'abbr': true, 'dfn': true,
33
'kbd': true, 'samp': true, 'data': true, 'time': true, 'mark': true, 'br': true,
34
'wbr': true, 'hr': true, 'li': true, 'dt': true, 'dd': true, 'td': true, 'th': true,
35
'tr': true, 'noinclude': true, 'includeonly': true, 'onlyinclude': true};
36
37
function makeStyle( style, state, endGround ) {
38
if ( state.isBold ) {
39
style += ' strong';
40
}
41
if ( state.isItalic ) {
42
style += ' em';
43
}
44
return makeLocalStyle( style, state, endGround );
45
}
46
47
function makeLocalStyle( style, state, endGround ) {
48
var ground = '';
49
switch ( state.nTemplate ) {
50
case 0:
51
break;
52
case 1:
53
ground += '-template';
54
break;
55
case 2:
56
ground += '-template2';
57
break;
58
default:
59
ground += '-template3';
60
break;
61
}
62
switch ( state.nExt ) {
63
case 0:
64
break;
65
case 1:
66
ground += '-ext';
67
break;
68
case 2:
69
ground += '-ext2';
70
break;
71
default:
72
ground += '-ext3';
73
break;
74
}
75
if ( state.nLink > 0 ) {
76
ground += '-link';
77
}
78
if ( ground !== '' ) {
79
style = 'mw' + ground + '-ground ' + style;
80
}
81
if ( endGround ) {
82
state[endGround]--;
83
}
84
return style;
85
}
86
87
function eatBlock( style, terminator ) {
88
return function( stream, state ) {
89
while ( !stream.eol() ) {
90
if ( stream.match( terminator ) ) {
91
state.tokenize = state.stack.pop();
92
break;
93
}
94
stream.next();
95
}
96
return makeLocalStyle( style, state );
97
};
98
}
99
100
function eatEnd( style ) {
101
return function( stream, state ) {
102
stream.skipToEnd();
103
state.tokenize = state.stack.pop();
104
return makeLocalStyle( style, state );
105
};
106
}
107
108
function eatChar( char, style ) {
109
return function( stream, state ) {
110
state.tokenize = state.stack.pop();
111
if ( stream.eat( char ) ) {
112
return makeLocalStyle( style, state );
113
}
114
return makeLocalStyle( 'error', state );
115
};
116
}
117
118
function eatSectionHeader( count ) {
119
return function( stream, state ) {
120
if ( stream.match( /[^&<\[\{~]+/ ) ) {
121
if ( stream.eol() ) {
122
stream.backUp( count );
123
state.tokenize = eatEnd( 'mw-section-header' );
124
}
125
return null; // style is null
126
}
127
return eatWikiText( '', '' )( stream, state );
128
};
129
}
130
131
function inVariable( stream, state ) {
132
if ( stream.match( /[^\{\}\|]+/ ) ) {
133
return makeLocalStyle( 'mw-templatevariable-name', state );
134
}
135
if ( stream.eat( '|' ) ) {
136
state.tokenize = inVariableDefault;
137
return makeLocalStyle( 'mw-templatevariable-delimiter', state );
138
}
139
if ( stream.match( '}}}' ) ) {
140
state.tokenize = state.stack.pop();
141
return makeLocalStyle( 'mw-templatevariable-bracket', state );
142
}
143
if ( stream.match( '{{{' ) ) {
144
state.stack.push( state.tokenize );
145
return makeLocalStyle( 'mw-templatevariable-bracket', state );
146
}
147
stream.next();
148
return makeLocalStyle( 'mw-templatevariable-name', state );
149
}
150
151
function inVariableDefault( stream, state ) {
152
if ( stream.match( /[^\{\}\[<\&~]+/ ) ) {
153
return makeLocalStyle( 'mw-templatevariable', state );
154
}
155
if ( stream.match( '}}}' ) ) {
156
state.tokenize = state.stack.pop();
157
return makeLocalStyle( 'mw-templatevariable-bracket', state );
158
}
159
return eatWikiText( 'mw-templatevariable', '' )( stream, state );
160
}
161
162
function inParserFunctionName( stream, state ) {
163
if ( stream.match( /#?[^\:\}\{~]+/ ) ) { // FIXME: {{#name}} and {{uc}} are wrong, must have ':'
164
return makeLocalStyle( 'mw-parserfunction-name', state );
165
}
166
if ( stream.eat( ':' ) ) {
167
state.tokenize = inParserFunctionArguments;
168
return makeLocalStyle( 'mw-parserfunction-delimiter', state );
169
}
170
if ( stream.match( '}}' ) ) {
171
state.tokenize = state.stack.pop();
172
return makeLocalStyle( 'mw-parserfunction-bracket', state, 'nExt' );
173
}
174
return eatWikiText( 'mw-parserfunction', '' )( stream, state );
175
}
176
177
function inParserFunctionArguments( stream, state ) {
178
if ( stream.match( /[^\|\}\{\[<\&~]+/ ) ) {
179
return makeLocalStyle( 'mw-parserfunction', state );
180
} else if ( stream.eat( '|' ) ) {
181
return makeLocalStyle( 'mw-parserfunction-delimiter', state );
182
} else if ( stream.match( '}}' ) ) {
183
state.tokenize = state.stack.pop();
184
return makeLocalStyle( 'mw-parserfunction-bracket', state, 'nExt' );
185
}
186
return eatWikiText( 'mw-parserfunction', '' )( stream, state );
187
}
188
189
function eatTemplatePageName( haveAte ) {
190
return function( stream, state ) {
191
if ( stream.match( /[\s\u00a0]*\|[\s\u00a0]*/ ) ) {
192
state.tokenize = eatTemplateArgument( true );
193
return makeLocalStyle( 'mw-template-delimiter', state );
194
}
195
if ( stream.match( /[\s\u00a0]*\}\}/ ) ) {
196
state.tokenize = state.stack.pop();
197
return makeLocalStyle( 'mw-template-bracket', state, 'nTemplate' );
198
}
199
if ( haveAte && stream.sol() ) {
200
// @todo error message
201
state.nTemplate--;
202
state.tokenize = state.stack.pop();
203
return;
204
}
205
if ( stream.match( /[\s\u00a0]*[^\s\u00a0\|\}<\{\&~]+/ ) ) {
206
state.tokenize = eatTemplatePageName( true );
207
return makeLocalStyle( 'mw-template-name mw-pagename', state );
208
} else if ( stream.eatSpace() ) {
209
if ( stream.eol() === true ) {
210
return makeLocalStyle( 'mw-template-name', state );
211
}
212
return makeLocalStyle( 'mw-template-name mw-pagename', state );
213
}
214
return eatWikiText( 'mw-template-name mw-pagename', 'mw-template-name-mnemonic mw-pagename' )( stream, state );
215
};
216
}
217
218
function eatTemplateArgument( expectArgName ) {
219
return function( stream, state ) {
220
if ( expectArgName && stream.eatWhile( /[^=\|\}\{\[<\&~]/ ) ) {
221
if ( stream.eat( '=' ) ) {
222
state.tokenize = eatTemplateArgument( false );
223
return makeLocalStyle( 'mw-template-argument-name', state );
224
}
225
return makeLocalStyle( 'mw-template', state );
226
} else if ( stream.eatWhile( /[^\|\}\{\[<\&~]/ ) ) {
227
return makeLocalStyle( 'mw-template', state );
228
} else if ( stream.eat( '|' ) ) {
229
state.tokenize = eatTemplateArgument( true );
230
return makeLocalStyle( 'mw-template-delimiter', state );
231
} else if ( stream.match( '}}' ) ) {
232
state.tokenize = state.stack.pop();
233
return makeLocalStyle( 'mw-template-bracket', state, 'nTemplate' );
234
}
235
return eatWikiText( 'mw-template', '' )( stream, state );
236
};
237
}
238
239
function eatExternalLinkProtocol( chars ) {
240
return function( stream, state ) {
241
while ( chars > 0 ) {
242
chars--;
243
stream.next();
244
}
245
if ( stream.eol() ) {
246
state.nLink--;
247
// @todo error message
248
state.tokenize = state.stack.pop();
249
} else {
250
state.tokenize = inExternalLink;
251
}
252
return makeLocalStyle( 'mw-extlink-protocol', state );
253
};
254
}
255
256
function inExternalLink( stream, state ) {
257
if ( stream.sol() ) {
258
state.nLink--;
259
// @todo error message
260
state.tokenize = state.stack.pop();
261
return;
262
}
263
if ( stream.match( /[\s\u00a0]*\]/ ) ) {
264
state.tokenize = state.stack.pop();
265
return makeLocalStyle( 'mw-extlink-bracket', state, 'nLink' );
266
}
267
if ( stream.eatSpace() ) {
268
state.tokenize = inExternalLinkText;
269
return makeStyle( '', state );
270
}
271
if ( stream.match( /[^\s\u00a0\]\{\&~]+/ ) || stream.eatSpace() ) {
272
return makeStyle( 'mw-extlink', state );
273
}
274
return eatWikiText( 'mw-extlink', '' )( stream, state );
275
}
276
277
function inExternalLinkText( stream, state ) {
278
if ( stream.sol() ) {
279
state.nLink--;
280
// @todo error message
281
state.tokenize = state.stack.pop();
282
return;
283
}
284
if ( stream.eat( ']' ) ) {
285
state.tokenize = state.stack.pop();
286
return makeLocalStyle( 'mw-extlink-bracket', state, 'nLink' );
287
}
288
if ( stream.match( /[^'\]\{\&~]+/ ) ) {
289
return makeStyle( 'mw-extlink-text', state );
290
}
291
return eatWikiText( 'mw-extlink-text', '' )( stream, state );
292
}
293
294
function inLink( stream, state ) {
295
if ( stream.sol() ) {
296
state.nLink--;
297
// @todo error message
298
state.tokenize = state.stack.pop();
299
return;
300
}
301
if ( stream.match( /[\s\u00a0]*#[\s\u00a0]*/ ) ) {
302
state.tokenize = inLinkToSection;
303
return makeLocalStyle( 'mw-link', state );
304
}
305
if ( stream.match( /[\s\u00a0]*\|[\s\u00a0]*/ ) ) {
306
state.tokenize = eatLinkText();
307
return makeLocalStyle( 'mw-link-delimiter', state );
308
}
309
if ( stream.match( /[\s\u00a0]*\]\]/ ) ) {
310
state.tokenize = state.stack.pop();
311
return makeLocalStyle( 'mw-link-bracket', state, 'nLink' );
312
// if ( !stream.eatSpace() ) {
313
// state.ImInBlock.push( 'LinkTrail' );
314
// }
315
}
316
if ( stream.match( /[\s\u00a0]*[^\s\u00a0#\|\]\&~\{]+/ ) || stream.eatSpace() ) { //FIXME '{{' brokes Link, sample [[z{{page]]
317
return makeStyle( 'mw-link-pagename mw-pagename', state );
318
}
319
return eatWikiText( 'mw-link-pagename mw-pagename', 'mw-pagename' )( stream, state );
320
}
321
322
function inLinkToSection( stream, state ) {
323
if ( stream.sol() ) {
324
// @todo error message
325
state.nLink--;
326
state.tokenize = state.stack.pop();
327
return;
328
}
329
if ( stream.match( /[^\|\]\&~\{\}]+/ ) ) { //FIXME '{{' brokes Link, sample [[z{{page]]
330
return makeLocalStyle( 'mw-link-tosection', state );
331
}
332
if ( stream.eat( '|' ) ) {
333
state.tokenize = eatLinkText();
334
return makeLocalStyle( 'mw-link-delimiter', state );
335
}
336
if ( stream.match( ']]' ) ) {
337
state.tokenize = state.stack.pop();
338
return makeLocalStyle( 'mw-link-bracket', state, 'nLink' );
339
// if ( !stream.eatSpace() ) {
340
// state.ImInBlock.push( 'LinkTrail' );
341
// }
342
}
343
return eatWikiText( 'mw-link-tosection', '' )( stream, state );
344
}
345
346
function eatLinkText() {
347
var isBold, isItalic;
348
return function ( stream, state ) {
349
if ( stream.match( ']]' ) ) {
350
state.tokenize = state.stack.pop();
351
return makeLocalStyle( 'mw-link-bracket', state, 'nLink' );
352
}
353
if ( stream.match( '\'\'\'' ) ) {
354
isBold = (isBold ? false : true);
355
return makeLocalStyle( 'mw-link-text mw-apostrophes', state );
356
}
357
if ( stream.match( '\'\'' ) ) {
358
isItalic = (isItalic ? false : true);
359
return makeLocalStyle( 'mw-link-text mw-apostrophes', state );
360
}
361
var tmpstyle = 'mw-link-text';
362
if ( isBold ) {
363
tmpstyle += ' strong';
364
}
365
if ( isItalic ) {
366
tmpstyle += ' em';
367
}
368
if ( stream.match( /[^'\]\{\&~]+/ ) ) {
369
return makeStyle( tmpstyle, state );
370
}
371
return eatWikiText( tmpstyle, '' )( stream, state );
372
};
373
}
374
375
function eatTagName( chars, isCloseTag, isHtmlTag ) {
376
return function ( stream, state ) {
377
var name = '';
378
while ( chars > 0 ) {
379
chars--;
380
name = name + stream.next();
381
}
382
if ( stream.eol() ) {
383
// @todo error message
384
state.tokenize = state.stack.pop();
385
return makeLocalStyle( (isHtmlTag ? 'mw-htmltag-name' : 'mw-exttag-name'), state );
386
}
387
stream.eatSpace();
388
if ( stream.eol() ) {
389
// @todo error message
390
state.tokenize = state.stack.pop();
391
return makeLocalStyle( (isHtmlTag ? 'mw-htmltag-name' : 'mw-exttag-name'), state );
392
}
393
394
if ( isHtmlTag ) {
395
if ( isCloseTag ) {
396
state.tokenize = eatChar( '>', 'mw-htmltag-bracket' );
397
} else {
398
state.tokenize = eatHtmlTagAttribute( name );
399
}
400
return makeLocalStyle( 'mw-htmltag-name', state );
401
} // it is the extension tag
402
if ( isCloseTag ) {
403
state.tokenize = eatChar( '>', 'mw-exttag-bracket' );
404
} else {
405
state.tokenize = eatExtTagAttribute( name );
406
}
407
return makeLocalStyle( 'mw-exttag-name', state );
408
};
409
}
410
411
function eatHtmlTagAttribute( name ) {
412
return function ( stream, state ) {
413
if ( stream.match( /[^>\/<\{\&~]+/ ) ) {
414
return makeLocalStyle( 'mw-htmltag-attribute', state );
415
}
416
if ( stream.eat( '>' ) ) {
417
state.InHtmlTag.push( name );
418
state.tokenize = state.stack.pop();
419
return makeLocalStyle( 'mw-htmltag-bracket', state );
420
}
421
if ( stream.match( '/>') ) {
422
state.tokenize = state.stack.pop();
423
return makeLocalStyle( 'mw-htmltag-bracket', state );
424
}
425
return eatWikiText( 'mw-htmltag-attribute', '' )( stream, state );
426
};
427
}
428
429
function eatExtTagAttribute( name ) {
430
return function ( stream, state ) {
431
if ( stream.match( /[^>\/<\{\&~]+/ ) ) {
432
return makeLocalStyle( 'mw-exttag-attribute', state );
433
}
434
if ( stream.eat( '>' ) ) {
435
state.extName = name;
436
if ( name in config.mwextMode.tag ) {
437
state.extMode = CodeMirror.getMode( config, config.mwextMode.tag[name] );
438
state.extState = CodeMirror.startState( state.extMode );
439
}
440
state.tokenize = eatExtTagArea( name );
441
return makeLocalStyle( 'mw-exttag-bracket', state );
442
}
443
if ( stream.match( '/>') ) {
444
state.tokenize = state.stack.pop();
445
return makeLocalStyle( 'mw-exttag-bracket', state );
446
}
447
return eatWikiText( 'mw-exttag-attribute', '' )( stream, state );
448
};
449
}
450
451
function eatExtTagArea( name ) {
452
return function( stream, state ) {
453
var origString = false, from = stream.pos, to;
454
var pattern = new RegExp( '</' + name + '\\s*>' );
455
var m = pattern.exec( from ? stream.string.slice( from ) : stream.string );
456
if ( m ) {
457
if ( m.index === 0 ) {
458
state.tokenize = eatExtCloseTag( name );
459
state.extName = false;
460
if ( state.extMode !== false ) {
461
state.extMode = false;
462
state.extState = false;
463
}
464
return state.tokenize( stream, state );
465
}
466
to = m.index + from;
467
origString = stream.string;
468
stream.string = origString.slice( 0, to );
469
}
470
state.stack.push( state.tokenize );
471
state.tokenize = eatExtTokens( origString );
472
return state.tokenize( stream, state );
473
};
474
}
475
476
function eatExtCloseTag( name ) {
477
return function ( stream, state ) {
478
stream.next(); // eat <
479
stream.next(); // eat /
480
state.tokenize = eatTagName( name.length, true, false );
481
return makeLocalStyle( 'mw-exttag-bracket', state );
482
};
483
}
484
485
function eatExtTokens( origString ) {
486
return function ( stream, state ) {
487
var ret;
488
if ( state.extMode === false ) {
489
ret = (origString === false && stream.sol() ? 'line-cm-mw-exttag' : 'mw-exttag');
490
stream.skipToEnd();
491
} else {
492
ret = (origString === false && stream.sol() ? 'line-cm-mw-tag-' : 'mw-tag-') + state.extName;
493
ret += ' ' + state.extMode.token( stream, state.extState, origString === false );
494
}
495
if ( stream.eol() ) {
496
if ( origString !== false ) {
497
stream.string = origString;
498
}
499
state.tokenize = state.stack.pop();
500
}
501
return makeLocalStyle( ret, state );
502
};
503
}
504
505
function inTableDefinition( stream, state ) {
506
if ( stream.sol() ) {
507
state.tokenize = inTable;
508
return inTable( stream, state );
509
}
510
return eatWikiText( 'mw-table-definition', '' )( stream, state );
511
}
512
513
function inTable( stream, state ) {
514
if ( stream.sol() ) {
515
if ( stream.eat( '|' ) ) {
516
if ( stream.eat( '-' ) ) {
517
stream.eatSpace();
518
state.tokenize = inTableDefinition;
519
return makeLocalStyle( 'mw-table-delimiter', state );
520
}
521
if ( stream.eat( '}' ) ) {
522
state.tokenize = state.stack.pop();
523
return makeLocalStyle( 'mw-table-bracket', state );
524
}
525
stream.eatSpace();
526
state.tokenize = eatTableRow( true, false );
527
return makeLocalStyle( 'mw-table-delimiter', state );
528
}
529
if ( stream.eat( '!' ) ) {
530
stream.eatSpace();
531
state.tokenize = eatTableRow( true, true );
532
return makeLocalStyle( 'mw-table-delimiter', state );
533
}
534
}
535
return eatWikiText( '', '' )( stream, state );
536
}
537
538
function eatTableRow( isStart, isHead ) {
539
return function ( stream, state ) {
540
if ( stream.sol() ) {
541
var peek = stream.peek();
542
if ( peek === '|' || peek === '!' ) {
543
state.tokenize = inTable;
544
return state.tokenize( stream, state );
545
}
546
state.isBold = false;
547
state.isItalic = false;
548
} else {
549
if ( stream.match( /[^'\|\{\[<\&~]+/ ) ) {
550
return makeStyle( (isHead ? 'strong' : ''), state );
551
}
552
if ( stream.match( '||' ) || isHead && stream.match( '!!' ) || (isStart && stream.eat( '|' )) ) {
553
state.isBold = false;
554
state.isItalic = false;
555
if ( isStart ) {
556
state.tokenize = eatTableRow( false, isHead );
557
}
558
return makeLocalStyle( 'mw-table-delimiter', state );
559
}
560
}
561
return eatWikiText( (isHead ? 'strong' : ''), (isHead ? 'strong' : '') )( stream, state );
562
};
563
}
564
565
function eatWikiText( style, mnemonicStyle ) {
566
return function( stream, state ) {
567
function chain( parser ) {
568
state.stack.push( state.tokenize );
569
state.tokenize = parser;
570
return parser( stream, state );
571
}
572
var sol = stream.sol();
573
var ch = stream.next();
574
575
if ( sol ) {
576
state.isBold = false;
577
state.isItalic = false;
578
switch ( ch ) {
579
case ' ':
580
return 'mw-skipformatting';
581
case '-':
582
if ( stream.match( '---' ) ) {
583
return 'mw-hr';
584
}
585
break;
586
case '=':
587
var tmp = stream.match( /(={0,5})(.+?(=\1\s*))$/ );
588
if ( tmp ) { // Title
589
stream.backUp( tmp[2].length );
590
state.stack.push( state.tokenize );
591
state.tokenize = eatSectionHeader( tmp[3].length );
592
return 'mw-section-header line-cm-mw-section-' + ( tmp[1].length + 1 );
593
}
594
break;
595
case '*':
596
case '#':
597
if ( stream.match( /[\*#]*:*/ ) ) {
598
return 'mw-list';
599
}
600
break;
601
case ':':
602
if ( stream.match( /:*[\*#]*/ ) ) {
603
return 'mw-indenting';
604
}
605
break;
606
case '{':
607
if ( stream.eat( '|' ) ) {
608
stream.eatSpace();
609
state.stack.push( state.tokenize );
610
state.tokenize = inTableDefinition;
611
return 'mw-table-bracket';
612
}
613
}
614
}
615
616
switch ( ch ) {
617
case '&':
618
return makeStyle( eatMnemonic( stream, style, mnemonicStyle ), state );
619
case '\'':
620
if ( stream.match( '\'\'' ) ) {
621
state.isBold = state.isBold ? false : true;
622
return makeLocalStyle( 'mw-apostrophes', state );
623
} else if ( stream.eat( '\'' ) ) {
624
state.isItalic = state.isItalic ? false : true;
625
return makeLocalStyle( 'mw-apostrophes', state );
626
}
627
break;
628
case '[':
629
if ( stream.eat( '[' ) ) { // Link Example: [[ Foo | Bar ]]
630
stream.eatSpace();
631
if ( /[^\]\|\[]/.test( stream.peek() ) ) {
632
state.nLink++;
633
state.stack.push( state.tokenize );
634
state.tokenize = inLink;
635
return makeLocalStyle( 'mw-link-bracket', state );
636
}
637
} else {
638
var mt = stream.match( urlProtocols );
639
if ( mt ) {
640
state.nLink++;
641
stream.backUp( mt[0].length );
642
state.stack.push( state.tokenize );
643
state.tokenize = eatExternalLinkProtocol( mt[0].length );
644
return makeLocalStyle( 'mw-extlink-bracket', state );
645
}
646
}
647
break;
648
case '{':
649
if ( stream.match( '{{' ) ) { // Variable
650
stream.eatSpace();
651
state.stack.push( state.tokenize );
652
state.tokenize = inVariable;
653
return makeLocalStyle( 'mw-templatevariable-bracket', state );
654
} else if ( stream.match( /\{[\s\u00a0]*/ ) ) {
655
if ( stream.peek() === '#' ) { // Parser function
656
state.nExt++;
657
state.stack.push( state.tokenize );
658
state.tokenize = inParserFunctionName;
659
return makeLocalStyle( 'mw-parserfunction-bracket', state );
660
}
661
// Check for parser function without '#'
662
var name = stream.match( /([^\s\u00a0\}\[\]<\{\'\|\&\:]+)(\:|[\s\u00a0]*)(\}\}?)?(.)?/ );
663
if ( name ) {
664
stream.backUp( name[0].length );
665
if ( (name[2] === ':' || name[4] === undefined || name[3] === '}}') && (name[1].toLowerCase() in config.mwextFunctionSynonyms[0] || name[1] in config.mwextFunctionSynonyms[1]) ) {
666
state.nExt++;
667
state.stack.push( state.tokenize );
668
state.tokenize = inParserFunctionName;
669
return makeLocalStyle( 'mw-parserfunction-bracket', state );
670
}
671
}
672
// Template
673
state.nTemplate++;
674
state.stack.push( state.tokenize );
675
state.tokenize = eatTemplatePageName( false );
676
return makeLocalStyle( 'mw-template-bracket', state );
677
}
678
break;
679
case '<':
680
if ( stream.match( '!--' ) ) { // coment
681
return chain( eatBlock( 'mw-comment', '-->' ) );
682
}
683
var isCloseTag = ( stream.eat( '/' ) ? true : false );
684
var tagname = stream.match( /[^>\/\s\u00a0\.\*\,\[\]\{\}\$\^\+\?\|\/\\'`~<=!@#%&\(\)-]+/ );
685
if ( tagname ) {
686
tagname = tagname[0].toLowerCase();
687
if ( config.mwextTags && tagname in config.mwextTags ) { // Parser function
688
if ( isCloseTag === true ) {
689
// @todo message
690
return 'error';
691
}
692
stream.backUp( tagname.length );
693
state.stack.push( state.tokenize );
694
state.tokenize = eatTagName( tagname.length, isCloseTag, false );
695
return makeLocalStyle( 'mw-exttag-bracket', state );
696
}
697
if ( tagname in permittedHtmlTags ) { // Html tag
698
if ( isCloseTag === true && tagname !== state.InHtmlTag.pop() ) {
699
// @todo message
700
return 'error';
701
}
702
stream.backUp( tagname.length );
703
state.stack.push( state.tokenize );
704
state.tokenize = eatTagName( tagname.length, isCloseTag, true );
705
return makeLocalStyle( 'mw-htmltag-bracket', state );
706
}
707
stream.backUp( tagname.length );
708
}
709
break;
710
case '~':
711
if ( stream.match( /~{2,4}/ ) ) {
712
return 'mw-signature';
713
}
714
break;
715
}
716
stream.match( /[^\s\u00a0_>\}\[\]<\{\'\|\&\:~]+/ );
717
var ret = makeStyle( style, state );
718
return ret;
719
};
720
}
721
722
return {
723
startState: function() {
724
return { tokenize: eatWikiText('', ''), stack: [], InHtmlTag:[], isBold: false, isItalic: false, extName: false, extMode: false, extState: false, nTemplate: 0, nLink: 0, nExt: 0 };
725
},
726
copyState: function( state ) {
727
return {
728
tokenize: state.tokenize,
729
stack: state.stack.concat( [] ),
730
InHtmlTag: state.InHtmlTag.concat( [] ),
731
isBold: state.isBold,
732
isItalic: state.isItalic,
733
extName: state.extName,
734
extMode: state.extMode,
735
extState: state.extMode !== false && CodeMirror.copyState( state.extMode, state.extState ),
736
nTemplate: state.nTemplate,
737
nLink: state.nLink,
738
nExt: state.nExt
739
};
740
},
741
token: function( stream, state ) {
742
return state.tokenize( stream, state );
743
},
744
blankLine: function( state ) {
745
if ( state.extName ) {
746
if ( state.extMode ) {
747
var ret = '';
748
if ( state.extMode.blankLine ) {
749
ret = ' ' + state.extMode.blankLine( state.extState );
750
}
751
return 'line-cm-mw-tag-' + state.extName + ret;
752
}
753
return 'line-cm-mw-exttag';
754
}
755
}
756
};
757
});
758
759
CodeMirror.defineMIME( 'text/mediawiki', 'mediawiki' );
760
761
function eatNowiki( style, lineStyle ) {
762
return function( stream , state, ownLine ) {
763
if ( ownLine && stream.sol() ) {
764
state.ownLine = true;
765
} else if( ownLine === false && state.ownLine ) {
766
state.ownLine = false;
767
}
768
var s = ( state.ownLine ? lineStyle : style );
769
if ( stream.match( /[^&]+/ ) ) {
770
return s;
771
}
772
stream.next(); // eat &
773
return eatMnemonic( stream, s, s );
774
};
775
}
776
777
CodeMirror.defineMode( 'mw-tag-pre', function( /*config, parserConfig */ ) {
778
return {
779
startState: function() { return {}; },
780
token: eatNowiki( 'mw-tag-pre', 'line-cm-mw-tag-pre' )
781
};
782
});
783
784
CodeMirror.defineMode( 'mw-tag-nowiki', function( /*config, parserConfig */ ) {
785
return {
786
startState: function() { return {}; },
787
token: eatNowiki( 'mw-tag-nowiki', 'line-cm-mw-tag-nowiki' )
788
};
789
});
790
791
});
792
793