416 lines
21 KiB
JavaScript
416 lines
21 KiB
JavaScript
// @see https://microsoft.github.io/monaco-editor/playground.html#interacting-with-the-editor-adding-an-action-to-an-editor-instance
|
|
(function(){
|
|
|
|
let init = function() {
|
|
let MediaWikiTokenizer = (function () {
|
|
function MediaWikiTokenizer() {
|
|
this.ignorecase = true;
|
|
this.empty = [
|
|
'area', 'base', 'basefont', 'br', 'col', 'frame',
|
|
'hr', 'img', 'input', 'isindex', 'link', 'meta', 'param'
|
|
];
|
|
// escape codes for javascript/CSS strings
|
|
this.escapes = /\\(?:[btnfr\\"']|[0-7][0-7]?|[0-3][0-7]{2})/;
|
|
this.tokenizer = {
|
|
root: [
|
|
{ include: '@whitespace' },
|
|
|
|
// Link reference
|
|
[/\[\[/, { token: 'string.quote', bracket: '@open', next: '@linkReferenceBlock' }],
|
|
|
|
// Template usage
|
|
[/{{/, { token: 'type.type-$1', bracket: '@open', next: '@templateBlock.$1' }],
|
|
[/}}/, { token: 'type.type-$1', bracket: '@close' }],
|
|
|
|
// Bold
|
|
[/'''/, { token: 'bold.quote', bracket: '@open', next: '@boldBlock' }],
|
|
|
|
// Italic
|
|
[/''/, { token: 'italic.quote', bracket: '@open', next: '@italicBlock' }],
|
|
|
|
// HTML-Style blocks
|
|
[/<(\w+)\/>/, 'tag.tag-$1'],
|
|
[/<(\w+)/, {
|
|
cases: {
|
|
'@empty': { token: 'tag.tag-$1', next: '@tag.$1', log: 'Push stack to tag.$1' },
|
|
'@default': { token: 'tag.tag-$1', bracket: '@open', next: '@tag.$1', log: 'Push stack to tag.$1, bracket open' }
|
|
}
|
|
}],
|
|
[/<\/(\w+)\s*>/, { token: 'tag.tag-$1', bracket: '@close', log: 'Close bracket of tag.$1' }],
|
|
[/&\w+;/, 'string.escape']
|
|
],
|
|
boldBlock: [
|
|
[/'''/, { token: 'bold.quote', bracket: '@close', next: '@pop' }],
|
|
[/[^''']+/, { token: 'bold' }],
|
|
// Nested italic + bold, need a style to present both
|
|
[/''/, { token: "italic.quote", bracket: "@open", next: "@italicBlock" }]
|
|
],
|
|
italicBlock: [
|
|
[/''/, { token: "italic.quote", bracket: "@close", next: "@pop" }],
|
|
[/[^'']+/, { token: "italic" }]
|
|
],
|
|
linkReferenceBlock: [
|
|
[/\]\]/, { token: "string.quote", bracket: "@close", next: "@pop" }],
|
|
[/[^\]\]]+/, { token: "string" }]
|
|
],
|
|
templateBlock: [
|
|
[/{{/, { token: 'type.type-$1', bracket: '@open', next: '@templateBlock.$1' }],
|
|
[/}}/, { token: 'type.type-$2', next: '@pop' }],
|
|
[/\[\[/, { token: 'string.quote', bracket: '@open', next: '@linkReferenceBlock' }],
|
|
[/'''/, { token: 'bold.quote', bracket: '@open', next: '@boldBlock' }],
|
|
[/''/, { token: 'italic.quote', bracket: '@open', next: '@italicBlock' }]
|
|
],
|
|
// Tags
|
|
tag: [
|
|
[/[ \t\r\n]+/, 'white'],
|
|
[/(type)(\s*=\s*)(")([^"]+)(")/, ['attribute.name', 'delimiter', 'attribute.value',
|
|
{ token: 'attribute.value', switchTo: '@tag.$S2.$4' },
|
|
'attribute.value']],
|
|
[/(type)(\s*=\s*)(')([^']+)(')/, ['attribute.name', 'delimiter', 'attribute.value',
|
|
{ token: 'attribute.value', switchTo: '@tag.$S2.$4' },
|
|
'attribute.value']],
|
|
[/(\w+)(\s*=\s*)("[^"]*"|'[^']*')/, ['attribute.name', 'delimiter', 'attribute.value']],
|
|
[/\w+/, 'attribute.name'],
|
|
[/\/>/, 'tag.tag-$S2', '@pop'],
|
|
[/>/, {
|
|
cases: {
|
|
'$S2==style': { token: 'tag.tag-$S2', switchTo: '@inlineStyle.$S2', nextEmbedded: 'text/css', log: 'Entering CSS section ($S2)' },
|
|
'$S2==script': {
|
|
cases: {
|
|
'$S3': { token: 'tag.tag-$S2', switchTo: '@inlineScript.$S2', nextEmbedded: '$S3' },
|
|
'@default': { token: 'tag.tag-$S2', switchTo: '@inlineScript.$S2', nextEmbedded: 'javascript', log: 'Entering JS section ($S2)' }
|
|
}
|
|
},
|
|
'@default': { token: 'tag.tag-$S2', next: '@pop', log: 'Entering $S2 section' }
|
|
}
|
|
}],
|
|
],
|
|
inlineStyle: [
|
|
[/<\/style\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop', log: 'Pop stack ($S2)' }]
|
|
],
|
|
inlineScript: [
|
|
[/<\/script\s*>/, { token: '@rematch', next: '@pop', nextEmbedded: '@pop', log: 'Pop stack ($S2)' }]
|
|
],
|
|
// scan embedded strings in javascript or css
|
|
// string.<delimiter>
|
|
string: [
|
|
[/[^\\"']+/, 'string'],
|
|
[/@escapes/, 'string.escape'],
|
|
[/\\./, 'string.escape.invalid'],
|
|
[/["']/, {
|
|
cases: {
|
|
'$#==$S2': { token: 'string', next: '@pop' },
|
|
'@default': 'string'
|
|
}
|
|
}]
|
|
],
|
|
whitespace: [
|
|
[/[ \t\r\n]+/, 'white'],
|
|
[/<!--/, 'comment', '@comment']
|
|
],
|
|
comment: [
|
|
[/[^<\-]+/, 'comment.content'],
|
|
[/-->/, 'comment', '@pop'],
|
|
[/<!--/, 'comment.content.invalid'],
|
|
[/[<\-]/, 'comment.content']
|
|
]
|
|
};
|
|
this.tokenPostfix = "";
|
|
}
|
|
return MediaWikiTokenizer;
|
|
}());
|
|
|
|
window.require.config({ paths: { 'vs': '/extensions/MonacoEditor/node_modules/monaco-editor/min/vs' }});
|
|
window.require(['vs/editor/editor.main'], function() {
|
|
let el_stock_editor = document.getElementById("wpTextbox1");
|
|
el_stock_editor.style.display = "none";
|
|
// Register a new language
|
|
monaco.languages.register({ id: 'wikitext' });
|
|
|
|
// Register a tokens provider for the language
|
|
monaco.languages.setMonarchTokensProvider('wikitext', new MediaWikiTokenizer());
|
|
|
|
// Register a completion item provider for the new language
|
|
monaco.languages.registerCompletionItemProvider('wikitext', {
|
|
provideCompletionItems: () => {
|
|
var suggestions = [{
|
|
label: 'syntax',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<syntaxhighlight lang="$1">',
|
|
'$2',
|
|
'</syntaxhighlight>'
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'syntax inline',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<syntaxhighlight lang="$1" inline>$2</syntaxhighlight>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'code',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<code>$1</code>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'poem',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<poem>$1</poem>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'bullet list',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'* $1',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'numbered list',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'# $1',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'bold',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
"'''$1'''",
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'italic',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
"''$1''",
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'heading 1',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
"= $1 =",
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'heading 2',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'== $1 ==',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'heading 3',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'=== $1 ===',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'heading 4',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'==== $1 ====',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'heading 5',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'===== $1 =====',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'heading 6',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'====== $1 ======',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'category',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'[[Category:$1]]',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'internal link',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'[[$1]]',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'external link',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'[$1 $2]',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'comment',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<!--',
|
|
'$1',
|
|
'-->',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'inline comment',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<!-- $1 -->',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'template',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'{{$1}}',
|
|
''
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'chunk: references',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'== References ==',
|
|
'{{Reflist}}',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'reference',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<ref>$1</ref>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'reference internal link',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<ref>[[$1]]</ref>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'reference external link',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<ref>[$1 $2]</ref>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'expanded quote',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'{{Quote | $1 | $2 | $3}}',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'quote',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'{{Quote | $1 || $2}}',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'expandable content',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'{{Expandable content | $1}}',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'nowiki',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'<nowiki>$1</nowiki>',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'horizontal rule',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'----',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}, {
|
|
label: 'related article',
|
|
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
insertText: [
|
|
'{{#related:$1}}',
|
|
].join('\n'),
|
|
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
}];
|
|
return { suggestions: suggestions };
|
|
}
|
|
});
|
|
|
|
let language = 'wikitext';
|
|
if (typeof RLCONF.wgPageContentModel !== 'undefined') {
|
|
switch (RLCONF.wgPageContentModel) {
|
|
case 'css':
|
|
language = 'css';
|
|
break;
|
|
case 'javascript':
|
|
language = 'javascript';
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Create new editor
|
|
let monaco_editor_container = document.createElement('div');
|
|
monaco_editor_container.id = 'monaco-editor'
|
|
monaco_editor_container.style["min-height"] = '35em';
|
|
monaco_editor_container.style["max-height"] = '100vh';
|
|
el_stock_editor.after(monaco_editor_container);
|
|
|
|
window.monaco_editor = monaco.editor.create(document.getElementById('monaco-editor'), {
|
|
value: el_stock_editor.value,
|
|
scrollBeyondLastLine: false,
|
|
wordWrap: 'on',
|
|
fontSize: '13px',
|
|
language: language,
|
|
// theme: "vs-dark",
|
|
});
|
|
|
|
// On preview
|
|
let el_btn_preview = document.querySelector('#wpPreview');
|
|
el_btn_preview.addEventListener('click', event => {
|
|
el_stock_editor.value = window.monaco_editor.getValue();
|
|
});
|
|
|
|
// On save
|
|
let el_btn_save = document.querySelector('#wpSave');
|
|
el_btn_save.addEventListener('click', event => {
|
|
el_stock_editor.value = window.monaco_editor.getValue();
|
|
});
|
|
});
|
|
};
|
|
|
|
function initializer() {
|
|
if (typeof window.require !== 'undefined') {
|
|
init();
|
|
} else {
|
|
setTimeout(initializer, 20);
|
|
}
|
|
}
|
|
initializer();
|
|
})(); |