@bhsd/codemirror-mediawiki 2.1.11 → 2.1.13
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 +12 -3
- package/dist/codemirror.d.ts +1 -1
- package/dist/main.min.js +12 -12
- package/dist/main.min.js.map +3 -3
- package/dist/mw.min.js +2 -0
- package/dist/mw.min.js.map +7 -0
- package/mediawiki.css +25 -25
- package/mw/base.ts +199 -0
- package/mw/config.ts +148 -0
- package/mw/openLinks.ts +36 -0
- package/mw/textSelection.ts +54 -0
- package/package.json +14 -13
- package/src/codemirror.ts +74 -44
- package/src/mediawiki.ts +1 -1
- package/mw/dist/base.js +0 -265
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bhsd/codemirror-mediawiki",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.13",
|
|
4
4
|
"description": "Modified CodeMirror mode based on wikimedia/mediawiki-extensions-CodeMirror",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mediawiki",
|
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
"!/src/gh-page.ts",
|
|
17
17
|
"!/src/plugins.ts",
|
|
18
18
|
"!/src/*.d.ts",
|
|
19
|
+
"/mw/*.ts",
|
|
20
|
+
"!/mw/*.d.ts",
|
|
19
21
|
"/dist/",
|
|
20
|
-
"/mediawiki.css"
|
|
21
|
-
"/mw/dist/"
|
|
22
|
+
"/mediawiki.css"
|
|
22
23
|
],
|
|
23
24
|
"browser": "dist/main.min.js",
|
|
24
25
|
"main": "./dist/main.min.js",
|
|
@@ -29,13 +30,13 @@
|
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
32
|
"build:core": "esbuild ./src/codemirror.ts --bundle --minify --target=es2018 --format=esm --sourcemap --outfile=dist/main.min.js && tsc --emitDeclarationOnly && rm dist/gh-page.d.ts",
|
|
32
|
-
"build:mw": "
|
|
33
|
+
"build:mw": "esbuild ./mw/base.ts --bundle --minify --target=es2018 --format=esm --sourcemap --outfile=dist/mw.min.js",
|
|
33
34
|
"build:gh-page": "bash build.sh src/gh-page.ts gh-page.js",
|
|
34
35
|
"build": "npm run build:core && npm run build:mw",
|
|
35
36
|
"lint:ts": "tsc --noEmit && tsc --project mw/tsconfig.json --noEmit && eslint --cache .",
|
|
36
37
|
"lint:css": "stylelint *.css",
|
|
37
38
|
"lint": "npm run lint:ts && npm run lint:css",
|
|
38
|
-
"server": "http-server .. -c-1 --cors &",
|
|
39
|
+
"server": "npm run test:end; http-server .. -c-1 --cors &",
|
|
39
40
|
"test": "npm run build:core && npm run build:gh-page && npm run server",
|
|
40
41
|
"test:end": "pkill -x http-server"
|
|
41
42
|
},
|
|
@@ -52,24 +53,24 @@
|
|
|
52
53
|
"@codemirror/state": "^6.3.3",
|
|
53
54
|
"@codemirror/view": "^6.22.2",
|
|
54
55
|
"@lezer/highlight": "^1.2.0",
|
|
55
|
-
"@stylistic/eslint-plugin": "^1.5.
|
|
56
|
+
"@stylistic/eslint-plugin": "^1.5.4",
|
|
56
57
|
"@stylistic/stylelint-plugin": "^2.0.0",
|
|
57
58
|
"@types/jquery": "^3.5.29",
|
|
58
59
|
"@types/oojs-ui": "^0.47.6",
|
|
59
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
60
|
-
"@typescript-eslint/parser": "^6.
|
|
61
|
-
"esbuild": "^0.19.
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^6.19.1",
|
|
61
|
+
"@typescript-eslint/parser": "^6.19.1",
|
|
62
|
+
"esbuild": "^0.19.12",
|
|
62
63
|
"eslint": "^8.56.0",
|
|
63
|
-
"eslint-plugin-es-x": "^7.
|
|
64
|
+
"eslint-plugin-es-x": "^7.5.0",
|
|
64
65
|
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
65
66
|
"eslint-plugin-promise": "^6.1.1",
|
|
66
|
-
"eslint-plugin-regexp": "^2.
|
|
67
|
+
"eslint-plugin-regexp": "^2.2.0",
|
|
67
68
|
"eslint-plugin-unicorn": "^50.0.1",
|
|
68
69
|
"http-server": "^14.1.0",
|
|
69
70
|
"stylelint": "^16.1.0",
|
|
70
71
|
"stylelint-config-recommended": "^14.0.0",
|
|
71
72
|
"types-mediawiki": "^1.4.0",
|
|
72
|
-
"typescript": "^5.
|
|
73
|
-
"wikilint": "^2.
|
|
73
|
+
"typescript": "^5.3.3",
|
|
74
|
+
"wikilint": "^2.4.1"
|
|
74
75
|
}
|
|
75
76
|
}
|
package/src/codemirror.ts
CHANGED
|
@@ -61,19 +61,20 @@ const avail: Record<string, [(config?: any) => Extension, Record<string, unknown
|
|
|
61
61
|
{},
|
|
62
62
|
],
|
|
63
63
|
};
|
|
64
|
+
const CDN = 'https://testingcf.jsdelivr.net';
|
|
64
65
|
|
|
65
66
|
/**
|
|
66
67
|
* 使用传统方法加载脚本
|
|
67
68
|
* @param src 脚本地址
|
|
68
|
-
* @param
|
|
69
|
+
* @param globalConst 脚本全局变量名
|
|
69
70
|
*/
|
|
70
|
-
const loadScript = (src: string,
|
|
71
|
-
if (
|
|
71
|
+
const loadScript = (src: string, globalConst: string): Promise<void> => new Promise(resolve => {
|
|
72
|
+
if (globalConst in window) {
|
|
72
73
|
resolve();
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
75
76
|
const script = document.createElement('script');
|
|
76
|
-
script.src =
|
|
77
|
+
script.src = `${CDN}/${src}`;
|
|
77
78
|
script.onload = (): void => {
|
|
78
79
|
resolve();
|
|
79
80
|
};
|
|
@@ -90,13 +91,14 @@ const pos = (doc: Text, line: number, column: number): number => doc.line(line).
|
|
|
90
91
|
|
|
91
92
|
export class CodeMirror6 {
|
|
92
93
|
readonly #textarea;
|
|
93
|
-
readonly #language;
|
|
94
|
-
readonly #linter;
|
|
95
|
-
readonly #extensions;
|
|
96
|
-
readonly #indent;
|
|
97
94
|
readonly #view;
|
|
95
|
+
readonly #language = new Compartment();
|
|
96
|
+
readonly #linter = new Compartment();
|
|
97
|
+
readonly #extensions = new Compartment();
|
|
98
|
+
readonly #indent = new Compartment();
|
|
98
99
|
#lang;
|
|
99
|
-
#visible =
|
|
100
|
+
#visible = false;
|
|
101
|
+
#preferred = new Set<string>();
|
|
100
102
|
|
|
101
103
|
get textarea(): HTMLTextAreaElement {
|
|
102
104
|
return this.#textarea;
|
|
@@ -122,10 +124,6 @@ export class CodeMirror6 {
|
|
|
122
124
|
constructor(textarea: HTMLTextAreaElement, lang = 'plain', config?: unknown) {
|
|
123
125
|
this.#textarea = textarea;
|
|
124
126
|
this.#lang = lang;
|
|
125
|
-
this.#language = new Compartment();
|
|
126
|
-
this.#linter = new Compartment();
|
|
127
|
-
this.#extensions = new Compartment();
|
|
128
|
-
this.#indent = new Compartment();
|
|
129
127
|
let timer: number | undefined;
|
|
130
128
|
const extensions = [
|
|
131
129
|
this.#language.of(languages[lang]!(config)),
|
|
@@ -162,25 +160,12 @@ export class CodeMirror6 {
|
|
|
162
160
|
extensions,
|
|
163
161
|
doc: textarea.value,
|
|
164
162
|
});
|
|
165
|
-
const {
|
|
166
|
-
{fontSize, lineHeight} = getComputedStyle(textarea),
|
|
167
|
-
hasFocus = document.activeElement === textarea;
|
|
163
|
+
const {fontSize, lineHeight} = getComputedStyle(textarea);
|
|
168
164
|
textarea.parentNode!.insertBefore(this.#view.dom, textarea);
|
|
169
165
|
this.#minHeight();
|
|
170
|
-
this.#
|
|
171
|
-
this.#view.dom.style.fontSize = fontSize;
|
|
166
|
+
this.#view.scrollDOM.style.fontSize = fontSize;
|
|
172
167
|
this.#view.scrollDOM.style.lineHeight = lineHeight;
|
|
173
|
-
this
|
|
174
|
-
this.#view.dispatch({
|
|
175
|
-
selection: {anchor: selectionStart, head: selectionEnd},
|
|
176
|
-
});
|
|
177
|
-
textarea.style.display = 'none';
|
|
178
|
-
if (hasFocus) {
|
|
179
|
-
this.#view.focus();
|
|
180
|
-
}
|
|
181
|
-
requestAnimationFrame(() => {
|
|
182
|
-
this.#view.scrollDOM.scrollTop = scrollTop;
|
|
183
|
-
});
|
|
168
|
+
this.toggle(true);
|
|
184
169
|
}
|
|
185
170
|
|
|
186
171
|
/** 刷新编辑器高度 */
|
|
@@ -264,16 +249,23 @@ export class CodeMirror6 {
|
|
|
264
249
|
* 添加扩展
|
|
265
250
|
* @param names 扩展名
|
|
266
251
|
*/
|
|
267
|
-
prefer(names:
|
|
252
|
+
prefer(names: string[] | Record<string, boolean>): void {
|
|
253
|
+
if (Array.isArray(names)) {
|
|
254
|
+
this.#preferred = new Set(names.filter(name => avail[name]));
|
|
255
|
+
} else {
|
|
256
|
+
for (const [name, enable] of Object.entries(names)) {
|
|
257
|
+
if (enable && avail[name]) {
|
|
258
|
+
this.#preferred.add(name);
|
|
259
|
+
} else {
|
|
260
|
+
this.#preferred.delete(name);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
268
264
|
this.#view.dispatch({
|
|
269
265
|
effects: [
|
|
270
|
-
this.#extensions.reconfigure(
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
const [extension, configs] = option;
|
|
274
|
-
return extension(configs[this.#lang]);
|
|
275
|
-
}
|
|
276
|
-
return [];
|
|
266
|
+
this.#extensions.reconfigure([...this.#preferred].map(name => {
|
|
267
|
+
const [extension, configs] = avail[name]!;
|
|
268
|
+
return extension(configs[this.#lang]);
|
|
277
269
|
})),
|
|
278
270
|
],
|
|
279
271
|
});
|
|
@@ -293,11 +285,21 @@ export class CodeMirror6 {
|
|
|
293
285
|
async getLinter(opt?: Record<string, unknown>): Promise<LintSource | undefined> {
|
|
294
286
|
switch (this.#lang) {
|
|
295
287
|
case 'mediawiki': {
|
|
296
|
-
const
|
|
297
|
-
|
|
288
|
+
const REPO = 'npm/wikiparser-node@1.4.1-b',
|
|
289
|
+
DIR = `${REPO}/extensions/dist`,
|
|
290
|
+
src = `combine/${DIR}/base.min.js,${DIR}/lint.min.js`,
|
|
291
|
+
lang = opt?.['i18n'];
|
|
298
292
|
await loadScript(src, 'wikiparse');
|
|
299
|
-
|
|
300
|
-
|
|
293
|
+
if (typeof lang === 'string') {
|
|
294
|
+
try {
|
|
295
|
+
const i18n: Record<string, string>
|
|
296
|
+
= await (await fetch(`${CDN}/${REPO}/i18n/${lang.toLowerCase()}.json`)).json();
|
|
297
|
+
wikiparse.setI18N(i18n);
|
|
298
|
+
} catch {}
|
|
299
|
+
}
|
|
300
|
+
const wikiLinter = new wikiparse.Linter(opt?.['include'] as boolean | undefined);
|
|
301
|
+
return async doc =>
|
|
302
|
+
(await wikiLinter.codemirror(doc.toString())).filter(({severity}) => severity === 'error');
|
|
301
303
|
}
|
|
302
304
|
case 'javascript': {
|
|
303
305
|
await loadScript('npm/eslint-linter-browserify', 'eslint');
|
|
@@ -434,11 +436,39 @@ export class CodeMirror6 {
|
|
|
434
436
|
*/
|
|
435
437
|
toggle(show = !this.#visible): void {
|
|
436
438
|
if (show && !this.#visible) {
|
|
437
|
-
this
|
|
439
|
+
const {value, selectionStart, selectionEnd, scrollTop} = this.#textarea,
|
|
440
|
+
hasFocus = document.activeElement === this.#textarea;
|
|
441
|
+
this.setContent(value);
|
|
438
442
|
this.#refresh();
|
|
443
|
+
this.#view.dom.style.setProperty('display', '');
|
|
444
|
+
this.#textarea.style.display = 'none';
|
|
445
|
+
this.#view.requestMeasure();
|
|
446
|
+
this.#view.dispatch({
|
|
447
|
+
selection: {anchor: selectionStart, head: selectionEnd},
|
|
448
|
+
});
|
|
449
|
+
if (hasFocus) {
|
|
450
|
+
this.#view.focus();
|
|
451
|
+
}
|
|
452
|
+
requestAnimationFrame(() => {
|
|
453
|
+
this.#view.scrollDOM.scrollTop = scrollTop;
|
|
454
|
+
});
|
|
455
|
+
} else if (!show && this.#visible) {
|
|
456
|
+
const {state: {selection: {main: {from, to}}}, hasFocus} = this.#view,
|
|
457
|
+
{scrollDOM: {scrollTop}} = this.#view;
|
|
458
|
+
this.#view.dom.style.setProperty('display', 'none', 'important');
|
|
459
|
+
this.#textarea.style.display = '';
|
|
460
|
+
this.#textarea.setSelectionRange(
|
|
461
|
+
Math.min(from, to),
|
|
462
|
+
Math.max(from, to),
|
|
463
|
+
from > to ? 'backward' : 'forward',
|
|
464
|
+
);
|
|
465
|
+
if (hasFocus) {
|
|
466
|
+
this.#textarea.focus();
|
|
467
|
+
}
|
|
468
|
+
requestAnimationFrame(() => {
|
|
469
|
+
this.#textarea.scrollTop = scrollTop;
|
|
470
|
+
});
|
|
439
471
|
}
|
|
440
472
|
this.#visible = show;
|
|
441
|
-
this.#view.dom.style.setProperty('display', show ? '' : 'none', 'important');
|
|
442
|
-
this.#textarea.style.display = show ? 'none' : '';
|
|
443
473
|
}
|
|
444
474
|
}
|
package/src/mediawiki.ts
CHANGED
|
@@ -951,7 +951,7 @@ class MediaWiki {
|
|
|
951
951
|
const isCloseTag = Boolean(stream.eat('/')),
|
|
952
952
|
mt = stream.match(/^[^>/\s.*,[\]{}$^+?|\\'`~<=!@#%&()-]+/u) as RegExpMatchArray | false;
|
|
953
953
|
if (mt) {
|
|
954
|
-
const tagname = mt[0]
|
|
954
|
+
const tagname = mt[0].toLowerCase();
|
|
955
955
|
if (tagname in this.config.tags) {
|
|
956
956
|
// Parser function
|
|
957
957
|
state.stack.push(state.tokenize);
|
package/mw/dist/base.js
DELETED
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { CodeMirror6 } from 'https://testingcf.jsdelivr.net/npm/@bhsd/codemirror-mediawiki@2.1.11/dist/main.min.js';
|
|
2
|
-
(() => {
|
|
3
|
-
var _a;
|
|
4
|
-
mw.loader.load('https://testingcf.jsdelivr.net/npm/@bhsd/codemirror-mediawiki@2.1.11/mediawiki.min.css', 'text/css');
|
|
5
|
-
mw.loader.addStyleTag('.wikiEditor-ui-toolbar{z-index:7}');
|
|
6
|
-
const instances = new WeakMap();
|
|
7
|
-
const getInstance = ($ele) => instances.get($ele[0]);
|
|
8
|
-
$.valHooks['textarea'] = {
|
|
9
|
-
get(elem) {
|
|
10
|
-
const cm = instances.get(elem);
|
|
11
|
-
return (cm === null || cm === void 0 ? void 0 : cm.visible) ? cm.view.state.doc.toString() : elem.value;
|
|
12
|
-
},
|
|
13
|
-
set(elem, value) {
|
|
14
|
-
const cm = instances.get(elem);
|
|
15
|
-
if (cm === null || cm === void 0 ? void 0 : cm.visible) {
|
|
16
|
-
cm.setContent(value);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
elem.value = value;
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
function getCaretPosition(option) {
|
|
24
|
-
const { view: { state: { selection: { main } } } } = getInstance(this);
|
|
25
|
-
return (option === null || option === void 0 ? void 0 : option.startAndEnd) ? [main.from, main.to] : main.head;
|
|
26
|
-
}
|
|
27
|
-
const textSelection = {
|
|
28
|
-
getContents() {
|
|
29
|
-
return getInstance(this).view.state.doc.toString();
|
|
30
|
-
},
|
|
31
|
-
setContents(content) {
|
|
32
|
-
getInstance(this).setContent(content);
|
|
33
|
-
return this;
|
|
34
|
-
},
|
|
35
|
-
getSelection() {
|
|
36
|
-
const { view: { state } } = getInstance(this);
|
|
37
|
-
return state.sliceDoc(state.selection.main.from, state.selection.main.to);
|
|
38
|
-
},
|
|
39
|
-
setSelection({ start, end }) {
|
|
40
|
-
const { view } = getInstance(this);
|
|
41
|
-
view.dispatch({
|
|
42
|
-
selection: { anchor: start, head: end !== null && end !== void 0 ? end : start },
|
|
43
|
-
});
|
|
44
|
-
view.focus();
|
|
45
|
-
return this;
|
|
46
|
-
},
|
|
47
|
-
replaceSelection(value) {
|
|
48
|
-
const { view } = getInstance(this);
|
|
49
|
-
view.dispatch(view.state.replaceSelection(value));
|
|
50
|
-
return this;
|
|
51
|
-
},
|
|
52
|
-
getCaretPosition,
|
|
53
|
-
scrollToCaretPosition() {
|
|
54
|
-
getInstance(this).view.dispatch({ scrollIntoView: true });
|
|
55
|
-
return this;
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
const USING_LOCAL = mw.loader.getState('ext.CodeMirror') !== null, DATA_MODULE = mw.loader.getState('ext.CodeMirror.data') ? 'ext.CodeMirror.data' : 'ext.CodeMirror', ALL_SETTINGS_CACHE = (_a = JSON.parse(localStorage.getItem('InPageEditMwConfig'))) !== null && _a !== void 0 ? _a : {}, SITE_ID = `${mw.config.get('wgServerName')}${mw.config.get('wgScriptPath')}`, SITE_SETTINGS = ALL_SETTINGS_CACHE[SITE_ID], VALID = Number(SITE_SETTINGS === null || SITE_SETTINGS === void 0 ? void 0 : SITE_SETTINGS.time) > Date.now() - 86400 * 1000 * 30;
|
|
59
|
-
const getConfig = (magicWords, rule, flip) => {
|
|
60
|
-
const words = magicWords.filter(rule).filter(({ 'case-sensitive': i }) => i !== flip)
|
|
61
|
-
.flatMap(({ aliases, name, 'case-sensitive': i }) => aliases.map(alias => ({
|
|
62
|
-
alias: (i ? alias : alias.toLowerCase()).replace(/:$/u, ''),
|
|
63
|
-
name,
|
|
64
|
-
}))), obj = {};
|
|
65
|
-
for (const { alias, name } of words) {
|
|
66
|
-
obj[alias] = name;
|
|
67
|
-
}
|
|
68
|
-
return obj;
|
|
69
|
-
};
|
|
70
|
-
const getConfigPair = (magicWords, rule) => [true, false]
|
|
71
|
-
.map(bool => getConfig(magicWords, rule, bool));
|
|
72
|
-
const setConfig = (config) => {
|
|
73
|
-
mw.config.set('extCodeMirrorConfig', config);
|
|
74
|
-
};
|
|
75
|
-
const getMwConfig = async () => {
|
|
76
|
-
if (USING_LOCAL && !VALID) {
|
|
77
|
-
await mw.loader.using(DATA_MODULE);
|
|
78
|
-
}
|
|
79
|
-
let config = mw.config.get('extCodeMirrorConfig');
|
|
80
|
-
if (!config && VALID) {
|
|
81
|
-
({ config } = SITE_SETTINGS);
|
|
82
|
-
setConfig(config);
|
|
83
|
-
}
|
|
84
|
-
const isIPE = config && Object.values(config.functionSynonyms[0]).includes(true);
|
|
85
|
-
if ((config === null || config === void 0 ? void 0 : config.img) && config.variants && !isIPE) {
|
|
86
|
-
return {
|
|
87
|
-
...config,
|
|
88
|
-
nsid: mw.config.get('wgNamespaceIds'),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
const { query: { general: { variants }, magicwords, extensiontags, functionhooks, variables }, } = await new mw.Api().get({
|
|
92
|
-
meta: 'siteinfo',
|
|
93
|
-
siprop: [
|
|
94
|
-
'general',
|
|
95
|
-
'magicwords',
|
|
96
|
-
...config && !isIPE ? [] : ['extensiontags', 'functionhooks', 'variables'],
|
|
97
|
-
],
|
|
98
|
-
formatversion: '2',
|
|
99
|
-
});
|
|
100
|
-
const others = new Set(['msg', 'raw', 'msgnw', 'subst', 'safesubst']);
|
|
101
|
-
if (config && !isIPE) {
|
|
102
|
-
const { functionSynonyms: [insensitive] } = config;
|
|
103
|
-
if (!('subst' in insensitive)) {
|
|
104
|
-
Object.assign(insensitive, getConfig(magicwords, ({ name }) => others.has(name)));
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
config = {
|
|
109
|
-
tagModes: {
|
|
110
|
-
tab: 'text/mediawiki',
|
|
111
|
-
indicator: 'text/mediawiki',
|
|
112
|
-
poem: 'text/mediawiki',
|
|
113
|
-
ref: 'text/mediawiki',
|
|
114
|
-
option: 'text/mediawiki',
|
|
115
|
-
combooption: 'text/mediawiki',
|
|
116
|
-
tabs: 'text/mediawiki',
|
|
117
|
-
poll: 'text/mediawiki',
|
|
118
|
-
gallery: 'text/mediawiki',
|
|
119
|
-
},
|
|
120
|
-
tags: {},
|
|
121
|
-
urlProtocols: mw.config.get('wgUrlProtocols'),
|
|
122
|
-
};
|
|
123
|
-
for (const tag of extensiontags) {
|
|
124
|
-
config.tags[tag.slice(1, -1)] = true;
|
|
125
|
-
}
|
|
126
|
-
const functions = new Set([
|
|
127
|
-
...functionhooks,
|
|
128
|
-
...variables,
|
|
129
|
-
...others,
|
|
130
|
-
]);
|
|
131
|
-
config.functionSynonyms = getConfigPair(magicwords, ({ name }) => functions.has(name));
|
|
132
|
-
config.doubleUnderscore = getConfigPair(magicwords, ({ aliases }) => aliases.some(alias => /^__.+__$/u.test(alias)));
|
|
133
|
-
}
|
|
134
|
-
config.img = getConfig(magicwords, ({ name }) => name.startsWith('img_'));
|
|
135
|
-
config.variants = variants ? variants.map(({ code }) => code) : [];
|
|
136
|
-
config.nsid = mw.config.get('wgNamespaceIds');
|
|
137
|
-
setConfig(config);
|
|
138
|
-
ALL_SETTINGS_CACHE[SITE_ID] = { config: config, time: Date.now() };
|
|
139
|
-
localStorage.setItem('InPageEditMwConfig', JSON.stringify(ALL_SETTINGS_CACHE));
|
|
140
|
-
return config;
|
|
141
|
-
};
|
|
142
|
-
const linters = {};
|
|
143
|
-
class CodeMirror extends CodeMirror6 {
|
|
144
|
-
constructor(textarea, lang, config) {
|
|
145
|
-
super(textarea, lang, config);
|
|
146
|
-
instances.set(textarea, this);
|
|
147
|
-
if (mw.loader.getState('jquery.textSelection') === 'ready') {
|
|
148
|
-
$(textarea).data('jquery.textSelection', textSelection);
|
|
149
|
-
}
|
|
150
|
-
mw.hook('wiki-codemirror6').fire(this);
|
|
151
|
-
}
|
|
152
|
-
toggle(show = !this.visible) {
|
|
153
|
-
super.toggle(show);
|
|
154
|
-
$(this.textarea).data('jquery.textSelection', show && textSelection);
|
|
155
|
-
}
|
|
156
|
-
async getLinter(opt) {
|
|
157
|
-
const linter = await super.getLinter(opt);
|
|
158
|
-
linters[this.lang] = linter;
|
|
159
|
-
return linter;
|
|
160
|
-
}
|
|
161
|
-
async defaultLint(on, optOrNs) {
|
|
162
|
-
if (!on) {
|
|
163
|
-
this.lint();
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
const { lang } = this;
|
|
167
|
-
let opt;
|
|
168
|
-
if (typeof optOrNs === 'number') {
|
|
169
|
-
if (lang === 'mediawiki' && (optOrNs === 10 || optOrNs === 828 || optOrNs === 2)) {
|
|
170
|
-
opt = { include: true };
|
|
171
|
-
}
|
|
172
|
-
else if (lang === 'javascript' && (optOrNs === 8 || optOrNs === 2300)) {
|
|
173
|
-
opt = {
|
|
174
|
-
env: { browser: true, es6: true },
|
|
175
|
-
parserOptions: { ecmaVersion: 6 },
|
|
176
|
-
};
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
opt = optOrNs;
|
|
181
|
-
}
|
|
182
|
-
if (!(lang in linters)) {
|
|
183
|
-
await this.getLinter(opt);
|
|
184
|
-
if (lang === 'mediawiki') {
|
|
185
|
-
const mwConfig = await getMwConfig(), config = {
|
|
186
|
-
...await wikiparse.getConfig(),
|
|
187
|
-
ext: Object.keys(mwConfig.tags),
|
|
188
|
-
namespaces: mw.config.get('wgFormattedNamespaces'),
|
|
189
|
-
nsid: mwConfig.nsid,
|
|
190
|
-
doubleUnderscore: mwConfig.doubleUnderscore.map(obj => Object.keys(obj).map(s => s.slice(2, -2))),
|
|
191
|
-
variants: mwConfig.variants,
|
|
192
|
-
protocol: mwConfig.urlProtocols.replace(/\\:/gu, ':'),
|
|
193
|
-
};
|
|
194
|
-
[config.parserFunction[0]] = mwConfig.functionSynonyms;
|
|
195
|
-
if (!USING_LOCAL) {
|
|
196
|
-
for (const [key, val] of Object.entries(mwConfig.functionSynonyms[0])) {
|
|
197
|
-
if (!key.startsWith('#')) {
|
|
198
|
-
config.parserFunction[0][`#${key}`] = val;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
config.parserFunction[1] = [
|
|
203
|
-
...Object.keys(mwConfig.functionSynonyms[1]),
|
|
204
|
-
'=',
|
|
205
|
-
];
|
|
206
|
-
for (const key of Object.keys(mwConfig.img)) {
|
|
207
|
-
config.img[key] = mwConfig.img[key].slice(4);
|
|
208
|
-
}
|
|
209
|
-
wikiparse.setConfig(config);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
else if (opt) {
|
|
213
|
-
await this.getLinter(opt);
|
|
214
|
-
}
|
|
215
|
-
if (linters[lang]) {
|
|
216
|
-
this.lint(linters[lang]);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
static async fromTextArea(textarea, lang) {
|
|
220
|
-
const isWiki = lang === 'mediawiki' || lang === 'html', cm = new CodeMirror(textarea, isWiki ? undefined : lang);
|
|
221
|
-
if (isWiki) {
|
|
222
|
-
const config = await getMwConfig();
|
|
223
|
-
cm.setLanguage(lang, config);
|
|
224
|
-
}
|
|
225
|
-
return cm;
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
document.body.addEventListener('click', e => {
|
|
229
|
-
if (e.target instanceof HTMLTextAreaElement && e.shiftKey && !instances.has(e.target)) {
|
|
230
|
-
e.preventDefault();
|
|
231
|
-
(async () => {
|
|
232
|
-
var _a;
|
|
233
|
-
const { wgAction, wgNamespaceNumber, wgPageContentModel } = mw.config.get();
|
|
234
|
-
let lang;
|
|
235
|
-
if (wgAction !== 'edit' && wgAction !== 'submit') {
|
|
236
|
-
await mw.loader.using('oojs-ui-windows');
|
|
237
|
-
lang = (_a = (await OO.ui.prompt('Language:') || undefined)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
238
|
-
}
|
|
239
|
-
else {
|
|
240
|
-
switch (wgPageContentModel) {
|
|
241
|
-
case 'css':
|
|
242
|
-
case 'sanitized-css':
|
|
243
|
-
lang = 'css';
|
|
244
|
-
break;
|
|
245
|
-
case 'javascript':
|
|
246
|
-
lang = 'javascript';
|
|
247
|
-
break;
|
|
248
|
-
case 'json':
|
|
249
|
-
lang = 'json';
|
|
250
|
-
break;
|
|
251
|
-
case 'Scribunto':
|
|
252
|
-
lang = 'lua';
|
|
253
|
-
break;
|
|
254
|
-
case 'wikitext':
|
|
255
|
-
lang = wgNamespaceNumber === 274 ? 'html' : 'mediawiki';
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
const cm = await CodeMirror.fromTextArea(e.target, lang);
|
|
260
|
-
void cm.defaultLint(true, wgNamespaceNumber);
|
|
261
|
-
})();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
Object.assign(window, { CodeMirror6: CodeMirror });
|
|
265
|
-
})();
|