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/README.md +2 -2
- package/dist/main.min.js +1 -1
- package/dist/main.min.js.map +1 -1
- package/i18n/en.json +1 -1
- package/i18n/ka.json +1 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/lint.js +92 -0
- package/main.js +16 -15
- package/package.json +11 -2
- package/.eslintrc.json +0 -675
- package/bump.sh +0 -24
- package/jsconfig.json +0 -11
- package/matchtags.js +0 -347
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
|
-
})();
|