wikiplus-highlight 2.22.2 → 2.22.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/matchtags.js DELETED
@@ -1,347 +0,0 @@
1
- /*
2
- * CodeMirror, copyright (c) by Marijn Haverbeke and others
3
- * Distributed under an MIT license: https://codemirror.net/LICENSE
4
- * Modified for MediaWiki by Bhsd <https://github.com/bhsd-harry>
5
- */
6
-
7
- (() => {
8
- 'use strict';
9
-
10
- const {Pos, cmpPos, Init} = CodeMirror;
11
-
12
- const tagStart = /<(\/?)([_a-z]\w*)/giu,
13
- voidTags = ['br', 'wbr', 'hr', 'img'],
14
- maxScanLines = 1000;
15
-
16
- /** @ignore */
17
- class Iter {
18
- /**
19
- * @param {CodeMirror.Editor} cm
20
- * @param {CodeMirror.Position} pos 当前位置
21
- */
22
- constructor(cm, pos) {
23
- const {line, ch} = pos;
24
- this.line = line;
25
- this.ch = ch;
26
- this.cm = cm;
27
- this.text = cm.getLine(line);
28
- this.min = Math.max(line - maxScanLines + 1, cm.firstLine());
29
- this.max = Math.min(line + maxScanLines - 1, cm.lastLine());
30
- }
31
-
32
- /** 是否是标签 */
33
- isTag() {
34
- const type = this.cm.getTokenTypeAt(Pos(this.line, this.ch));
35
- return /\b(?:mw-(?:html|ext)tag|tag\b)/u.test(type);
36
- }
37
-
38
- /**
39
- * 判断是否是括号
40
- * @param {number} ch 列号
41
- */
42
- bracketAt(ch) {
43
- const type = this.cm.getTokenTypeAt(Pos(this.line, ch + 1));
44
- return /\b(?:mw-(?:html|ext)tag-)?bracket\b/u.test(type);
45
- }
46
-
47
- /** Jump to the start of the next line */
48
- nextLine() {
49
- if (this.line >= this.max) {
50
- return false;
51
- }
52
- this.ch = 0;
53
- this.text = this.cm.getLine(++this.line);
54
- return true;
55
- }
56
-
57
- /** Jump to the end of the previous line */
58
- prevLine() {
59
- if (this.line <= this.min) {
60
- return false;
61
- }
62
- this.text = this.cm.getLine(--this.line);
63
- this.ch = this.text.length;
64
- return true;
65
- }
66
-
67
- /** Jump to the letter after a `>` towards the line end */
68
- toTagEnd() {
69
- for (;;) {
70
- const gt = this.text.indexOf('>', this.ch);
71
- if (gt === -1) {
72
- return undefined;
73
- }
74
- this.ch = gt + 1;
75
- if (!this.bracketAt(gt)) {
76
- continue;
77
- }
78
- return this.text[gt - 1] === '/' ? 'selfClose' : 'regular';
79
- }
80
- }
81
-
82
- /** Jump to a `<` towards the line start */
83
- toTagStart() {
84
- for (;;) {
85
- const lt = this.ch ? this.text.lastIndexOf('<', this.ch - 1) : -1;
86
- if (lt === -1) {
87
- return undefined;
88
- }
89
- if (!this.bracketAt(lt)) {
90
- this.ch = lt;
91
- continue;
92
- }
93
- tagStart.lastIndex = lt;
94
- this.ch = lt;
95
- const match = tagStart.exec(this.text);
96
- if (match && match.index === lt) {
97
- return match;
98
- }
99
- }
100
- }
101
-
102
- /** Jump to the start of the last line, or the letter after a `tagStart` */
103
- toNextTag() {
104
- for (;;) {
105
- tagStart.lastIndex = this.ch;
106
- const found = tagStart.exec(this.text);
107
- if (!found) {
108
- if (this.nextLine()) {
109
- continue;
110
- } else {
111
- return undefined;
112
- }
113
- }
114
- if (!this.bracketAt(found.index)) {
115
- this.ch = found.index + found[0].length;
116
- continue;
117
- }
118
- this.ch = found.index + found[0].length;
119
- return found;
120
- }
121
- }
122
-
123
- /** Jump to the end of the first line, or a non-bracket `>`, or the letter after a tag bracket `>` */
124
- toPrevTag() {
125
- for (;;) {
126
- const gt = this.ch ? this.text.lastIndexOf('>', this.ch - 1) : -1;
127
- if (gt === -1) {
128
- if (this.prevLine()) {
129
- continue;
130
- } else {
131
- return undefined;
132
- }
133
- }
134
- if (!this.bracketAt(gt)) {
135
- this.ch = gt;
136
- continue;
137
- }
138
- const lastSlash = this.text.lastIndexOf('/', gt);
139
- const selfClose = lastSlash > -1 && !/\S/u.test(this.text.slice(lastSlash + 1, gt));
140
- this.ch = gt + 1;
141
- return selfClose ? 'selfClose' : 'regular';
142
- }
143
- }
144
-
145
- // eslint-disable-next-line jsdoc/require-returns-check
146
- /**
147
- * 搜索匹配的闭合标签
148
- * @param {string} tag 标签名
149
- * @returns {CodeMirror.MatchingTag}
150
- */
151
- findMatchingClose(tag) {
152
- const /** @type {string[]} */ stack = [];
153
- for (;;) {
154
- const next = this.toNextTag();
155
- if (!next) {
156
- return undefined;
157
- }
158
- const start = this.ch - next[0].length,
159
- end = this.toTagEnd(),
160
- tagName = next[2].toLowerCase();
161
- if (!end) {
162
- return undefined;
163
- }
164
- if (end === 'selfClose' || voidTags.includes(tagName)) {
165
- continue;
166
- }
167
- if (next[1]) { // closing tag
168
- let i = stack.length - 1;
169
- for (; i >= 0; --i) {
170
- if (stack[i] === tagName) {
171
- stack.length = i;
172
- break;
173
- }
174
- }
175
- if (i < 0 && (!tag || tag === tagName)) {
176
- return {tag: tagName, from: Pos(this.line, start), to: Pos(this.line, this.ch)};
177
- }
178
- } else { // opening tag
179
- stack.push(tagName);
180
- }
181
- }
182
- }
183
-
184
- // eslint-disable-next-line jsdoc/require-returns-check
185
- /**
186
- * 搜索匹配的开启标签
187
- * @param {string|undefined} tag 标签名
188
- * @returns {CodeMirror.MatchingTag}
189
- */
190
- findMatchingOpen(tag) {
191
- const /** @type {string[]} */ stack = [];
192
- for (;;) {
193
- const prev = this.toPrevTag();
194
- if (!prev) {
195
- return undefined;
196
- }
197
- const {ch: end} = this,
198
- start = this.toTagStart();
199
- if (!start) {
200
- return undefined;
201
- }
202
- const tagName = start[2].toLowerCase();
203
- if (prev === 'selfClose' || voidTags.includes(tagName)) {
204
- continue;
205
- }
206
- if (start[1]) { // closing tag
207
- stack.push(tagName);
208
- } else { // opening tag
209
- let i = stack.length - 1;
210
- for (; i >= 0; --i) {
211
- if (stack[i] === tagName) {
212
- stack.length = i;
213
- break;
214
- }
215
- }
216
- if (i < 0 && (!tag || tag === tagName)) {
217
- // eslint-disable-next-line unicorn/consistent-destructuring
218
- return {tag: tagName, from: Pos(this.line, this.ch), to: Pos(this.line, end)};
219
- }
220
- }
221
- }
222
- }
223
- }
224
-
225
- CodeMirror.defineExtension(
226
- 'findMatchingTag',
227
-
228
- /**
229
- * @this {CodeMirror.Editor}
230
- * @param {CodeMirror.Position} pos 当前位置
231
- * @returns {CodeMirror.MatchingTagPair}
232
- */
233
- function(pos) {
234
- let iter = new Iter(this, pos);
235
- if (!iter.isTag()) {
236
- return undefined;
237
- }
238
- const end = iter.toTagEnd(),
239
- to = end && Pos(iter.line, iter.ch);
240
- const start = end && iter.toTagStart();
241
- if (!start || cmpPos(iter, pos) > 0) {
242
- return undefined;
243
- }
244
- const tag = start[2].toLowerCase(),
245
- here = {from: Pos(iter.line, iter.ch), to, tag};
246
- if (end === 'selfClose' || voidTags.includes(tag)) {
247
- return {open: here, close: null, at: 'self'};
248
- }
249
-
250
- if (start[1]) { // closing tag
251
- return {open: iter.findMatchingOpen(tag), close: here, at: 'close'};
252
- } // opening tag
253
- iter = new Iter(this, to);
254
- return {open: here, close: iter.findMatchingClose(tag), at: 'open'};
255
- },
256
- );
257
-
258
- CodeMirror.defineExtension(
259
- 'findEnclosingTag',
260
-
261
- /**
262
- * @this {CodeMirror.Editor}
263
- * @param {CodeMirror.Position} pos
264
- * @param {string} tag
265
- * @returns {CodeMirror.MatchingTagPair}
266
- */
267
- function(pos, tag) {
268
- const iter = new Iter(this, pos),
269
- open = iter.findMatchingOpen(tag);
270
- if (!open) {
271
- return undefined;
272
- }
273
- const forward = new Iter(this, pos),
274
- close = forward.findMatchingClose(open.tag);
275
- if (close) {
276
- return {open, close};
277
- }
278
- return undefined;
279
- },
280
- );
281
-
282
- /** Used by addon/edit/closetag.js */
283
- CodeMirror.scanForClosingTag = (cm, pos, tagName) => {
284
- const iter = new Iter(cm, pos);
285
- return iter.findMatchingClose(tagName);
286
- };
287
-
288
- CodeMirror.defineOption('matchTags', false, (cm, val, old) => {
289
- if (old && old !== Init) {
290
- cm.off('cursorActivity', doMatchTags);
291
- clear(cm);
292
- }
293
- if (val) {
294
- cm.on('cursorActivity', doMatchTags);
295
- doMatchTags(cm);
296
- }
297
- });
298
-
299
- /**
300
- * 清除高亮
301
- * @param {CodeMirror.EditorWithMatchingTags} cm
302
- */
303
- const clear = cm => {
304
- if (cm.state.tagHit) {
305
- cm.state.tagHit.clear();
306
- }
307
- if (cm.state.tagOther) {
308
- cm.state.tagOther.clear();
309
- }
310
- cm.state.tagHit = null;
311
- cm.state.tagOther = null;
312
- };
313
-
314
- /**
315
- * 搜索并高亮匹配的标签
316
- * @param {CodeMirror.EditorWithMatchingTags} cm
317
- */
318
- const doMatchTags = cm => {
319
- cm.operation(() => {
320
- clear(cm);
321
- if (cm.somethingSelected()) {
322
- return;
323
- }
324
- const match = cm.findMatchingTag(cm.getCursor());
325
- if (!match) {
326
- return;
327
- }
328
- if (match.at === 'self') {
329
- cm.state.tagHit = cm.markText(match.open.from, match.open.to, {className: 'cm-matchingtag'});
330
- return;
331
- }
332
- const hit = match.at === 'open' ? match.open : match.close,
333
- other = match.at === 'close' ? match.open : match.close;
334
- if (hit) {
335
- cm.state.tagHit = cm.markText(hit.from, hit.to, {className: `cm-${other ? '' : 'non'}matchingtag`});
336
- }
337
- if (other) {
338
- cm.state.tagOther = cm.markText(other.from, other.to, {className: 'cm-matchingtag'});
339
- }
340
- });
341
- };
342
-
343
- mw.loader.addStyleTag(
344
- '.cm-matchingtag{background-color:#c9ffc8}'
345
- + '.cm-nonmatchingtag{background-color:#fff0a8}',
346
- );
347
- })();