CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

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