diff --git a/.eslintrc.json b/.eslintrc.json
new file mode 100644
index 00000000..40f6bcfa
--- /dev/null
+++ b/.eslintrc.json
@@ -0,0 +1,15 @@
+{
+ "extends": "wikimedia",
+ "env": {
+ "browser": true,
+ "jquery": true,
+ "qunit": true
+ },
+ "globals": {
+ "mediaWiki": false,
+ "CodeMirror": false
+ },
+ "rules": {
+ "dot-notation": [ "error", { "allowKeywords": true } ]
+ }
+}
diff --git a/.jscsrc b/.jscsrc
deleted file mode 100644
index 83457a7c..00000000
--- a/.jscsrc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "preset": "wikimedia",
- "requireVarDeclFirst": null,
- "requireMultipleVarDecl": null,
- "disallowEmptyBlocks": null
-}
diff --git a/.jshintignore b/.jshintignore
deleted file mode 100644
index 1fc3c970..00000000
--- a/.jshintignore
+++ /dev/null
@@ -1,4 +0,0 @@
-node_modules
-vendor
-# upstream libs
-resources/lib/
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index d980a037..00000000
--- a/.jshintrc
+++ /dev/null
@@ -1,25 +0,0 @@
-{
- // Enforcing
- "bitwise": true,
- "eqeqeq": true,
- "freeze": true,
- "latedef": true,
- "noarg": true,
- "nonew": true,
- "undef": true,
- "unused": true,
- "strict": false,
-
- // Relaxing
- "es5": false,
-
- // Environment
- "browser": true,
- "jquery": true,
-
- "globals": {
- "mediaWiki": false,
- "CodeMirror": false,
- "mod": false
- }
-}
diff --git a/.stylelintrc b/.stylelintrc
new file mode 100644
index 00000000..2c907302
--- /dev/null
+++ b/.stylelintrc
@@ -0,0 +1,3 @@
+{
+ "extends": "stylelint-config-wikimedia"
+}
diff --git a/Gruntfile.js b/Gruntfile.js
index c4b1daa8..4a474d8a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1,23 +1,24 @@
-/*jshint node:true */
+/* eslint-env node, es6 */
module.exports = function ( grunt ) {
- grunt.loadNpmTasks( 'grunt-contrib-jshint' );
- grunt.loadNpmTasks( 'grunt-jsonlint' );
grunt.loadNpmTasks( 'grunt-banana-checker' );
- grunt.loadNpmTasks( 'grunt-jscs' );
+ grunt.loadNpmTasks( 'grunt-eslint' );
+ grunt.loadNpmTasks( 'grunt-jsonlint' );
+ grunt.loadNpmTasks( 'grunt-stylelint' );
grunt.initConfig( {
- jshint: {
- options: {
- jshintrc: true
- },
+ eslint: {
all: [
'**/*.js',
'!resources/lib/**',
'!node_modules/**'
]
},
- jscs: {
- src: '<%= jshint.all %>'
+ stylelint: {
+ all: [
+ '**/*.css',
+ '!resources/lib/**',
+ '!node_modules/**'
+ ]
},
banana: {
all: 'i18n/'
@@ -30,6 +31,6 @@ module.exports = function ( grunt ) {
}
} );
- grunt.registerTask( 'test', [ 'jshint', 'jscs', 'jsonlint', 'banana' ] );
+ grunt.registerTask( 'test', [ 'eslint', 'stylelint', 'jsonlint', 'banana' ] );
grunt.registerTask( 'default', 'test' );
};
diff --git a/package.json b/package.json
index 8a4e5f3b..629b866a 100644
--- a/package.json
+++ b/package.json
@@ -3,11 +3,12 @@
"test": "grunt test"
},
"devDependencies": {
- "grunt": "0.4.5",
- "grunt-cli": "0.1.13",
- "grunt-contrib-jshint": "0.11.3",
- "grunt-banana-checker": "0.4.0",
- "grunt-jscs": "2.5.0",
- "grunt-jsonlint": "1.0.7"
+ "eslint-config-wikimedia": "0.3.0",
+ "grunt": "1.0.1",
+ "grunt-banana-checker": "0.5.0",
+ "grunt-eslint": "19.0.0",
+ "grunt-jsonlint": "1.1.0",
+ "grunt-stylelint": "0.7.0",
+ "stylelint-config-wikimedia": "0.4.1"
}
}
diff --git a/resources/ext.CodeMirror.js b/resources/ext.CodeMirror.js
index ca5ae36d..9c4a9dfa 100644
--- a/resources/ext.CodeMirror.js
+++ b/resources/ext.CodeMirror.js
@@ -1,248 +1,272 @@
( function ( mw, $ ) {
+ var origTextSelection, codeMirror, api, originHooksTextarea;
+
if ( mw.config.get( 'wgCodeEditorCurrentLanguage' ) ) { // If the CodeEditor is used then just exit;
return;
}
// codeMirror needs a special textselection jQuery function to work, save the current one to restore when
// CodeMirror get's disabled.
- var origTextSelection = $.fn.textSelection,
- codeMirror = mw.user.options.get( 'usecodemirror' ) === '1' || mw.user.options.get( 'usecodemirror' ) === 1,
- api = new mw.Api(),
- // function for a textselection function for CodeMirror
- cmTextSelection = function ( command, options ) {
- if ( !codeMirror || codeMirror.getTextArea() !== this[ 0 ] ) {
- return origTextSelection.call( this, command, options );
- }
- var fn, retval;
+ origTextSelection = $.fn.textSelection;
+ codeMirror = mw.user.options.get( 'usecodemirror' ) === '1' || mw.user.options.get( 'usecodemirror' ) === 1;
+ api = new mw.Api();
+ originHooksTextarea = $.valHooks.textarea;
- fn = {
- /**
- * Get the contents of the textarea
- */
- getContents: function () {
- return codeMirror.doc.getValue();
- },
+ // function for a textselection function for CodeMirror
+ function cmTextSelection( command, options ) {
+ var fn, retval;
- setContents: function ( newContents ) {
- codeMirror.doc.setValue( newContents );
- },
+ if ( !codeMirror || codeMirror.getTextArea() !== this[ 0 ] ) {
+ return origTextSelection.call( this, command, options );
+ }
- /**
- * Get the currently selected text in this textarea. Will focus the textarea
- * in some browsers (IE/Opera)
- */
- getSelection: function () {
- return codeMirror.doc.getSelection();
- },
+ fn = {
+ /**
+ * Get the contents of the textarea
+ *
+ * @return {string}
+ */
+ getContents: function () {
+ return codeMirror.doc.getValue();
+ },
- /**
- * Inserts text at the beginning and end of a text selection, optionally
- * inserting text at the caret when selection is empty.
- */
- encapsulateSelection: function ( options ) {
- return this.each( function () {
- var insertText,
- selText,
- selectPeri = options.selectPeri,
- pre = options.pre,
- post = options.post,
- startCursor = codeMirror.doc.getCursor( true ),
- endCursor = codeMirror.doc.getCursor( false );
+ setContents: function ( newContents ) {
+ codeMirror.doc.setValue( newContents );
+ },
- if ( options.selectionStart !== undefined ) {
- // fn[command].call( this, options );
- fn.setSelection( { start: options.selectionStart, end: options.selectionEnd } ); // not tested
+ /**
+ * Get the currently selected text in this textarea. Will focus the textarea
+ * in some browsers (IE/Opera)
+ *
+ * @return {string}
+ */
+ getSelection: function () {
+ return codeMirror.doc.getSelection();
+ },
+
+ /**
+ * Inserts text at the beginning and end of a text selection, optionally
+ * inserting text at the caret when selection is empty.
+ *
+ * @param {Object} options
+ * @return {jQuery}
+ */
+ encapsulateSelection: function ( options ) {
+ return this.each( function () {
+ var insertText,
+ selText,
+ selectPeri = options.selectPeri,
+ pre = options.pre,
+ post = options.post,
+ startCursor = codeMirror.doc.getCursor( true ),
+ endCursor = codeMirror.doc.getCursor( false );
+
+ if ( options.selectionStart !== undefined ) {
+ // fn[command].call( this, options );
+ fn.setSelection( { start: options.selectionStart, end: options.selectionEnd } ); // not tested
+ }
+
+ selText = codeMirror.doc.getSelection();
+ if ( !selText ) {
+ selText = options.peri;
+ } else if ( options.replace ) {
+ selectPeri = false;
+ selText = options.peri;
+ } else {
+ selectPeri = false;
+ while ( selText.charAt( selText.length - 1 ) === ' ' ) {
+ // Exclude ending space char
+ selText = selText.substring( 0, selText.length - 1 );
+ post += ' ';
}
-
- selText = codeMirror.doc.getSelection();
- if ( !selText ) {
- selText = options.peri;
- } else if ( options.replace ) {
- selectPeri = false;
- selText = options.peri;
- } else {
- selectPeri = false;
- while ( selText.charAt( selText.length - 1 ) === ' ' ) {
- // Exclude ending space char
- selText = selText.substring( 0, selText.length - 1 );
- post += ' ';
- }
- while ( selText.charAt( 0 ) === ' ' ) {
- // Exclude prepending space char
- selText = selText.substring( 1, selText.length );
- pre = ' ' + pre;
- }
+ while ( selText.charAt( 0 ) === ' ' ) {
+ // Exclude prepending space char
+ selText = selText.substring( 1, selText.length );
+ pre = ' ' + pre;
}
+ }
- /**
- * Do the splitlines stuff.
- *
- * Wrap each line of the selected text with pre and post
- */
- function doSplitLines( selText, pre, post ) {
- var i,
- insertText = '',
- selTextArr = selText.split( '\n' );
+ /**
+ * Do the splitlines stuff.
+ *
+ * Wrap each line of the selected text with pre and post
+ *
+ * @param {string} selText
+ * @param {string} pre
+ * @param {string} post
+ * @return {string}
+ */
+ function doSplitLines( selText, pre, post ) {
+ var i,
+ insertText = '',
+ selTextArr = selText.split( '\n' );
- for ( i = 0; i < selTextArr.length; i++ ) {
- insertText += pre + selTextArr[ i ] + post;
- if ( i !== selTextArr.length - 1 ) {
- insertText += '\n';
- }
- }
- return insertText;
- }
-
- if ( options.splitlines ) {
- selectPeri = false;
- insertText = doSplitLines( selText, pre, post );
- } else {
- insertText = pre + selText + post;
- }
-
- if ( options.ownline ) {
- if ( startCursor.ch !== 0 ) {
- insertText = '\n' + insertText;
- pre += '\n';
- }
-
- if ( codeMirror.doc.getLine( endCursor.line ).length !== endCursor.ch ) {
+ for ( i = 0; i < selTextArr.length; i++ ) {
+ insertText += pre + selTextArr[ i ] + post;
+ if ( i !== selTextArr.length - 1 ) {
insertText += '\n';
- post += '\n';
}
}
+ return insertText;
+ }
- codeMirror.doc.replaceSelection( insertText );
+ if ( options.splitlines ) {
+ selectPeri = false;
+ insertText = doSplitLines( selText, pre, post );
+ } else {
+ insertText = pre + selText + post;
+ }
- if ( selectPeri ) {
- codeMirror.doc.setSelection(
- codeMirror.doc.posFromIndex( codeMirror.doc.indexFromPos( startCursor ) + pre.length ),
- codeMirror.doc.posFromIndex( codeMirror.doc.indexFromPos( startCursor ) + pre.length + selText.length )
- );
+ if ( options.ownline ) {
+ if ( startCursor.ch !== 0 ) {
+ insertText = '\n' + insertText;
+ pre += '\n';
}
- } );
- },
- /**
- * Get the position (in resolution of bytes not necessarily characters)
- * in a textarea
- */
- getCaretPosition: function ( options ) {
- var caretPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( true ) ),
- endPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( false ) );
- if ( options.startAndEnd ) {
- return [ caretPos, endPos ];
+ if ( codeMirror.doc.getLine( endCursor.line ).length !== endCursor.ch ) {
+ insertText += '\n';
+ post += '\n';
+ }
}
- return caretPos;
- },
- setSelection: function ( options ) {
- return this.each( function () {
- codeMirror.doc.setSelection( codeMirror.doc.posFromIndex( options.start ), codeMirror.doc.posFromIndex( options.end ) );
- } );
- },
+ codeMirror.doc.replaceSelection( insertText );
- /**
- * Scroll a textarea to the current cursor position. You can set the cursor
- * position with setSelection()
- */
- scrollToCaretPosition: function () {
- return this.each( function () {
- codeMirror.scrollIntoView( null );
- } );
+ if ( selectPeri ) {
+ codeMirror.doc.setSelection(
+ codeMirror.doc.posFromIndex( codeMirror.doc.indexFromPos( startCursor ) + pre.length ),
+ codeMirror.doc.posFromIndex( codeMirror.doc.indexFromPos( startCursor ) + pre.length + selText.length )
+ );
+ }
+ } );
+ },
+
+ /**
+ * Get the position (in resolution of bytes not necessarily characters)
+ * in a textarea
+ *
+ * @param {Object} options
+ * @return {number}
+ */
+ getCaretPosition: function ( options ) {
+ var caretPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( true ) ),
+ endPos = codeMirror.doc.indexFromPos( codeMirror.doc.getCursor( false ) );
+ if ( options.startAndEnd ) {
+ return [ caretPos, endPos ];
}
- };
+ return caretPos;
+ },
- switch ( command ) {
- // case 'getContents': // no params
- // case 'setContents': // no params with defaults
- // case 'getSelection': // no params
- case 'encapsulateSelection':
- options = $.extend( {
- pre: '', // Text to insert before the cursor/selection
- peri: '', // Text to insert between pre and post and select afterwards
- post: '', // Text to insert after the cursor/selection
- ownline: false, // Put the inserted text on a line of its own
- replace: false, // If there is a selection, replace it with peri instead of leaving it alone
- selectPeri: true, // Select the peri text if it was inserted (but not if there was a selection and replace==false, or if splitlines==true)
- splitlines: false, // If multiple lines are selected, encapsulate each line individually
- selectionStart: undefined, // Position to start selection at
- selectionEnd: undefined // Position to end selection at. Defaults to start
- }, options );
- break;
- case 'getCaretPosition':
- options = $.extend( {
- // Return [start, end] instead of just start
- startAndEnd: false
- }, options );
- // FIXME: We may not need character position-based functions if we insert markers in the right places
- break;
- case 'setSelection':
- options = $.extend( {
- // Position to start selection at
- start: undefined,
- // Position to end selection at. Defaults to start
- end: undefined,
- // Element to start selection in (iframe only)
- startContainer: undefined,
- // Element to end selection in (iframe only). Defaults to startContainer
- endContainer: undefined
- }, options );
+ setSelection: function ( options ) {
+ return this.each( function () {
+ codeMirror.doc.setSelection( codeMirror.doc.posFromIndex( options.start ), codeMirror.doc.posFromIndex( options.end ) );
+ } );
+ },
- if ( options.end === undefined ) {
- options.end = options.start;
- }
- if ( options.endContainer === undefined ) {
- options.endContainer = options.startContainer;
- }
- // FIXME: We may not need character position-based functions if we insert markers in the right places
- break;
- case 'scrollToCaretPosition':
- options = $.extend( {
- force: false // Force a scroll even if the caret position is already visible
- }, options );
- break;
+ /**
+ * Scroll a textarea to the current cursor position. You can set the cursor
+ * position with setSelection()
+ *
+ * @return {jQuery}
+ */
+ scrollToCaretPosition: function () {
+ return this.each( function () {
+ codeMirror.scrollIntoView( null );
+ } );
}
+ };
- retval = fn[ command ].call( this, options );
- codeMirror.focus();
+ switch ( command ) {
+ // case 'getContents': // no params
+ // case 'setContents': // no params with defaults
+ // case 'getSelection': // no params
+ case 'encapsulateSelection':
+ options = $.extend( {
+ pre: '', // Text to insert before the cursor/selection
+ peri: '', // Text to insert between pre and post and select afterwards
+ post: '', // Text to insert after the cursor/selection
+ ownline: false, // Put the inserted text on a line of its own
+ replace: false, // If there is a selection, replace it with peri instead of leaving it alone
+ selectPeri: true, // Select the peri text if it was inserted (but not if there was a selection and replace==false, or if splitlines==true)
+ splitlines: false, // If multiple lines are selected, encapsulate each line individually
+ selectionStart: undefined, // Position to start selection at
+ selectionEnd: undefined // Position to end selection at. Defaults to start
+ }, options );
+ break;
+ case 'getCaretPosition':
+ options = $.extend( {
+ // Return [start, end] instead of just start
+ startAndEnd: false
+ }, options );
+ // FIXME: We may not need character position-based functions if we insert markers in the right places
+ break;
+ case 'setSelection':
+ options = $.extend( {
+ // Position to start selection at
+ start: undefined,
+ // Position to end selection at. Defaults to start
+ end: undefined,
+ // Element to start selection in (iframe only)
+ startContainer: undefined,
+ // Element to end selection in (iframe only). Defaults to startContainer
+ endContainer: undefined
+ }, options );
- return retval;
- },
- /**
- * Adds the CodeMirror button to WikiEditor
- */
- addCodeMirrorToWikiEditor = function () {
- if ( $( '#wikiEditor-section-main' ).length > 0 ) {
- var msg = codeMirror ? 'codemirror-disable-label' : 'codemirror-enable-label';
+ if ( options.end === undefined ) {
+ options.end = options.start;
+ }
+ if ( options.endContainer === undefined ) {
+ options.endContainer = options.startContainer;
+ }
+ // FIXME: We may not need character position-based functions if we insert markers in the right places
+ break;
+ case 'scrollToCaretPosition':
+ options = $.extend( {
+ force: false // Force a scroll even if the caret position is already visible
+ }, options );
+ break;
+ }
- $( '#wpTextbox1' ).wikiEditor(
- 'addToToolbar',
- {
- section: 'main',
- groups: {
- codemirror: {
- tools: {
- CodeMirror: {
- label: mw.msg( msg ),
- type: 'button',
- // FIXME: There should be a better way?
- icon: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/cm-' + ( codeMirror ? 'on.png' : 'off.png' ),
- action: {
- type: 'callback',
- execute: function ( context ) {
- switchCodeMirror( context );
- }
+ retval = fn[ command ].call( this, options );
+ codeMirror.focus();
+
+ return retval;
+ }
+
+ /**
+ * Adds the CodeMirror button to WikiEditor
+ */
+ function addCodeMirrorToWikiEditor() {
+ var msg;
+ if ( $( '#wikiEditor-section-main' ).length > 0 ) {
+ msg = codeMirror ? 'codemirror-disable-label' : 'codemirror-enable-label';
+
+ $( '#wpTextbox1' ).wikiEditor(
+ 'addToToolbar',
+ {
+ section: 'main',
+ groups: {
+ codemirror: {
+ tools: {
+ CodeMirror: {
+ label: mw.msg( msg ),
+ type: 'button',
+ // FIXME: There should be a better way?
+ icon: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/cm-' + ( codeMirror ? 'on.png' : 'off.png' ),
+ action: {
+ type: 'callback',
+ execute: function ( context ) {
+ // eslint-disable-next-line no-use-before-define
+ switchCodeMirror( context );
}
}
}
}
}
}
- );
- }
- },
- originHooksTextarea = $.valHooks.textarea;
+ }
+ );
+ }
+ }
// define JQuery hook for searching and replacing text using JS if CodeMirror is enabled, see Bug: T108711
$.valHooks.textarea = {
@@ -308,6 +332,7 @@
.attr( 'src', $src )
.attr( 'title', mw.msg( 'codemirror-enable-label' ) );
} else {
+ // eslint-disable-next-line no-use-before-define
enableCodeMirror();
$src = mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/' + ( context ? 'cm-on.png' : 'old-cm-on.png' );
$img
@@ -327,20 +352,20 @@
return;
}
codeMirror = CodeMirror.fromTextArea( textbox1[ 0 ], {
- mwextFunctionSynonyms: mw.config.get( 'extCodeMirrorFunctionSynonyms' ),
- mwextTags: mw.config.get( 'extCodeMirrorTags' ),
- mwextDoubleUnderscore: mw.config.get( 'extCodeMirrorDoubleUnderscore' ),
- mwextUrlProtocols: mw.config.get( 'extCodeMirrorUrlProtocols' ),
- mwextModes: mw.config.get( 'extCodeMirrorExtModes' ),
- styleActiveLine: true,
- lineWrapping: true,
- readOnly: textbox1[ 0 ].readOnly,
- // select mediawiki as text input mode
- mode: 'text/mediawiki',
- extraKeys: {
- Tab: false
- }
- } );
+ mwextFunctionSynonyms: mw.config.get( 'extCodeMirrorFunctionSynonyms' ),
+ mwextTags: mw.config.get( 'extCodeMirrorTags' ),
+ mwextDoubleUnderscore: mw.config.get( 'extCodeMirrorDoubleUnderscore' ),
+ mwextUrlProtocols: mw.config.get( 'extCodeMirrorUrlProtocols' ),
+ mwextModes: mw.config.get( 'extCodeMirrorExtModes' ),
+ styleActiveLine: true,
+ lineWrapping: true,
+ readOnly: textbox1[ 0 ].readOnly,
+ // select mediawiki as text input mode
+ mode: 'text/mediawiki',
+ extraKeys: {
+ Tab: false
+ }
+ } );
// Our best friend, IE, needs some special css
if ( window.navigator.userAgent.indexOf( 'Trident/' ) > -1 ) {
$( '.CodeMirror' ).addClass( 'CodeMirrorIE' );
@@ -356,6 +381,7 @@
if ( $.inArray( mw.config.get( 'wgAction' ), [ 'edit', 'submit' ] ) !== -1 ) {
// This function shouldn't be called without user.options is loaded, but it's not guaranteed
mw.loader.using( 'user.options', function () {
+ var $image;
// This can be the string "0" if the user disabled the preference - Bug T54542#555387
if ( mw.user.options.get( 'usebetatoolbar' ) === 1 || mw.user.options.get( 'usebetatoolbar' ) === '1' ) {
// load wikiEditor's toolbar (if not already) and add our button
@@ -364,7 +390,7 @@
).then( addCodeMirrorToWikiEditor );
} else {
// If WikiEditor isn't enabled, add CodeMirror button to the default wiki editor toolbar
- var $image = $( '' ).attr( {
+ $image = $( '' ).attr( {
width: 23,
height: 22,
src: mw.config.get( 'wgExtensionAssetsPath' ) + '/CodeMirror/resources/images/old-cm-' + ( codeMirror ? 'on.png' : 'off.png' ),
diff --git a/resources/mode/mediawiki/mediawiki.css b/resources/mode/mediawiki/mediawiki.css
index aae23002..ecd98389 100644
--- a/resources/mode/mediawiki/mediawiki.css
+++ b/resources/mode/mediawiki/mediawiki.css
@@ -1,5 +1,5 @@
.CodeMirror {
- border: 1px solid #CCC;
+ border: 1px solid #ccc;
font-size: medium;
line-height: 1.5em;
}
@@ -8,101 +8,104 @@
font-size: small;
}
+/* stylelint-disable block-opening-brace-newline-before, block-opening-brace-newline-after,
+ block-closing-brace-space-after, declaration-block-single-line-max-declarations,
+ declaration-block-semicolon-newline-after, selector-list-comma-newline-after */
+
.cm-mw-pagename { text-decoration: underline; }
-.cm-mw-matching {background-color: gold;}
+.cm-mw-matching { background-color: #ffd700; }
-.cm-mw-skipformatting { background-color: #adf; }
-.cm-mw-list {color: #08f; font-weight: bold; background-color: #eee;}
-.cm-mw-signature,
-.cm-mw-hr { color: #08f; font-weight: bold; background-color: #eee; }
-.cm-mw-indenting {color: #08f; font-weight: bold; background-color: #ddd;}
-.cm-mw-mnemonic {color: #090;}
-.cm-mw-comment {color: #aaa; font-weight: normal;}
-.cm-mw-apostrophes-bold, .cm-mw-apostrophes-italic {color: #08f;}
+.cm-mw-skipformatting { background-color: #adf; }
+.cm-mw-list { color: #08f; font-weight: bold; background-color: #eee; }
+.cm-mw-signature, .cm-mw-hr { color: #08f; font-weight: bold; background-color: #eee; }
+.cm-mw-indenting { color: #08f; font-weight: bold; background-color: #ddd; }
+.cm-mw-mnemonic { color: #090; }
+.cm-mw-comment { color: #aaa; font-weight: normal; }
+.cm-mw-apostrophes-bold, .cm-mw-apostrophes-italic { color: #08f; }
-pre.cm-mw-section-1 {font-size: 1.8em;}
-pre.cm-mw-section-2 {font-size: 1.5em;}
-pre.cm-mw-section-3 {font-weight: bold;}
-pre.cm-mw-section-4 {font-weight: bold;}
-pre.cm-mw-section-5 {font-weight: bold;}
-pre.cm-mw-section-6 {font-weight: bold;}
-.cm-mw-section-header {color: #08f; font-weight: normal;}
+pre.cm-mw-section-1 { font-size: 1.8em; }
+pre.cm-mw-section-2 { font-size: 1.5em; }
+pre.cm-mw-section-3 { font-weight: bold; }
+pre.cm-mw-section-4 { font-weight: bold; }
+pre.cm-mw-section-5 { font-weight: bold; }
+pre.cm-mw-section-6 { font-weight: bold; }
+.cm-mw-section-header { color: #08f; font-weight: normal; }
-.cm-mw-template {color: #a11; font-weight: normal;}
-.cm-mw-template-name {color: #a11; font-weight: bold;}
-.cm-mw-template-name-mnemonic {font-weight: normal;}
-.cm-mw-template-argument-name {color: #a11; font-weight: bold;}
-.cm-mw-template-delimiter {color: #a11; font-weight: bold;}
-.cm-mw-template-bracket {color: #a11; font-weight: bold;}
+.cm-mw-template { color: #a11; font-weight: normal; }
+.cm-mw-template-name { color: #a11; font-weight: bold; }
+.cm-mw-template-name-mnemonic { font-weight: normal; }
+.cm-mw-template-argument-name { color: #a11; font-weight: bold; }
+.cm-mw-template-delimiter { color: #a11; font-weight: bold; }
+.cm-mw-template-bracket { color: #a11; font-weight: bold; }
-.cm-mw-templatevariable {color: #f50; font-weight: normal;}
-.cm-mw-templatevariable-name {color: #f50; font-weight: bold;}
-.cm-mw-templatevariable-bracket {color: #f50; font-weight: normal;}
-.cm-mw-templatevariable-delimiter {color: #f50; font-weight: bold;}
+.cm-mw-templatevariable { color: #f50; font-weight: normal; }
+.cm-mw-templatevariable-name { color: #f50; font-weight: bold; }
+.cm-mw-templatevariable-bracket { color: #f50; font-weight: normal; }
+.cm-mw-templatevariable-delimiter { color: #f50; font-weight: bold; }
-.cm-mw-parserfunction {font-weight: normal;}
-.cm-mw-parserfunction-name {color: #70a; font-weight: bold;}
-.cm-mw-parserfunction-bracket {color: #70a; font-weight: bold;}
-.cm-mw-parserfunction-delimiter {color: #70a; font-weight: bold;}
+.cm-mw-parserfunction { font-weight: normal; }
+.cm-mw-parserfunction-name { color: #70a; font-weight: bold; }
+.cm-mw-parserfunction-bracket { color: #70a; font-weight: bold; }
+.cm-mw-parserfunction-delimiter { color: #70a; font-weight: bold; }
-pre.cm-mw-exttag {background-image: url(img/ext2.png);}
-.cm-mw-exttag {background-image: url(img/ext4.png);}
-.cm-mw-exttag-name {color: #70a; font-weight: bold;}
-.cm-mw-exttag-bracket {color: #70a; font-weight: normal;}
-.cm-mw-exttag-attribute {color: #70a; font-weight: normal;}
+pre.cm-mw-exttag { background-image: url( img/ext2.png ); }
+.cm-mw-exttag { background-image: url( img/ext4.png ); }
+.cm-mw-exttag-name { color: #70a; font-weight: bold; }
+.cm-mw-exttag-bracket { color: #70a; font-weight: normal; }
+.cm-mw-exttag-attribute { color: #70a; font-weight: normal; }
-.cm-mw-htmltag-name {color: #170; font-weight: bold;}
-.cm-mw-htmltag-bracket {color: #170; font-weight: normal;}
-.cm-mw-htmltag-attribute {color: #170; font-weight: normal;}
+.cm-mw-htmltag-name { color: #170; font-weight: bold; }
+.cm-mw-htmltag-bracket { color: #170; font-weight: normal; }
+.cm-mw-htmltag-attribute { color: #170; font-weight: normal; }
-pre.cm-mw-tag-pre, .cm-mw-tag-pre {background-image: url(img/black4.png);}
-pre.cm-mw-tag-nowiki, .cm-mw-tag-nowiki {background-image: url(img/black4.png);}
+pre.cm-mw-tag-pre, .cm-mw-tag-pre { background-image: url( img/black4.png ); }
+pre.cm-mw-tag-nowiki, .cm-mw-tag-nowiki { background-image: url( img/black4.png ); }
-.cm-mw-link-pagename {color: #219; font-weight: normal;}
-.cm-mw-link-tosection {color: #08f; font-weight: normal;}
-.cm-mw-link-bracket {color: #219; font-weight: normal;}
-.cm-mw-link-text {}
-.cm-mw-link-delimiter {color: #219; font-weight: normal;}
+.cm-mw-link-pagename { color: #219; font-weight: normal; }
+.cm-mw-link-tosection { color: #08f; font-weight: normal; }
+.cm-mw-link-bracket { color: #219; font-weight: normal; }
+/* .cm-mw-link-text { } */
+.cm-mw-link-delimiter { color: #219; font-weight: normal; }
-.cm-mw-extlink, .cm-mw-free-extlink {color: #219; font-weight: normal;}
-.cm-mw-extlink-protocol, .cm-mw-free-extlink-protocol {color: #219; font-weight: bold;}
-.cm-mw-extlink-text {}
-.cm-mw-extlink-bracket {color: #219; font-weight: bold;}
+.cm-mw-extlink, .cm-mw-free-extlink { color: #219; font-weight: normal; }
+.cm-mw-extlink-protocol, .cm-mw-free-extlink-protocol { color: #219; font-weight: bold; }
+/* .cm-mw-extlink-text { } */
+.cm-mw-extlink-bracket { color: #219; font-weight: bold; }
-.cm-mw-table-bracket {color: #e0e; font-weight: bold;}
-.cm-mw-table-delimiter {color: #e0e; font-weight: bold;}
-.cm-mw-table-definition {color: #e0e; font-weight: normal;}
-.cm-mw-table-caption {font-weight: bold;}
+.cm-mw-table-bracket { color: #e0e; font-weight: bold; }
+.cm-mw-table-delimiter { color: #e0e; font-weight: bold; }
+.cm-mw-table-definition { color: #e0e; font-weight: normal; }
+.cm-mw-table-caption { font-weight: bold; }
-.cm-mw-template-ground {}
-.cm-mw-template2-ground {background-image: url(img/template4.png);}
-.cm-mw-template3-ground {background-image: url(img/template8.png);}
-.cm-mw-template-ext-ground {background-image: url(img/ext4.png);}
-.cm-mw-template-ext2-ground {background-image: url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-template-ext3-ground {background-image: url(img/ext4.png),url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-template-link-ground {background-image: url(img/link4.png);}
-.cm-mw-template-ext-link-ground {background-image: url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template-ext2-link-ground {background-image: url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template-ext3-link-ground {background-image: url(img/ext4.png),url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template2-ext-ground {background-image: url(img/template4.png),url(img/ext4.png);}
-.cm-mw-template2-ext2-ground {background-image: url(img/template4.png),url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-template2-ext3-ground {background-image: url(img/template4.png),url(img/ext4.png),url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-template2-link-ground {background-image: url(img/template4.png),url(img/link4.png);}
-.cm-mw-template2-ext-link-ground {background-image: url(img/template4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template2-ext2-link-ground {background-image: url(img/template4.png),url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template2-ext3-link-ground {background-image: url(img/template4.png),url(img/ext4.png),url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template3-ext-ground {background-image: url(img/template8.png),url(img/ext4.png);}
-.cm-mw-template3-ext2-ground {background-image: url(img/template8.png),url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-template3-ext3-ground {background-image: url(img/template8.png),url(img/ext4.png),url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-template3-link-ground {background-image: url(img/template8.png),url(img/link4.png);}
-.cm-mw-template3-ext-link-ground {background-image: url(img/template8.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template3-ext2-link-ground {background-image: url(img/template8.png),url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-template3-ext3-link-ground {background-image: url(img/template8.png),url(img/ext4.png),url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-ext-ground {background-image: url(img/ext4.png)}
-.cm-mw-ext2-ground {background-image: url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-ext3-ground {background-image: url(img/ext4.png),url(img/ext4.png),url(img/ext4.png);}
-.cm-mw-ext-link-ground {background-image: url(img/link4.png);}
-.cm-mw-ext2-link-ground {background-image: url(img/ext4.png),url(img/link4.png);}
-.cm-mw-ext3-link-ground {background-image: url(img/ext4.png),url(img/ext4.png),url(img/link4.png);}
-.cm-mw-link-ground {background-image: url(img/link4.png);}
+/* .cm-mw-template-ground {} */
+.cm-mw-template2-ground { background-image: url( img/template4.png ); }
+.cm-mw-template3-ground { background-image: url( img/template8.png ); }
+.cm-mw-template-ext-ground { background-image: url( img/ext4.png ); }
+.cm-mw-template-ext2-ground { background-image: url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-template-ext3-ground { background-image: url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-template-link-ground { background-image: url( img/link4.png ); }
+.cm-mw-template-ext-link-ground { background-image: url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template-ext2-link-ground { background-image: url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template-ext3-link-ground { background-image: url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template2-ext-ground { background-image: url( img/template4.png ), url( img/ext4.png ); }
+.cm-mw-template2-ext2-ground { background-image: url( img/template4.png ), url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-template2-ext3-ground { background-image: url( img/template4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-template2-link-ground { background-image: url( img/template4.png ), url( img/link4.png ); }
+.cm-mw-template2-ext-link-ground { background-image: url( img/template4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template2-ext2-link-ground { background-image: url( img/template4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template2-ext3-link-ground { background-image: url( img/template4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template3-ext-ground { background-image: url( img/template8.png ), url( img/ext4.png ); }
+.cm-mw-template3-ext2-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-template3-ext3-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-template3-link-ground { background-image: url( img/template8.png ), url( img/link4.png ); }
+.cm-mw-template3-ext-link-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template3-ext2-link-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-template3-ext3-link-ground { background-image: url( img/template8.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-ext-ground { background-image: url( img/ext4.png ); }
+.cm-mw-ext2-ground { background-image: url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-ext3-ground { background-image: url( img/ext4.png ), url( img/ext4.png ), url( img/ext4.png ); }
+.cm-mw-ext-link-ground { background-image: url( img/link4.png ); }
+.cm-mw-ext2-link-ground { background-image: url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-ext3-link-ground { background-image: url( img/ext4.png ), url( img/ext4.png ), url( img/link4.png ); }
+.cm-mw-link-ground { background-image: url( img/link4.png ); }
diff --git a/resources/mode/mediawiki/mediawiki.js b/resources/mode/mediawiki/mediawiki.js
index 844b0bf6..985ce5a7 100644
--- a/resources/mode/mediawiki/mediawiki.js
+++ b/resources/mode/mediawiki/mediawiki.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-use-before-define */
( function ( CodeMirror ) {
'use strict';
@@ -19,7 +20,7 @@
return style;
}
- CodeMirror.defineMode( 'mediawiki', function ( config/*, parserConfig */ ) {
+ CodeMirror.defineMode( 'mediawiki', function ( config /* , parserConfig */ ) {
var urlProtocols = new RegExp( config.mwextUrlProtocols, 'i' ),
permittedHtmlTags = { b: true, bdi: true, del: true, i: true, ins: true,
@@ -354,19 +355,20 @@
function eatLinkText() {
var linkIsBold, linkIsItalic;
return function ( stream, state ) {
+ var tmpstyle;
if ( stream.match( ']]' ) ) {
state.tokenize = state.stack.pop();
return makeLocalStyle( 'mw-link-bracket', state, 'nLink' );
}
if ( stream.match( '\'\'\'' ) ) {
- linkIsBold = ( linkIsBold ? false : true );
+ linkIsBold = !linkIsBold;
return makeLocalStyle( 'mw-link-text mw-apostrophes', state );
}
if ( stream.match( '\'\'' ) ) {
- linkIsItalic = ( linkIsItalic ? false : true );
+ linkIsItalic = !linkIsItalic;
return makeLocalStyle( 'mw-link-text mw-apostrophes', state );
}
- var tmpstyle = 'mw-link-text';
+ tmpstyle = 'mw-link-text';
if ( linkIsBold ) {
tmpstyle += ' strong';
}
@@ -441,7 +443,7 @@
}
if ( stream.eat( '>' ) ) {
state.extName = name;
- if ( name in config.mwextModes.tag ) {
+ if ( name in config.mwextModes.tag ) {
state.extMode = CodeMirror.getMode( config, config.mwextModes.tag[ name ] );
state.extState = CodeMirror.startState( state.extMode );
}
@@ -627,13 +629,14 @@
function eatWikiText( style, mnemonicStyle ) {
return function ( stream, state ) {
+ var ch, tmp, mt, name, isCloseTag, tagname,
+ sol = stream.sol();
+
function chain( parser ) {
state.stack.push( state.tokenize );
state.tokenize = parser;
return parser( stream, state );
}
- var ch,
- sol = stream.sol();
if ( sol ) {
if ( stream.match( urlProtocols ) ) { // highlight free external links, bug T108448
@@ -649,7 +652,7 @@
}
break;
case '=':
- var tmp = stream.match( /(={0,5})(.+?(=\1\s*))$/ );
+ tmp = stream.match( /(={0,5})(.+?(=\1\s*))$/ );
if ( tmp ) { // Title
stream.backUp( tmp[ 2 ].length );
state.stack.push( state.tokenize );
@@ -685,7 +688,7 @@
return 'mw-skipformatting';
}
// break is not necessary here
- /*falls through*/
+ // falls through
case '{':
if ( stream.eat( '|' ) ) {
stream.eatSpace();
@@ -709,10 +712,10 @@
if ( !( firstsingleletterword || stream.match( '\'\'', false ) ) ) {
prepareItalicForCorrection( stream );
}
- isBold = isBold ? false : true;
+ isBold = !isBold;
return makeLocalStyle( 'mw-apostrophes-bold', state );
} else if ( stream.eat( '\'' ) ) { // italic
- isItalic = isItalic ? false : true;
+ isItalic = !isItalic;
return makeLocalStyle( 'mw-apostrophes-italic', state );
}
break;
@@ -726,7 +729,7 @@
return makeLocalStyle( 'mw-link-bracket', state );
}
} else {
- var mt = stream.match( urlProtocols );
+ mt = stream.match( urlProtocols );
if ( mt ) {
state.nLink++;
stream.backUp( mt[ 0 ].length );
@@ -750,7 +753,7 @@
return makeLocalStyle( 'mw-parserfunction-bracket', state );
}
// Check for parser function without '#'
- var name = stream.match( /([^\s\u00a0\}\[\]<\{\'\|\&\:]+)(\:|[\s\u00a0]*)(\}\}?)?(.)?/ );
+ name = stream.match( /([^\s\u00a0\}\[\]<\{\'\|\&\:]+)(\:|[\s\u00a0]*)(\}\}?)?(.)?/ );
if ( name ) {
stream.backUp( name[ 0 ].length );
if ( ( name[ 2 ] === ':' || name[ 4 ] === undefined || name[ 3 ] === '}}' ) && ( name[ 1 ].toLowerCase() in config.mwextFunctionSynonyms[ 0 ] || name[ 1 ] in config.mwextFunctionSynonyms[ 1 ] ) ) {
@@ -768,8 +771,8 @@
}
break;
case '<':
- var isCloseTag = ( stream.eat( '/' ) ? true : false );
- var tagname = stream.match( /[^>\/\s\u00a0\.\*\,\[\]\{\}\$\^\+\?\|\/\\'`~<=!@#%&\(\)-]+/ );
+ isCloseTag = !!stream.eat( '/' );
+ tagname = stream.match( /[^>\/\s\u00a0\.\*\,\[\]\{\}\$\^\+\?\|\/\\'`~<=!@#%&\(\)-]+/ );
if ( stream.match( '!--' ) ) { // coment
return chain( eatBlock( 'mw-comment', '-->' ) );
}
@@ -937,9 +940,10 @@
return t.style;
},
blankLine: function ( state ) {
+ var ret;
if ( state.extName ) {
if ( state.extMode ) {
- var ret = '';
+ ret = '';
if ( state.extMode.blankLine ) {
ret = ' ' + state.extMode.blankLine( state.extState );
}
@@ -955,12 +959,13 @@
function eatNowiki( style, lineStyle ) {
return function ( stream, state, ownLine ) {
+ var s;
if ( ownLine && stream.sol() ) {
state.ownLine = true;
} else if ( ownLine === false && state.ownLine ) {
state.ownLine = false;
}
- var s = ( state.ownLine ? lineStyle : style );
+ s = ( state.ownLine ? lineStyle : style );
if ( stream.match( /[^&]+/ ) ) {
return s;
}
@@ -969,14 +974,14 @@
};
}
- CodeMirror.defineMode( 'mw-tag-pre', function ( /*config, parserConfig */ ) {
+ CodeMirror.defineMode( 'mw-tag-pre', function ( /* config, parserConfig */ ) {
return {
startState: function () { return {}; },
token: eatNowiki( 'mw-tag-pre', 'line-cm-mw-tag-pre' )
};
} );
- CodeMirror.defineMode( 'mw-tag-nowiki', function ( /*config, parserConfig */ ) {
+ CodeMirror.defineMode( 'mw-tag-nowiki', function ( /* config, parserConfig */ ) {
return {
startState: function () { return {}; },
token: eatNowiki( 'mw-tag-nowiki', 'line-cm-mw-tag-nowiki' )