mediawiki/extensions/Translate (main)

sourcepatches
From 216241917b758eeae5abb770798eb84dc62953ad Mon Sep 17 00:00:00 2001
From: libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Date: Mon, 31 Mar 2025 06:36:23 +0000
Subject: [PATCH] build: Updating eslint-config-wikimedia to 0.29.1

The following rules are failing and were disabled:
* resources:
  * no-jquery/no-done-fail* tests/qunit:
  * no-jquery/no-done-fail

Change-Id: I1953f37dfe776fda2d996fbd90f961121a200a87
---
 package-lock.json                             | 35 ++++++++++---------
 package.json                                  |  2 +-
 resources/.eslintrc.json                      |  3 +-
 resources/js/ext.translate.editor.js          |  2 +-
 .../js/ext.translate.messagerenamedialog.js   |  4 +--
 resources/js/ext.translate.messagetable.js    | 10 +++---
 resources/js/ext.translate.proofread.js       |  2 +-
 ...anslate.special.managetranslatorsandbox.js |  4 +--
 .../js/ext.translate.special.pagemigration.js |  2 +-
 .../ext.translate.special.pagepreparation.js  |  4 +--
 ...xt.translate.special.searchtranslations.js |  8 ++---
 .../js/ext.translate.special.translate.js     |  4 +--
 ...translate.translationstats.graphbuilder.js |  2 +-
 .../ext.translate.entity.selector/index.js    |  2 +-
 .../src/ext.translate.mtHelpers/index.js      |  4 +--
 .../ve.ui.MWTranslateAnnotationContextItem.js |  2 +-
 tests/qunit/.eslintrc.json                    |  5 ++-
 17 files changed, 50 insertions(+), 45 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 80fa8cd..f58c501 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,7 +7,7 @@
 			"name": "Translate",
 			"devDependencies": {
 				"@wikimedia/codex-design-tokens": "1.21.1",
-				"eslint-config-wikimedia": "0.28.2",
+				"eslint-config-wikimedia": "0.29.1",
 				"grunt": "1.6.1",
 				"grunt-banana-checker": "0.13.0",
 				"grunt-eslint": "24.3.0",
@@ -1586,11 +1586,10 @@
 			}
 		},
 		"node_modules/eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.29.1",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.29.1.tgz",
+			"integrity": "sha512-4dbL5o3hKGSvreyrGZWLPoTDLFubZ575IQOPhUaTcpbTsi0u05TBEMsOyYkthTaK21vsFQqhSYtxp/xU93BSdA==",
 			"dev": true,
-			"license": "MIT",
 			"dependencies": {
 				"browserslist-config-wikimedia": "^0.7.0",
 				"eslint": "^8.57.0",
@@ -1602,13 +1601,16 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
 				"eslint-plugin-vue": "^9.26.0",
 				"eslint-plugin-wdio": "^8.24.12",
 				"eslint-plugin-yml": "^1.14.0"
+			},
+			"engines": {
+				"node": ">=18 <23"
 			}
 		},
 		"node_modules/eslint-plugin-compat": {
@@ -1826,11 +1828,10 @@
 			}
 		},
 		"node_modules/eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
-			"license": "MIT",
 			"peerDependencies": {
 				"eslint": ">=8.0.0"
 			}
@@ -6507,9 +6508,9 @@
 			}
 		},
 		"eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.29.1",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.29.1.tgz",
+			"integrity": "sha512-4dbL5o3hKGSvreyrGZWLPoTDLFubZ575IQOPhUaTcpbTsi0u05TBEMsOyYkthTaK21vsFQqhSYtxp/xU93BSdA==",
 			"dev": true,
 			"requires": {
 				"browserslist-config-wikimedia": "^0.7.0",
@@ -6522,7 +6523,7 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
@@ -6669,9 +6670,9 @@
 			}
 		},
 		"eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
 			"requires": {}
 		},
diff --git a/package.json b/package.json
index 142e230..b09496e 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
 	},
 	"devDependencies": {
 		"@wikimedia/codex-design-tokens": "1.21.1",
-		"eslint-config-wikimedia": "0.28.2",
+		"eslint-config-wikimedia": "0.29.1",
 		"grunt": "1.6.1",
 		"grunt-banana-checker": "0.13.0",
 		"grunt-eslint": "24.3.0",
diff --git a/resources/.eslintrc.json b/resources/.eslintrc.json
index 897c2a7..a620368 100644
--- a/resources/.eslintrc.json
+++ b/resources/.eslintrc.json
@@ -22,6 +22,7 @@
 		"no-jquery/no-visibility": "error",
 		"compat/compat": "warn",
 		"no-jquery/no-extend": "warn",
-		"es-x/no-resizable-and-growable-arraybuffers": "warn"
+		"es-x/no-resizable-and-growable-arraybuffers": "warn",
+		"no-jquery/no-done-fail": "warn"
 	}
 }
diff --git a/resources/js/ext.translate.editor.js b/resources/js/ext.translate.editor.js
index a4f1429..a664349 100644
--- a/resources/js/ext.translate.editor.js
+++ b/resources/js/ext.translate.editor.js
@@ -1183,7 +1183,7 @@
 			}
 
 			for ( var index = 0; index < stringTypes.length; index++ ) {
-				if ( allNoticeTypes.indexOf( stringTypes[ index ] ) === -1 ) {
+				if ( !allNoticeTypes.includes( stringTypes[ index ] ) ) {
 					var errMsg = 'tux: Invalid notice type removeNotice - ' + stringTypes[ index ];
 					mw.log.error( errMsg );
 					throw new Error( errMsg );
diff --git a/resources/js/ext.translate.messagerenamedialog.js b/resources/js/ext.translate.messagerenamedialog.js
index 5e362e3..d5d3edb 100644
--- a/resources/js/ext.translate.messagerenamedialog.js
+++ b/resources/js/ext.translate.messagerenamedialog.js
@@ -277,8 +277,8 @@ mw.translate.MessageRenameDialog.prototype.filterMessages = function ( searchVal
 	}
 
 	filteredMessages = this.possibleRenames.filter( function ( message ) {
-		return message.key.toLowerCase().indexOf( normalizedSearchVal ) !== -1 &&
-			message.content.toLowerCase().indexOf( normalizedSearchVal ) !== -1;
+		return message.key.toLowerCase().includes( normalizedSearchVal ) &&
+			message.content.toLowerCase().includes( normalizedSearchVal );
 	} );
 
 	this.clearMessages();
diff --git a/resources/js/ext.translate.messagetable.js b/resources/js/ext.translate.messagetable.js
index 78d2de9..22ef0a0 100644
--- a/resources/js/ext.translate.messagetable.js
+++ b/resources/js/ext.translate.messagetable.js
@@ -33,7 +33,7 @@
 	function MessageTable( container, options, settings ) {
 		this.$container = $( container );
 		this.options = options;
-		this.options = $.extend( {}, $.fn.messagetable.defaults, options );
+		this.options = Object.assign( {}, $.fn.messagetable.defaults, options );
 		this.settings = settings;
 		// mode can be proofread, page or translate
 		this.mode = this.options.mode;
@@ -152,7 +152,7 @@
 			message.proofreadable = false;
 
 			if ( message.tags.length &&
-				message.tags.indexOf( 'optional' ) >= 0 &&
+				message.tags.includes( 'optional' ) &&
 				status === 'untranslated'
 			) {
 				status = 'optional';
@@ -752,7 +752,7 @@
 
 				// Fix the filter if it is untranslated. Untranslated does not make sense
 				// for proofread mode. Keep the filter if it is not 'untranslated'
-				if ( !filter || filter.indexOf( '!translated' ) >= 0 ) {
+				if ( !filter || filter.includes( '!translated' ) ) {
 					messageTable.messages = [];
 					// default filter for proofread mode
 					mw.translate.changeFilter( 'translated|!reviewer:' + userId +
@@ -766,11 +766,11 @@
 				$tuxTabUntranslated.removeClass( 'hide' );
 				$tuxTabUnproofread.addClass( 'hide' );
 
-				if ( filter.indexOf( '!translated' ) > -1 ) {
+				if ( filter.includes( '!translated' ) ) {
 					$hideTranslatedButton.removeClass( 'hide' );
 				}
 
-				if ( filter && filter.indexOf( '!last-translator' ) >= 0 ) {
+				if ( filter && filter.includes( '!last-translator' ) ) {
 					messageTable.messages = [];
 					// default filter for translate mode
 					mw.translate.changeFilter( '!translated' );
diff --git a/resources/js/ext.translate.proofread.js b/resources/js/ext.translate.proofread.js
index c0829ba..e483780 100644
--- a/resources/js/ext.translate.proofread.js
+++ b/resources/js/ext.translate.proofread.js
@@ -97,7 +97,7 @@
 			/* Whether the current user if the last translator of this message.
 			 * Accepting own translations is prohibited. */
 			var translatedBySelf = ( this.message.properties[ 'last-translator-text' ] === mw.user.getName() );
-			var proofreadBySelf = reviewers.indexOf( userId ) > -1;
+			var proofreadBySelf = reviewers.includes( userId );
 
 			var sourceLangDir = $.uls.data.getDir( this.options.sourcelangcode );
 
diff --git a/resources/js/ext.translate.special.managetranslatorsandbox.js b/resources/js/ext.translate.special.managetranslatorsandbox.js
index 56a5dbe..2c1aabe 100644
--- a/resources/js/ext.translate.special.managetranslatorsandbox.js
+++ b/resources/js/ext.translate.special.managetranslatorsandbox.js
@@ -28,7 +28,7 @@
 
 	function doApiAction( options ) {
 		var api = new mw.Api(),
-			optionsWithDefaults = $.extend( {}, { action: 'translatesandbox' }, options );
+			optionsWithDefaults = Object.assign( {}, { action: 'translatesandbox' }, options );
 
 		return api.postWithToken( 'csrf', optionsWithDefaults ).promise();
 	}
@@ -636,7 +636,7 @@
 			if ( !language ||
 				( requestData.languagepreferences &&
 					requestData.languagepreferences.languages &&
-					requestData.languagepreferences.languages.indexOf( language ) > -1 )
+					requestData.languagepreferences.languages.includes( language ) )
 			) {
 				// Found language
 				$request.removeClass( 'hide' );
diff --git a/resources/js/ext.translate.special.pagemigration.js b/resources/js/ext.translate.special.pagemigration.js
index 56ff257..a7808d6 100644
--- a/resources/js/ext.translate.special.pagemigration.js
+++ b/resources/js/ext.translate.special.pagemigration.js
@@ -154,7 +154,7 @@
 			var errorMessage = mw.msg( 'pm-translation-unit-fetch-failed' );
 			if (
 				code === 'badparameter' &&
-				result.error && result.error.info.indexOf( 'mcgroup' ) !== -1
+				result.error && result.error.info.includes( 'mcgroup' )
 			) {
 				errorMessage = mw.msg( 'pm-pagetitle-not-translatable', page );
 			}
diff --git a/resources/js/ext.translate.special.pagepreparation.js b/resources/js/ext.translate.special.pagepreparation.js
index 2b245e0..1cec366 100644
--- a/resources/js/ext.translate.special.pagepreparation.js
+++ b/resources/js/ext.translate.special.pagepreparation.js
@@ -124,13 +124,13 @@
 		var headerSearchRegex = new RegExp( '(==+[ ]*' + headerText + '[ ]*==+)', 'gi' );
 		// This is to ensure that the tags and the anchor are added only once
 
-		if ( pageContent.indexOf( '<span id="' + mw.html.escape( anchorID ) + '"' ) === -1 ) {
+		if ( !pageContent.includes( '<span id="' + mw.html.escape( anchorID ) + '"' ) ) {
 			pageContent = pageContent.replace( headerSearchRegex, '</translate>\n' +
 				'<span id="' + mw.html.escape( anchorID ) + '"></span>\n<translate>\n$1' );
 		}
 
 		// This is to add back the tags which were removed in cleanupTags()
-		if ( pageContent.indexOf( '</translate>\n<span id="' + anchorID + '"' ) === -1 ) {
+		if ( !pageContent.includes( '</translate>\n<span id="' + anchorID + '"' ) ) {
 			var spanSearchRegex = new RegExp( '(<span id="' + mw.util.escapeRegExp( anchorID ) + '"></span>)', 'gi' );
 			pageContent = pageContent.replace( spanSearchRegex, '\n</translate>\n$1\n</translate>\n' );
 		}
diff --git a/resources/js/ext.translate.special.searchtranslations.js b/resources/js/ext.translate.special.searchtranslations.js
index 65fa216..6151714 100644
--- a/resources/js/ext.translate.special.searchtranslations.js
+++ b/resources/js/ext.translate.special.searchtranslations.js
@@ -64,14 +64,14 @@
 
 		// Remove duplicates from the language list
 		quickLanguageList.forEach( function ( lang ) {
-			if ( languages[ lang ] && unique.indexOf( lang ) === -1 ) {
+			if ( languages[ lang ] && !unique.includes( lang ) ) {
 				unique.push( lang );
 			}
 		} );
 
-		if ( currentLanguage && quickLanguageList.indexOf( currentLanguage ) >= 0 ) {
+		if ( currentLanguage && quickLanguageList.includes( currentLanguage ) ) {
 			quickLanguageList = unique.splice( 0, 5 );
-			if ( quickLanguageList.indexOf( currentLanguage ) === -1 ) {
+			if ( !quickLanguageList.includes( currentLanguage ) ) {
 				quickLanguageList = quickLanguageList.concat( currentLanguage );
 			}
 		} else {
@@ -165,7 +165,7 @@
 		}
 		var grouppath = getParameterByName( 'grouppath' ).split( '|' )[ 0 ];
 		if ( currentGroup && resultGroups[ grouppath ] &&
-			groupList.indexOf( grouppath ) < 0 &&
+			!groupList.includes( grouppath ) &&
 			level === 0
 		) {
 			// Make sure current selected group is displayed always.
diff --git a/resources/js/ext.translate.special.translate.js b/resources/js/ext.translate.special.translate.js
index 3c117e5..b599913 100644
--- a/resources/js/ext.translate.special.translate.js
+++ b/resources/js/ext.translate.special.translate.js
@@ -396,7 +396,7 @@
 			return true;
 		}
 
-		return priorityLanguages.indexOf( language ) !== -1;
+		return priorityLanguages.includes( language );
 	}
 
 	function setupLanguageSelector( $element ) {
@@ -625,7 +625,7 @@
 				filter: actualFilter
 			} );
 
-			if ( actualFilter.indexOf( hideOptionalMessages ) === -1 ) {
+			if ( !actualFilter.includes( hideOptionalMessages ) ) {
 				$( '#tux-option-optional' ).prop( 'checked', true );
 			}
 		}
diff --git a/resources/js/ext.translate.translationstats.graphbuilder.js b/resources/js/ext.translate.translationstats.graphbuilder.js
index 640fd0c..64996ba 100644
--- a/resources/js/ext.translate.translationstats.graphbuilder.js
+++ b/resources/js/ext.translate.translationstats.graphbuilder.js
@@ -180,7 +180,7 @@
 				maxValue = 0, minValue = 0;
 
 			for ( var labelProp in jsonGraphData ) {
-				if ( labels.indexOf( labelProp ) === -1 ) {
+				if ( !labels.includes( labelProp ) ) {
 					labels.push( labelProp );
 				}
 
diff --git a/resources/src/ext.translate.entity.selector/index.js b/resources/src/ext.translate.entity.selector/index.js
index 2737103..f0c0423 100644
--- a/resources/src/ext.translate.entity.selector/index.js
+++ b/resources/src/ext.translate.entity.selector/index.js
@@ -78,7 +78,7 @@ var EntitySelectorWidget = function ( config ) {
 
 	if ( this.groupTypesToFetch ) {
 		for ( var i = 0; i < this.groupTypesToFetch.length; i++ ) {
-			if ( validGroupTypes.indexOf( this.groupTypesToFetch[ i ] ) === -1 ) {
+			if ( !validGroupTypes.includes( this.groupTypesToFetch[ i ] ) ) {
 				throw new Error(
 					this.groupTypesToFetch[ i ] +
 					' is invalid. Allowed types: ' + validGroupTypes );
diff --git a/resources/src/ext.translate.mtHelpers/index.js b/resources/src/ext.translate.mtHelpers/index.js
index 64d11ef..765c90b 100644
--- a/resources/src/ext.translate.mtHelpers/index.js
+++ b/resources/src/ext.translate.mtHelpers/index.js
@@ -46,7 +46,7 @@ const tokenize = function ( string, language ) {
 	if ( !string ) {
 		return [];
 	}
-	if ( CJKLanguages.indexOf( language ) !== -1 ) {
+	if ( CJKLanguages.includes( language ) ) {
 		return string.split( '' );
 	}
 	// Match all non whitespace characters for tokens.
@@ -81,7 +81,7 @@ const calculateUnmodifiedContent = {
 			smallSet = tokens1;
 		}
 		// Find the intersection (tokens that did not change) of two token sets
-		const unmodifiedTokens = bigSet.filter( ( token ) => smallSet.indexOf( token ) >= 0 );
+		const unmodifiedTokens = bigSet.filter( ( token ) => smallSet.includes( token ) );
 		// If string1 has 10 tokens and we see that 2 tokens are different or not present in
 		// string2, we are saying that string2 is 80% (ie. 10-2/10) of unmodified version
 		// for string1.
diff --git a/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js b/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js
index a69a095..4b7148a 100644
--- a/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js
+++ b/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js
@@ -48,7 +48,7 @@ ve.ui.MWTranslateAnnotationContextItem.prototype.getLabelMessage = function () {
 
 ve.ui.MWTranslateAnnotationContextItem.prototype.getDescriptionMessage = function () {
 	var type = this.model.getAttribute( 'type' );
-	if ( type.indexOf( '/End', type.length - 4 ) !== -1 ) {
+	if ( type.includes( '/End', type.length - 4 ) ) {
 		return '';
 	}
 	var map = {
diff --git a/tests/qunit/.eslintrc.json b/tests/qunit/.eslintrc.json
index 4c3e352..e79edce 100644
--- a/tests/qunit/.eslintrc.json
+++ b/tests/qunit/.eslintrc.json
@@ -3,5 +3,8 @@
 	"extends": [
 		"../../resources/.eslintrc.json",
 		"wikimedia/qunit"
-	]
+	],
+	"rules": {
+		"no-jquery/no-done-fail": "warn"
+	}
 }
-- 
2.39.2

$ date
--- stdout ---
Mon Mar 31 06:35:18 UTC 2025

--- end ---
$ git clone file:///srv/git/mediawiki-extensions-Translate.git repo --depth=1 -b master
--- stderr ---
Cloning into 'repo'...
--- stdout ---

--- end ---
$ git config user.name libraryupgrader
--- stdout ---

--- end ---
$ git config user.email tools.libraryupgrader@tools.wmflabs.org
--- stdout ---

--- end ---
$ git submodule update --init
--- stdout ---

--- end ---
$ grr init
--- stdout ---
Installed commit-msg hook.

--- end ---
$ git show-ref refs/heads/master
--- stdout ---
50caae2107a485fe650b2b70a5720e11000e109d refs/heads/master

--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
  "auditReportVersion": 2,
  "vulnerabilities": {},
  "metadata": {
    "vulnerabilities": {
      "info": 0,
      "low": 0,
      "moderate": 0,
      "high": 0,
      "critical": 0,
      "total": 0
    },
    "dependencies": {
      "prod": 1,
      "dev": 445,
      "optional": 0,
      "peer": 1,
      "peerOptional": 0,
      "total": 445
    }
  }
}

--- end ---
$ /usr/bin/composer install
--- stderr ---
No composer.lock file present. Updating dependencies to latest instead of installing from lock file. See https://getcomposer.org/install for more information.
Loading composer repositories with package information
Updating dependencies
Lock file operations: 41 installs, 0 updates, 0 removals
  - Locking composer/installers (v2.3.0)
  - Locking composer/pcre (3.3.2)
  - Locking composer/semver (3.4.3)
  - Locking composer/spdx-licenses (1.5.8)
  - Locking composer/xdebug-handler (3.0.5)
  - Locking dealerdirect/phpcodesniffer-composer-installer (v1.0.0)
  - Locking doctrine/deprecations (1.1.4)
  - Locking felixfbecker/advanced-json-rpc (v3.2.1)
  - Locking mediawiki/mediawiki-codesniffer (v46.0.0)
  - Locking mediawiki/mediawiki-phan-config (0.15.1)
  - Locking mediawiki/minus-x (1.1.3)
  - Locking mediawiki/phan-taint-check-plugin (6.1.0)
  - Locking microsoft/tolerant-php-parser (v0.1.2)
  - Locking mustangostang/spyc (0.6.3)
  - Locking netresearch/jsonmapper (v4.5.0)
  - Locking phan/phan (5.4.5)
  - Locking php-parallel-lint/php-console-color (v1.0.1)
  - Locking php-parallel-lint/php-console-highlighter (v1.0.0)
  - Locking php-parallel-lint/php-parallel-lint (v1.4.0)
  - Locking phpcsstandards/phpcsextra (1.2.1)
  - Locking phpcsstandards/phpcsutils (1.0.12)
  - Locking phpdocumentor/reflection-common (2.2.0)
  - Locking phpdocumentor/reflection-docblock (5.6.1)
  - Locking phpdocumentor/type-resolver (1.10.0)
  - Locking phpstan/phpdoc-parser (2.1.0)
  - Locking psr/container (2.0.2)
  - Locking psr/log (3.0.2)
  - Locking sabre/event (5.1.7)
  - Locking slevomat/coding-standard (8.16.2)
  - Locking squizlabs/php_codesniffer (3.11.3)
  - Locking symfony/console (v7.2.5)
  - Locking symfony/deprecation-contracts (v3.5.1)
  - Locking symfony/polyfill-ctype (v1.31.0)
  - Locking symfony/polyfill-intl-grapheme (v1.31.0)
  - Locking symfony/polyfill-intl-normalizer (v1.31.0)
  - Locking symfony/polyfill-mbstring (v1.31.0)
  - Locking symfony/polyfill-php80 (v1.31.0)
  - Locking symfony/service-contracts (v3.5.1)
  - Locking symfony/string (v7.2.0)
  - Locking tysonandre/var_representation_polyfill (0.1.3)
  - Locking webmozart/assert (1.11.0)
Writing lock file
Installing dependencies from lock file (including require-dev)
Package operations: 41 installs, 0 updates, 0 removals
  - Downloading mustangostang/spyc (0.6.3)
 0/1 [>---------------------------]   0%
 1/1 [============================] 100%
  - Installing composer/installers (v2.3.0): Extracting archive
  - Installing squizlabs/php_codesniffer (3.11.3): Extracting archive
  - Installing dealerdirect/phpcodesniffer-composer-installer (v1.0.0): Extracting archive
  - Installing composer/pcre (3.3.2): Extracting archive
  - Installing symfony/polyfill-php80 (v1.31.0): Extracting archive
  - Installing phpcsstandards/phpcsutils (1.0.12): Extracting archive
  - Installing phpcsstandards/phpcsextra (1.2.1): Extracting archive
  - Installing symfony/polyfill-mbstring (v1.31.0): Extracting archive
  - Installing composer/spdx-licenses (1.5.8): Extracting archive
  - Installing composer/semver (3.4.3): Extracting archive
  - Installing mediawiki/mediawiki-codesniffer (v46.0.0): Extracting archive
  - Installing tysonandre/var_representation_polyfill (0.1.3): Extracting archive
  - Installing symfony/polyfill-intl-normalizer (v1.31.0): Extracting archive
  - Installing symfony/polyfill-intl-grapheme (v1.31.0): Extracting archive
  - Installing symfony/polyfill-ctype (v1.31.0): Extracting archive
  - Installing symfony/string (v7.2.0): Extracting archive
  - Installing symfony/deprecation-contracts (v3.5.1): Extracting archive
  - Installing psr/container (2.0.2): Extracting archive
  - Installing symfony/service-contracts (v3.5.1): Extracting archive
  - Installing symfony/console (v7.2.5): Extracting archive
  - Installing sabre/event (5.1.7): Extracting archive
  - Installing netresearch/jsonmapper (v4.5.0): Extracting archive
  - Installing microsoft/tolerant-php-parser (v0.1.2): Extracting archive
  - Installing webmozart/assert (1.11.0): Extracting archive
  - Installing phpstan/phpdoc-parser (2.1.0): Extracting archive
  - Installing phpdocumentor/reflection-common (2.2.0): Extracting archive
  - Installing doctrine/deprecations (1.1.4): Extracting archive
  - Installing phpdocumentor/type-resolver (1.10.0): Extracting archive
  - Installing phpdocumentor/reflection-docblock (5.6.1): Extracting archive
  - Installing felixfbecker/advanced-json-rpc (v3.2.1): Extracting archive
  - Installing psr/log (3.0.2): Extracting archive
  - Installing composer/xdebug-handler (3.0.5): Extracting archive
  - Installing phan/phan (5.4.5): Extracting archive
  - Installing mediawiki/phan-taint-check-plugin (6.1.0): Extracting archive
  - Installing mediawiki/mediawiki-phan-config (0.15.1): Extracting archive
  - Installing mediawiki/minus-x (1.1.3): Extracting archive
  - Installing mustangostang/spyc (0.6.3): Extracting archive
  - Installing php-parallel-lint/php-console-color (v1.0.1): Extracting archive
  - Installing php-parallel-lint/php-console-highlighter (v1.0.0): Extracting archive
  - Installing php-parallel-lint/php-parallel-lint (v1.4.0): Extracting archive
  - Installing slevomat/coding-standard (8.16.2): Extracting archive
  0/38 [>---------------------------]   0%
 19/38 [==============>-------------]  50%
 29/38 [=====================>------]  76%
 38/38 [============================] 100%
4 package suggestions were added by new dependencies, use `composer suggest` to see details.
Generating autoload files
18 packages you are using are looking for funding.
Use the `composer fund` command to find out more!
--- stdout ---
PHP CodeSniffer Config installed_paths set to ../../mediawiki/mediawiki-codesniffer,../../phpcsstandards/phpcsextra,../../phpcsstandards/phpcsutils,../../slevomat/coding-standard

--- end ---
Upgrading n:eslint-config-wikimedia from 0.28.2 -> 0.29.1
$ /usr/bin/npm install
--- stderr ---
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@wikimedia/codex-design-tokens@1.21.1',
npm WARN EBADENGINE   required: { node: '>=20', npm: '>=10.8.1' },
npm WARN EBADENGINE   current: { node: 'v18.19.0', npm: '9.2.0' }
npm WARN EBADENGINE }
--- stdout ---

added 445 packages, and audited 446 packages in 5s

95 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
$ /usr/bin/npm install grunt-eslint@24.3.0 --save-exact
--- stderr ---
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@wikimedia/codex-design-tokens@1.21.1',
npm WARN EBADENGINE   required: { node: '>=20', npm: '>=10.8.1' },
npm WARN EBADENGINE   current: { node: 'v18.19.0', npm: '9.2.0' }
npm WARN EBADENGINE }
--- stdout ---

up to date, audited 446 packages in 993ms

95 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
$ ./node_modules/.bin/eslint . --fix
--- stdout ---

/src/repo/resources/js/ext.translate.base.js
   6:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  40:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  66:4   error    Prefer .then to .done                                    no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.editor.helpers.js
   32:3   warning  Missing JSDoc @return declaration                        jsdoc/require-returns
   84:11  error    Prefer .then to .done                                    no-jquery/no-done-fail
   84:11  error    Prefer .then to .fail                                    no-jquery/no-done-fail
   93:6   error    Prefer .then to .done                                    no-jquery/no-done-fail
   93:6   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  393:1   warning  Missing JSDoc @param "e" type                            jsdoc/require-param-type
  394:1   warning  Missing JSDoc @param "suggestion" type                   jsdoc/require-param-type
  677:5   error    Prefer .then to .done                                    no-jquery/no-done-fail
  714:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  714:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  802:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  819:2   warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.editor.js
   270:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
   270:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail
   773:6   warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  1124:22  error    Prefer .then to .done                                    no-jquery/no-done-fail
  1283:7   error    Prefer .then to .done                                    no-jquery/no-done-fail
  1646:24  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.editor.shortcuts.js
  37:4  warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  73:2  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.messagerenamedialog.js
  250:2  error  Prefer .then to .done  no-jquery/no-done-fail
  250:2  error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.messagetable.js
   11:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   73:5   warning  ES2024 Resizable ArrayBuffer is forbidden                es-x/no-resizable-and-growable-arraybuffers
  275:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  285:25  warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  392:9   warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  406:16  warning  Positional selector extensions are not allowed           no-jquery/no-sizzle
  409:5   warning  ES2024 Resizable ArrayBuffer is forbidden                es-x/no-resizable-and-growable-arraybuffers
  422:20  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  488:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  488:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  535:7   warning  Positional selector extensions are not allowed           no-jquery/no-sizzle

/src/repo/resources/js/ext.translate.parsers.js
  13:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.proofread.js
  235:4  error  Prefer .then to .done  no-jquery/no-done-fail
  235:4  error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.aggregategroups.js
   19:16  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   24:3   error    Prefer .then to .done                                    no-jquery/no-done-fail
   24:3   error    Prefer .then to .fail                                    no-jquery/no-done-fail
   70:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   75:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
   75:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail
   99:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  103:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  103:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  145:3   error    Prefer .then to .done                                    no-jquery/no-done-fail
  145:3   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  397:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  397:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.managegroups.js
   18:11  error  Prefer .then to .done  no-jquery/no-done-fail
   18:11  error  Prefer .then to .fail  no-jquery/no-done-fail
   68:4   error  Prefer .then to .done  no-jquery/no-done-fail
   68:4   error  Prefer .then to .fail  no-jquery/no-done-fail
   98:4   error  Prefer .then to .done  no-jquery/no-done-fail
   98:4   error  Prefer .then to .fail  no-jquery/no-done-fail
  368:4   error  Prefer .then to .done  no-jquery/no-done-fail
  368:4   error  Prefer .then to .fail  no-jquery/no-done-fail
  391:4   error  Prefer .then to .done  no-jquery/no-done-fail
  391:4   error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.managetranslatorsandbox.js
  100:8  error  Prefer .then to .done  no-jquery/no-done-fail
  100:8  error  Prefer .then to .fail  no-jquery/no-done-fail
  128:8  error  Prefer .then to .done  no-jquery/no-done-fail
  145:8  error  Prefer .then to .done  no-jquery/no-done-fail
  185:3  error  Prefer .then to .done  no-jquery/no-done-fail
  305:8  error  Prefer .then to .done  no-jquery/no-done-fail
  322:8  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.pagemigration.js
  134:10  error    Prefer .then to .fail                                    no-jquery/no-done-fail
  388:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  388:4   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  562:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.special.pagepreparation.js
  327:4  error  Prefer .then to .done  no-jquery/no-done-fail
  327:4  error  Prefer .then to .fail  no-jquery/no-done-fail
  354:4  error  Prefer .then to .done  no-jquery/no-done-fail
  354:4  error  Prefer .then to .fail  no-jquery/no-done-fail
  372:5  error  Prefer .then to .done  no-jquery/no-done-fail
  372:5  error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.pagetranslation.js
  36:3  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.translate.js
   19:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   59:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
   96:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  236:3   error    Prefer .then to .done                                    no-jquery/no-done-fail
  269:3   error    Prefer .then to .done                                    no-jquery/no-done-fail
  269:3   error    Prefer .then to .fail                                    no-jquery/no-done-fail
  664:4   error    Prefer .then to .done                                    no-jquery/no-done-fail
  736:3   error    Prefer .then to .done                                    no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.statsbar.js
  33:4  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.translationstats.graphbuilder.js
  69:3   warning  Missing JSDoc @return declaration    jsdoc/require-returns
  70:1   warning  Missing JSDoc @param "options" type  jsdoc/require-param-type
  85:11  error    Prefer .then to .fail                no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.workflowselector.js
   52:4  error  Prefer .then to .done  no-jquery/no-done-fail
  146:5  error  Prefer .then to .done  no-jquery/no-done-fail
  146:5  error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/jquery.ajaxdispatcher.js
  19:10  error    Prefer .then to .fail                                    no-jquery/no-done-fail
  65:2   warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupDialog.vue
  143:4  error  Prefer .then to .done  no-jquery/no-done-fail
  143:4  error  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/src/ext.translate.groupselector/index.js
  156:5  error  Prefer .then to .done  no-jquery/no-done-fail
  348:4  error  Prefer .then to .done  no-jquery/no-done-fail
  391:4  error  Prefer .then to .done  no-jquery/no-done-fail
  450:4  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/src/ext.translate.special.exporttranslations/index.js
  22:25  warning  Selector extensions are not allowed  no-jquery/no-sizzle
  37:29  warning  Selector extensions are not allowed  no-jquery/no-sizzle

/src/repo/resources/src/ext.translate.special.languagestats/index.js
   20:3   warning  Positional selector extensions are not allowed                                  no-jquery/no-sizzle
   21:3   warning  Positional selector extensions are not allowed                                  no-jquery/no-sizzle
  214:23  warning  Selector extensions are not allowed                                             no-jquery/no-sizzle
  242:27  warning  Selector extensions are not allowed                                             no-jquery/no-sizzle
  300:3   warning  ResizeObserver.observe() is not supported in Safari 11.1, iOS Safari 11.3-11.4  compat/compat
  300:3   warning  ResizeObserver is not supported in Safari 11.1                                  compat/compat

/src/repo/resources/src/ext.translate.specialTranslationStash/index.js
  172:2  error  Prefer .then to .done  no-jquery/no-done-fail
  172:2  error  Prefer .then to .fail  no-jquery/no-done-fail
  247:2  error  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/tests/qunit/ext.translate.special.pagemigration.test.js
  17:3  error  Prefer .then to .done  no-jquery/no-done-fail
  31:3  error  Prefer .then to .fail  no-jquery/no-done-fail
  46:3  error  Prefer .then to .done  no-jquery/no-done-fail
  61:3  error  Prefer .then to .done  no-jquery/no-done-fail

✖ 118 problems (83 errors, 35 warnings)


--- end ---
$ ./node_modules/.bin/eslint . -f json
--- stdout ---
[{"filePath":"/src/repo/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/.stylelintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/.svgo.config.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/Gruntfile.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/composer.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/data/group-yaml-schema.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/data/plural-cldr.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/extension.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/api/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/core/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/core/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pagetranslation/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/pagetranslation/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sandbox/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/sandbox/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/search/en.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/i18n/search/qqq.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/jsdoc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/package-lock.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/package.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/LanguagesMultiselectWidget.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.base.js","messages":[{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":6,"column":17,"nodeType":"CallExpression","endLine":239,"endColumn":5},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":40,"column":4,"nodeType":"CallExpression","endLine":42,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":66,"column":4,"nodeType":"CallExpression","endLine":74,"endColumn":8}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\n\tmw.translate = mw.translate || {};\n\n\tmw.translate = $.extend( mw.translate, {\n\t\t/** @private */\n\t\tdirty: false,\n\n\t\t/**\n\t\t * A cache for language stats loaded from API, indexed by language code\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tlanguagestats: {},\n\n\t\t/**\n\t\t * Storage for language stats loader functions from API, indexed by language code\n\t\t *\n\t\t * @private\n\t\t */\n\t\tlanguageStatsLoader: {},\n\n\t\t/**\n\t\t * Get language stats for a language from the API.\n\t\t *\n\t\t * @internal\n\t\t * @param {string} language Language code.\n\t\t * @return {jQuery.Deferred}\n\t\t */\n\t\tloadMessageGroupStatsForLanguage: function ( language ) {\n\t\t\tif ( !mw.translate.languageStatsLoader[ language ] ) {\n\t\t\t\tmw.translate.languageStatsLoader[ language ] = new mw.Api().get( {\n\t\t\t\t\taction: 'query',\n\t\t\t\t\tmeta: 'languagestats',\n\t\t\t\t\tlslanguage: language\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tmw.translate.languageStatsLoader[ language ].done( function ( result ) {\n\t\t\t\tmw.translate.languagestats[ language ] = result.query.languagestats;\n\t\t\t} );\n\n\t\t\treturn mw.translate.languageStatsLoader[ language ];\n\t\t},\n\n\t\t/**\n\t\t * Get language stats for a language and group from the API\n\t\t *\n\t\t * @internal\n\t\t * @param {string} language\n\t\t * @param {string} group\n\t\t * @return {jQuery.Deferred}\n\t\t */\n\t\tloadMessageGroupStatsForItem: function ( language, group ) {\n\t\t\tvar uniqueKey = group + '|' + language;\n\t\t\tif ( !mw.translate.languageStatsLoader[ uniqueKey ] ) {\n\t\t\t\tmw.translate.languageStatsLoader[ uniqueKey ] = new mw.Api().get( {\n\t\t\t\t\taction: 'query',\n\t\t\t\t\tmeta: 'languagestats',\n\t\t\t\t\tlslanguage: language,\n\t\t\t\t\tlsgroup: group\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tmw.translate.languageStatsLoader[ uniqueKey ]\n\t\t\t\t.done( function ( result ) {\n\t\t\t\t\tif ( result.query.languagestats && result.query.languagestats.length ) {\n\t\t\t\t\t\tmw.translate.languagestats[ language ] = result.query.languagestats;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmw.translate.languagestats[ language ] = [];\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\treturn mw.translate.languageStatsLoader[ uniqueKey ];\n\t\t},\n\n\t\t/**\n\t\t * Load message group information asynchronously.\n\t\t *\n\t\t * @internal\n\t\t * @param {string} id Message group id\n\t\t * @param {string|Array} [props] List of properties to load\n\t\t * @return {jQuery.Promise} Object containing the requested properties on success.\n\t\t */\n\t\tgetMessageGroup: function ( id, props ) {\n\t\t\tif ( Array.isArray( props ) ) {\n\t\t\t\tprops = props.join( '|' );\n\t\t\t} else if ( props === undefined ) {\n\t\t\t\tprops = 'id|label|description|icon|priority|prioritylangs|priorityforce|workflowstates';\n\t\t\t}\n\n\t\t\tvar params = {\n\t\t\t\tmeta: 'messagegroups',\n\t\t\t\tmgformat: 'flat',\n\t\t\t\tmgprop: props,\n\t\t\t\tmgroot: id,\n\t\t\t\tformatversion: 2,\n\t\t\t\tuselang: mw.config.get( 'wgUserLanguage' )\n\t\t\t};\n\n\t\t\tvar api = new mw.Api();\n\n\t\t\treturn api.get( params ).then( function ( result ) {\n\t\t\t\treturn result.query.messagegroups[ 0 ];\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Find a group from an array of message groups as returned by web api\n\t\t * and recurse it through sub groups.\n\t\t *\n\t\t * @internal\n\t\t * @param {string} id Group id to search for.\n\t\t * @param {Array} groups Array of message groups\n\t\t * @return {Object} Message group object\n\t\t */\n\t\tfindGroup: function ( id, groups ) {\n\t\t\tif ( !id ) {\n\t\t\t\treturn groups;\n\t\t\t}\n\n\t\t\tvar result;\n\t\t\tgroups.some( function ( group ) {\n\t\t\t\tif ( group.id === id ) {\n\t\t\t\t\tresult = group;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\tif ( group.groups ) {\n\t\t\t\t\tgroup = mw.translate.findGroup( id, group.groups );\n\n\t\t\t\t\tif ( group ) {\n\t\t\t\t\t\tresult = group;\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t} );\n\n\t\t\treturn result;\n\t\t},\n\n\t\t/**\n\t\t * Check if the current user is allowed to translate on this wiki.\n\t\t *\n\t\t * @internal\n\t\t * @return {boolean}\n\t\t */\n\t\tcanTranslate: function () {\n\t\t\treturn mw.config.get( 'TranslateRight' );\n\t\t},\n\n\t\t/**\n\t\t * Check if the current user is allowed to proofread on this wiki.\n\t\t *\n\t\t * @internal\n\t\t * @return {boolean}\n\t\t */\n\t\tcanProofread: function () {\n\t\t\treturn mw.config.get( 'TranslateMessageReviewRight' );\n\t\t},\n\n\t\t/**\n\t\t * Check if the current user can delete translations on this wiki.\n\t\t *\n\t\t * @internal\n\t\t * @return {boolean}\n\t\t */\n\t\tcanDelete: function () {\n\t\t\treturn mw.config.get( 'DeleteRight' ) && mw.config.get( 'TranslateRight' );\n\t\t},\n\n\t\t/**\n\t\t * Check if the current user can update and manage message groups.\n\t\t *\n\t\t * @internal\n\t\t * @return {boolean}\n\t\t */\n\t\tcanManage: function () {\n\t\t\treturn mw.config.get( 'TranslateManageRight' );\n\t\t},\n\n\t\t/**\n\t\t * Adds missing languages to the language database so that they can be used in ULS.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} languages Language tags mapped to language names\n\t\t * @param {Array} regions Which regions to add the languages.\n\t\t */\n\t\taddExtraLanguagesToLanguageData: function ( languages, regions ) {\n\t\t\tfor ( var code in languages ) {\n\t\t\t\tif ( code in $.uls.data.languages ) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t$.uls.data.addLanguage( code, {\n\t\t\t\t\tscript: 'Zyyy',\n\t\t\t\t\tregions: regions,\n\t\t\t\t\tautonym: languages[ code ]\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Checks if there are any unsaved edits in Special:Translate\n\t\t *\n\t\t * @internal\n\t\t * @return {boolean|number}\n\t\t */\n\t\tisDirty: function () {\n\t\t\t// Something being typed in the current editor.\n\t\t\treturn mw.translate.dirty ||\n\t\t\t\t// Previous editors has some unsaved edits\n\t\t\t\t$( '.tux-status-unsaved' ).length;\n\t\t},\n\n\t\t/**\n\t\t * Return the language details for usage in HTML attributes\n\t\t *\n\t\t * @internal\n\t\t * @param {string} languageCode\n\t\t * @return {Object}\n\t\t */\n\t\tgetLanguageDetailsForHtml: function ( languageCode ) {\n\t\t\tvar languageCodeForHtml = languageCode;\n\t\t\tif ( languageCode === mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\t\tlanguageCodeForHtml = mw.config.get( 'wgContentLanguage' );\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tcode: languageCodeForHtml,\n\t\t\t\tdirection: $.uls.data.getDir( languageCodeForHtml ),\n\t\t\t\tautonym: $.uls.data.getAutonym( languageCode )\n\t\t\t};\n\t\t}\n\t} );\n\n\t/**\n\t * A warning to be shown if a user tries to close the page or navigate away\n\t * from it without saving the written translation.\n\t */\n\tfunction translateOnBeforeUnloadRegister() {\n\t\t$( window ).on( 'beforeunload', function () {\n\t\t\tif ( mw.translate.isDirty() ) {\n\t\t\t\t// Return our message\n\t\t\t\treturn mw.msg( 'translate-js-support-unsaved-warning' );\n\t\t\t}\n\t\t} );\n\t}\n\n\t$( function () {\n\t\ttranslateOnBeforeUnloadRegister();\n\t} );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.dropdownmenu.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.editor.helpers.js","messages":[{"ruleId":"jsdoc/require-returns","severity":1,"message":"Missing JSDoc @return declaration.","line":32,"column":3,"nodeType":"Block","endLine":32,"endColumn":19},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":84,"column":11,"nodeType":"CallExpression","endLine":111,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":84,"column":11,"nodeType":"CallExpression","endLine":114,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":93,"column":6,"nodeType":"CallExpression","endLine":97,"endColumn":9},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":93,"column":6,"nodeType":"CallExpression","endLine":102,"endColumn":9},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"e\" type.","line":393,"column":1,"nodeType":"Block","endLine":393,"endColumn":1},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"suggestion\" type.","line":394,"column":1,"nodeType":"Block","endLine":394,"endColumn":1},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":677,"column":5,"nodeType":"CallExpression","endLine":689,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":714,"column":4,"nodeType":"CallExpression","endLine":781,"endColumn":20},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":714,"column":4,"nodeType":"CallExpression","endLine":791,"endColumn":20},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":802,"column":17,"nodeType":"CallExpression","endLine":815,"endColumn":5},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":819,"column":2,"nodeType":"CallExpression","endLine":819,"endColumn":57}],"suppressedMessages":[{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":746,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":746,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'target_title' is not in camel case.","line":748,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":748,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_language' is not in camel case.","line":750,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":750,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'target_language' is not in camel case.","line":752,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":752,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":7,"fatalErrorCount":0,"warningCount":5,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * Translate editor additional helper functionality\n */\n( function () {\n\t'use strict';\n\n\tvar logger = require( 'ext.translate.eventlogginghelpers' );\n\n\tfunction getEditSummaryTimeWithDiff( pageTitle, comment ) {\n\t\tvar diffLink = mw.util.getUrl( pageTitle, {\n\t\t\toldid: comment.revisionId,\n\t\t\tdiff: 'prev'\n\t\t} );\n\n\t\treturn $( '<a>' )\n\t\t\t.addClass( 'edit-summary-time' )\n\t\t\t.attr(\n\t\t\t\t{\n\t\t\t\t\thref: diffLink,\n\t\t\t\t\ttarget: '_blank'\n\t\t\t\t}\n\t\t\t)\n\t\t\t.data( 'commentTimestamp', comment.timestamp )\n\t\t\t.text( comment.humanTimestamp );\n\t}\n\n\tfunction getSpacer() {\n\t\treturn '<span class=\"edit-summary-spacer\">·</span>';\n\t}\n\n\tvar translateEditorHelpers = {\n\t\t/** @internal */\n\t\tshowDocumentationEditor: function () {\n\t\t\tvar $infoColumnBlock = this.$editor.find( '.infocolumn-block' ),\n\t\t\t\t$editColumn = this.$editor.find( '.editcolumn' ),\n\t\t\t\t$messageDescEditor = $infoColumnBlock.find( '.message-desc-editor' ),\n\t\t\t\t$messageDescViewer = $infoColumnBlock.find( '.message-desc-viewer' );\n\n\t\t\t$infoColumnBlock\n\t\t\t\t.removeClass( 'five' )\n\t\t\t\t.addClass( 'seven' );\n\t\t\t$editColumn\n\t\t\t\t.removeClass( 'seven' )\n\t\t\t\t.addClass( 'five' );\n\n\t\t\t$messageDescViewer.addClass( 'hide' );\n\n\t\t\t$messageDescEditor.removeClass( 'hide' );\n\t\t\t$messageDescEditor.find( '.tux-textarea-documentation' ).trigger( 'focus' );\n\n\t\t\t// So that the link won't be followed\n\t\t\treturn false;\n\t\t},\n\n\t\t/** @internal */\n\t\thideDocumentationEditor: function () {\n\t\t\tvar $infoColumnBlock = this.$editor.find( '.infocolumn-block' ),\n\t\t\t\t$editColumn = this.$editor.find( '.editcolumn' ),\n\t\t\t\t$messageDescEditor = $infoColumnBlock.find( '.message-desc-editor' ),\n\t\t\t\t$messageDescViewer = $infoColumnBlock.find( '.message-desc-viewer' );\n\n\t\t\t$infoColumnBlock\n\t\t\t\t.removeClass( 'seven' )\n\t\t\t\t.addClass( 'five' );\n\t\t\t$editColumn\n\t\t\t\t.removeClass( 'five' )\n\t\t\t\t.addClass( 'seven' );\n\n\t\t\t$messageDescEditor.addClass( 'hide' );\n\t\t\t$messageDescViewer.removeClass( 'hide' );\n\t\t},\n\n\t\t/**\n\t\t * Save the documentation\n\t\t *\n\t\t * @internal\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tsaveDocumentation: function () {\n\t\t\tvar translateEditor = this,\n\t\t\t\tapi = new mw.Api(),\n\t\t\t\tnewDocumentation = translateEditor.$editor.find( '.tux-textarea-documentation' ).val();\n\n\t\t\treturn api.postWithToken( 'csrf', {\n\t\t\t\taction: 'edit',\n\t\t\t\ttitle: translateEditor.message.title\n\t\t\t\t\t.replace( /\\/[a-z-]+$/, '/' + mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ),\n\t\t\t\ttext: newDocumentation\n\t\t\t} ).done( function ( response ) {\n\t\t\t\tvar $messageDesc = translateEditor.$editor.find( '.infocolumn-block .message-desc' );\n\n\t\t\t\tif ( response.edit.result === 'Success' ) {\n\t\t\t\t\tapi.parse(\n\t\t\t\t\t\tnewDocumentation\n\t\t\t\t\t).done( function ( parsedDocumentation ) {\n\t\t\t\t\t\t$messageDesc.html( parsedDocumentation );\n\t\t\t\t\t} ).fail( function ( errorCode, results ) {\n\t\t\t\t\t\t// Note: It is possible for results to be undefined.\n\t\t\t\t\t\tvar errorInfo = results && results.error ? results.error.info : 'No information';\n\t\t\t\t\t\t$messageDesc.html( newDocumentation );\n\t\t\t\t\t\tmw.log( 'Error parsing documentation ' + errorCode + ' ' + errorInfo );\n\t\t\t\t\t} ).always( function () {\n\t\t\t\t\t\t// A collapsible element etc. may have been added\n\t\t\t\t\t\tmw.hook( 'wikipage.content' ).fire( $messageDesc );\n\t\t\t\t\t\ttranslateEditor.hideDocumentationEditor();\n\t\t\t\t\t} );\n\t\t\t\t} else {\n\t\t\t\t\tmw.notify( 'Error saving message documentation' );\n\t\t\t\t\tmw.log( 'Error saving documentation', response );\n\t\t\t\t}\n\t\t\t} ).fail( function ( errorCode, results ) {\n\t\t\t\tmw.notify( 'Error saving message documentation' );\n\t\t\t\tmw.log( 'Error saving documentation', errorCode, results );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Shows the message documentation.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} documentation A documentation object as returned by API.\n\t\t */\n\t\tshowMessageDocumentation: function ( documentation ) {\n\t\t\tif ( !mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar $messageDescViewer = this.$editor.find( '.message-desc-viewer' );\n\t\t\tvar $descEditLink = $messageDescViewer.find( '.message-desc-edit' );\n\t\t\tvar $messageDoc = $messageDescViewer.find( '.message-desc' );\n\n\t\t\t// Display the documentation only if it's not empty and\n\t\t\t// documentation language is configured\n\t\t\tif ( documentation.error ) {\n\t\t\t\t// TODO: better error handling, especially since the presence of documentation\n\t\t\t\t// is heavily hinted at in the UI\n\t\t\t\treturn;\n\t\t\t} else if ( documentation.value ) {\n\t\t\t\tvar documentationDir = $.uls.data.getDir( documentation.language );\n\n\t\t\t\t// Show the documentation and set appropriate\n\t\t\t\t// lang and dir attributes.\n\t\t\t\t// The message documentation is assumed to be written\n\t\t\t\t// in the content language of the wiki.\n\t\t\t\tvar langAttr = {\n\t\t\t\t\tlang: documentation.language,\n\t\t\t\t\tdir: documentationDir\n\t\t\t\t};\n\n\t\t\t\t// Possible classes:\n\t\t\t\t// * mw-content-ltr\n\t\t\t\t// * mw-content-rtl\n\t\t\t\t// (The direction classes are needed, because the documentation\n\t\t\t\t// is likely to be MediaWiki-formatted text.)\n\t\t\t\t$messageDoc\n\t\t\t\t\t.attr( langAttr )\n\t\t\t\t\t.addClass( 'mw-content-' + documentationDir )\n\t\t\t\t\t.html( documentation.html );\n\n\t\t\t\t$messageDoc.find( 'a[href]' ).prop( 'target', '_blank' );\n\n\t\t\t\tthis.$editor.find( '.tux-textarea-documentation' )\n\t\t\t\t\t.attr( langAttr )\n\t\t\t\t\t.val( documentation.value );\n\n\t\t\t\t$descEditLink.text( mw.msg( 'tux-editor-edit-desc' ) );\n\n\t\t\t\tif ( documentation.html.length > 500 ) {\n\t\t\t\t\tvar $readMore = $( '<span>' )\n\t\t\t\t\t\t.addClass( 'read-more column' )\n\t\t\t\t\t\t.text( mw.msg( 'tux-editor-message-desc-more' ) );\n\n\t\t\t\t\tvar expand = function () {\n\t\t\t\t\t\t$messageDoc.removeClass( 'compact' );\n\t\t\t\t\t\t$readMore.text( mw.msg( 'tux-editor-message-desc-less' ) );\n\t\t\t\t\t};\n\n\t\t\t\t\tvar readMore = function () {\n\t\t\t\t\t\tif ( $messageDoc.hasClass( 'compact' ) ) {\n\t\t\t\t\t\t\texpand();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$messageDoc.addClass( 'compact' );\n\t\t\t\t\t\t\t$readMore.text( mw.msg( 'tux-editor-message-desc-more' ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\n\t\t\t\t\t$readMore.on( 'click', readMore );\n\n\t\t\t\t\t$messageDescViewer.find( '.message-desc-control' )\n\t\t\t\t\t\t.prepend( $readMore );\n\n\t\t\t\t\t$messageDoc.addClass( 'long compact' ).on( 'mouseenter mouseleave', expand );\n\t\t\t\t}\n\n\t\t\t\t// Enable dynamic content, such as collapsible elements\n\t\t\t\tmw.hook( 'wikipage.content' ).fire( $messageDoc );\n\t\t\t} else {\n\t\t\t\t$descEditLink.text( mw.msg( 'tux-editor-add-desc' ) );\n\t\t\t}\n\n\t\t\t$messageDescViewer.removeClass( 'hide' );\n\t\t},\n\n\t\t/**\n\t\t * Shows uneditable documentation.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} documentation A gettext object as returned by API.\n\t\t */\n\t\tshowUneditableDocumentation: function ( documentation ) {\n\t\t\tif ( documentation.error ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar dir = $.uls.data.getDir( documentation.language );\n\n\t\t\t// The following classes are used here:\n\t\t\t// * mw-content-ltr\n\t\t\t// * mw-content-rtl\n\t\t\tthis.$editor.find( '.uneditable-documentation' )\n\t\t\t\t.attr( {\n\t\t\t\t\tlang: documentation.language,\n\t\t\t\t\tdir: dir\n\t\t\t\t} )\n\t\t\t\t.addClass( 'mw-content-' + dir )\n\t\t\t\t.html( documentation.html )\n\t\t\t\t.removeClass( 'hide' );\n\t\t},\n\n\t\t/**\n\t\t * Shows the translations from other languages\n\t\t *\n\t\t * @internal\n\t\t * @param {Array} translations An inotherlanguages array as returned by the translation helpers API.\n\t\t */\n\t\tshowAssistantLanguages: function ( translations ) {\n\t\t\tif ( translations.error ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( !translations.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar $elements = translations.map( function ( translation ) {\n\t\t\t\tvar langAttr = {\n\t\t\t\t\tlang: translation.language,\n\t\t\t\t\tdir: $.uls.data.getDir( translation.language )\n\t\t\t\t};\n\n\t\t\t\tvar $element = $( '<div>' )\n\t\t\t\t\t.addClass( 'row in-other-language' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'nine columns suggestiontext' )\n\t\t\t\t\t\t\t.attr( langAttr )\n\t\t\t\t\t\t\t.text( translation.value ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'three columns language text-right' )\n\t\t\t\t\t\t\t.attr( langAttr )\n\t\t\t\t\t\t\t.text( $.uls.data.getAutonym( translation.language ) )\n\t\t\t\t\t);\n\n\t\t\t\tthis.suggestionAdder( $element, translation.value, 'assistant language' );\n\n\t\t\t\treturn $element;\n\t\t\t}.bind( this ) );\n\n\t\t\tthis.$editor.find( '.in-other-languages-title' )\n\t\t\t\t.removeClass( 'hide' )\n\t\t\t\t.after( $elements );\n\t\t},\n\n\t\t/**\n\t\t * Shows the translation suggestions from Translation Memory\n\t\t *\n\t\t * @internal\n\t\t * @param {Array} translations A ttmserver array as returned by API.\n\t\t */\n\t\tshowTranslationMemory: function ( translations ) {\n\t\t\tif ( !translations.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Container for the suggestions\n\t\t\tvar $tmSuggestions = $( '<div>' ).addClass( 'tm-suggestions' );\n\n\t\t\tvar $heading = this.$editor.find( '.tm-suggestions-title' );\n\t\t\t$heading.after( $tmSuggestions );\n\n\t\t\tvar $messageList = $( '.tux-messagelist' );\n\t\t\tvar lang = $messageList.data( 'targetlangcode' );\n\t\t\tvar dir = $messageList.data( 'targetlangdir' );\n\n\t\t\tvar suggestions = {};\n\n\t\t\ttranslations.forEach( function ( translation ) {\n\t\t\t\t// Remove once formatversion=2\n\t\t\t\tif ( translation.local === '' ) {\n\t\t\t\t\ttranslation.local = true;\n\t\t\t\t} else if ( translation.local === undefined ) {\n\t\t\t\t\ttranslation.local = false;\n\t\t\t\t}\n\n\t\t\t\tif ( translation.local && translation.location === this.message.title ) {\n\t\t\t\t\t// Do not add self-suggestions\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Check if suggestion with this value already exists\n\t\t\t\tvar suggestion = suggestions[ translation.target ];\n\t\t\t\tif ( suggestion ) {\n\t\t\t\t\tsuggestion.count++;\n\t\t\t\t\tsuggestion.sources.push( translation );\n\t\t\t\t\tsuggestion.$showSourcesElement.children( 'a' ).text(\n\t\t\t\t\t\tmw.msg(\n\t\t\t\t\t\t\t'tux-editor-n-uses',\n\t\t\t\t\t\t\tmw.language.convertNumber( suggestion.count )\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tsuggestion = {};\n\n\t\t\t\tsuggestion.$showSourcesElement = $( '<div>' )\n\t\t\t\t\t.addClass( 'text-right columns twelve' )\n\t\t\t\t\t.append( $( '<a>' ).addClass( 'n-uses' ) );\n\n\t\t\t\tsuggestion.$element = $( '<div>' )\n\t\t\t\t\t.addClass( 'row tm-suggestion' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'nine columns suggestiontext' )\n\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\tlang: lang,\n\t\t\t\t\t\t\t\tdir: dir\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.text( translation.target ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'three columns quality text-right' )\n\t\t\t\t\t\t\t.text(\n\t\t\t\t\t\t\t\tmw.msg(\n\t\t\t\t\t\t\t\t\t'tux-editor-tm-match',\n\t\t\t\t\t\t\t\t\tmw.language.convertNumber( Math.floor( translation.quality * 100 ) )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\tsuggestion.$showSourcesElement\n\t\t\t\t\t);\n\n\t\t\t\tsuggestion.count = 1;\n\t\t\t\tsuggestion.sources = [];\n\t\t\t\tsuggestion.sources.push( translation );\n\n\t\t\t\tthis.suggestionAdder( suggestion.$element, translation.target, 'translation memory' );\n\n\t\t\t\tsuggestions[ translation.target ] = suggestion;\n\t\t\t}, this );\n\n\t\t\tif ( $.isEmptyObject( suggestions ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar currentSuggestionsOrder = [];\n\t\t\tObject.keys( suggestions ).forEach( function ( key ) {\n\t\t\t\tcurrentSuggestionsOrder.push( {\n\t\t\t\t\tkey: key,\n\t\t\t\t\tcount: suggestions[ key ].count,\n\t\t\t\t\tquality: suggestions[ key ].sources[ 0 ].quality\n\t\t\t\t} );\n\t\t\t} );\n\n\t\t\tcurrentSuggestionsOrder.sort( function ( a, b ) {\n\t\t\t\tif ( a.quality === b.quality ) {\n\t\t\t\t\treturn b.count - a.count;\n\t\t\t\t}\n\t\t\t\treturn a.quality < b.quality ? 1 : -1;\n\t\t\t} );\n\n\t\t\tcurrentSuggestionsOrder.forEach( function ( item ) {\n\t\t\t\tvar currentSuggestion = suggestions[ item.key ];\n\t\t\t\tcurrentSuggestion.$showSourcesElement.on( 'click', function ( e ) {\n\t\t\t\t\tthis.onShowTranslationMemorySources( e, currentSuggestion );\n\t\t\t\t}.bind( this ) );\n\t\t\t\t$tmSuggestions.append( currentSuggestion.$element );\n\t\t\t}, this );\n\n\t\t\t$heading.removeClass( 'hide' );\n\t\t},\n\n\t\t/**\n\t\t * @param e\n\t\t * @param suggestion\n\t\t * @internal\n\t\t */\n\t\tonShowTranslationMemorySources: function ( e, suggestion ) {\n\t\t\te.stopPropagation();\n\n\t\t\tif ( suggestion.$sourcesElement ) {\n\t\t\t\tsuggestion.$sourcesElement.toggleClass( 'hide' );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Build the sources list. Add class to show external icons :(\n\t\t\tsuggestion.$sourcesElement = $( '<ul>' )\n\t\t\t\t.addClass( 'tux-tm-suggestion-source mw-parser-output' );\n\n\t\t\t// Sort local suggestions first, then alphabetically\n\t\t\tsuggestion.sources.sort( function ( a, b ) {\n\t\t\t\tif ( a.local === b.local ) {\n\t\t\t\t\treturn a.location.localeCompare( b.location );\n\t\t\t\t} else {\n\t\t\t\t\treturn a.local ? -1 : 1;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tsuggestion.sources.forEach( function ( translation ) {\n\t\t\t\tsuggestion.$sourcesElement.append(\n\t\t\t\t\t$( '<li>' )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t\t\t.prop( 'target', '_blank' )\n\t\t\t\t\t\t\t\t.prop( 'href', translation.editorUrl || translation.uri )\n\t\t\t\t\t\t\t\t.text( translation.location )\n\t\t\t\t\t\t\t\t.toggleClass( 'external', !translation.local )\n\t\t\t\t\t\t)\n\t\t\t\t);\n\t\t\t} );\n\t\t\tsuggestion.$element.after( suggestion.$sourcesElement );\n\t\t},\n\n\t\t/**\n\t\t * Shows the translation from machine translation systems\n\t\t *\n\t\t * @internal\n\t\t * @param {Array} suggestions\n\t\t */\n\t\tshowMachineTranslations: function ( suggestions ) {\n\t\t\tif ( !suggestions.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar translateEditor = this;\n\n\t\t\tvar $mtSuggestions = this.$editor.find( '.tm-suggestions' );\n\n\t\t\tif ( !$mtSuggestions.length ) {\n\t\t\t\t$mtSuggestions = $( '<div>' ).addClass( 'tm-suggestions' );\n\t\t\t}\n\n\t\t\tthis.$editor.find( '.tm-suggestions-title' )\n\t\t\t\t.removeClass( 'hide' )\n\t\t\t\t.after( $mtSuggestions );\n\n\t\t\tvar $messageList = $( '.tux-messagelist' );\n\t\t\tvar translationLang = $messageList.data( 'targetlangcode' );\n\t\t\tvar translationDir = $messageList.data( 'targetlangdir' );\n\n\t\t\tsuggestions.forEach( function ( translation ) {\n\t\t\t\tvar $translation;\n\n\t\t\t\t$translation = $( '<div>' )\n\t\t\t\t\t.addClass( 'row tm-suggestion' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'nine columns suggestiontext' )\n\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\tlang: translationLang,\n\t\t\t\t\t\t\t\tdir: translationDir\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.text( translation.target ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'three columns text-right service' )\n\t\t\t\t\t\t\t.text( translation.service )\n\t\t\t\t\t);\n\n\t\t\t\ttranslateEditor.suggestionAdder( $translation, translation.target, translation.service );\n\n\t\t\t\t$mtSuggestions.append( $translation );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Makes the $source element clickable and clicking it will replace the\n\t\t * translation textarea with the given suggestion.\n\t\t *\n\t\t * @internal\n\t\t * @param {jQuery} $source\n\t\t * @param {string} suggestion Text to add\n\t\t * @param {string} service TTM service\n\t\t */\n\t\tsuggestionAdder: function ( $source, suggestion, service ) {\n\t\t\tvar $target = this.$editor.find( '.tux-textarea-translation' );\n\t\t\tif ( $target.get( 0 ).readOnly ) {\n\t\t\t\t// If the textarea is disabled, then disable the translation aid.\n\t\t\t\t// Do not add the click handler.\n\t\t\t\t$source.addClass( 'tux-translation-aid-disabled' );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst inserter = () => {\n\t\t\t\tvar selection;\n\t\t\t\tif ( window.getSelection ) {\n\t\t\t\t\tselection = window.getSelection().toString();\n\t\t\t\t} else if ( document.selection && document.selection.type !== 'Control' ) {\n\t\t\t\t\tselection = document.selection.createRange().text;\n\t\t\t\t}\n\n\t\t\t\tif ( !selection ) {\n\t\t\t\t\t$target.val( suggestion ).trigger( 'focus' ).trigger( 'input' );\n\t\t\t\t}\n\t\t\t\tlogger.logClickEvent( 'accept_suggestion', service );\n\n\t\t\t\t// Remove all 'tux-suggestion-aid-used' classes on the page, we only need the one\n\t\t\t\t// that was most recently clicked.\n\t\t\t\tthis.$editor.find( '.tux-suggestion-aid-used' ).removeClass( 'tux-suggestion-aid-used' );\n\t\t\t\t$source.addClass( 'tux-suggestion-aid-used' );\n\t\t\t};\n\n\t\t\t$source.on( 'click', inserter )\n\t\t\t\t.addClass( 'shortcut-activated' );\n\t\t},\n\n\t\t/**\n\t\t * Shows the support options for the translator.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} support A support object as returned by API.\n\t\t */\n\t\tshowSupportOptions: function ( support ) {\n\t\t\t// Support URL\n\t\t\tif ( support.url ) {\n\t\t\t\tthis.$editor.find( '.help a' ).attr( 'href', support.url );\n\t\t\t\tthis.$editor.find( '.help' ).removeClass( 'hide' );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Adds buttons for quickly inserting insertables.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} insertables A insertables object as returned by API.\n\t\t */\n\t\taddInsertables: function ( insertables ) {\n\t\t\tvar count = insertables.length,\n\t\t\t\t$sourceMessage = this.$editor.find( '.sourcemessage' ),\n\t\t\t\t$buttonArea = this.$editor.find( '.tux-editor-insert-buttons' ),\n\t\t\t\t$textarea = this.$editor.find( '.tux-textarea-translation' );\n\n\t\t\tfor ( var i = 0; i < count; i++ ) {\n\t\t\t\t// The dir and lang attributes must be set here,\n\t\t\t\t// because the language of the insertables is the language\n\t\t\t\t// of the source message and not of the translation.\n\t\t\t\t// The direction may appear confusing, for example,\n\t\t\t\t// in tvar strings, which would appear with the dollar sign\n\t\t\t\t// on the wrong end.\n\t\t\t\t$( '<button>' )\n\t\t\t\t\t.prop( {\n\t\t\t\t\t\tlang: $sourceMessage.prop( 'lang' ),\n\t\t\t\t\t\tdir: $sourceMessage.prop( 'dir' )\n\t\t\t\t\t} )\n\t\t\t\t\t.addClass( 'insertable shortcut-activated' )\n\t\t\t\t\t.text( insertables[ i ].display )\n\t\t\t\t\t.data( 'iid', i )\n\t\t\t\t\t.appendTo( $buttonArea );\n\t\t\t}\n\n\t\t\t$buttonArea.on( 'click', '.insertable', function () {\n\t\t\t\tvar data = insertables[ $( this ).data( 'iid' ) ];\n\t\t\t\tif ( data.post === '' ) { // 1-piece insertables\n\t\t\t\t\t$textarea.textSelection( 'replaceSelection', data.pre );\n\t\t\t\t} else {\n\t\t\t\t\t$textarea.textSelection( 'encapsulateSelection', {\n\t\t\t\t\t\tpre: data.pre,\n\t\t\t\t\t\tpost: data.post\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t\t$textarea.trigger( 'focus' ).trigger( 'input' );\n\t\t\t} );\n\n\t\t\tthis.resizeInsertables( $textarea );\n\t\t},\n\n\t\t/**\n\t\t * Loads and shows edit summaries\n\t\t *\n\t\t * @internal\n\t\t * @param {Array} editsummaries An array of edit summaries as returned by the API\n\t\t */\n\t\tshowEditSummaries: function ( editsummaries ) {\n\t\t\tif ( !editsummaries.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar $editSummariesContainer = this.$editor.find( '.edit-summaries' );\n\n\t\t\tif ( !$editSummariesContainer.length ) {\n\t\t\t\t$editSummariesContainer = $( '<div>' ).addClass( 'edit-summaries' );\n\t\t\t}\n\t\t\tvar $editSummariesTitle = this.$editor.find( '.edit-summaries-title' );\n\t\t\t$editSummariesTitle.after( $editSummariesContainer );\n\t\t\tvar $summaryList = $( '<ul>' );\n\t\t\tvar lastEmptySummaryCount = 0;\n\t\t\tvar pageTitle = this.message.title;\n\t\t\teditsummaries.forEach( function ( comment ) {\n\t\t\t\tvar $summaryListItem = $( '<li>' );\n\t\t\t\t// An additional tag is added so that display: list-item can be retained\n\t\t\t\t// for the <li> tag\n\t\t\t\tvar $summaryItem = $( '<span>' );\n\n\t\t\t\tif ( comment.summary === '' ) {\n\t\t\t\t\tvar $lastSummaryItem = $summaryList.find( 'li' ).last();\n\n\t\t\t\t\t// Last item added was an empty summary and the current one is also empty,\n\t\t\t\t\t// so update that instead of adding a new one.\n\t\t\t\t\tif ( $lastSummaryItem.hasClass( 'update-without-summary' ) ) {\n\t\t\t\t\t\t$lastSummaryItem.find( 'span' ).text(\n\t\t\t\t\t\t\tmw.msg(\n\t\t\t\t\t\t\t\t'tux-editor-changes-without-summary',\n\t\t\t\t\t\t\t\tmw.language.convertNumber( ++lastEmptySummaryCount )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t\t// Remove the timestamp link if there is more than one empty summary.\n\t\t\t\t\t\t$lastSummaryItem.find( '.edit-summary-time' ).remove();\n\t\t\t\t\t\t// Remove the spacer since we no longer have a timestamp\n\t\t\t\t\t\t$lastSummaryItem.find( '.edit-summary-spacer' ).remove();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Add a new empty summary list item\n\t\t\t\t\t\t$summaryItem.append(\n\t\t\t\t\t\t\t$( '<span>' ).text(\n\t\t\t\t\t\t\t\tmw.msg(\n\t\t\t\t\t\t\t\t\t'tux-editor-changes-without-summary',\n\t\t\t\t\t\t\t\t\tmw.language.convertNumber( ++lastEmptySummaryCount )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\tgetSpacer(),\n\t\t\t\t\t\t\tgetEditSummaryTimeWithDiff( pageTitle, comment )\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t$summaryList.append(\n\t\t\t\t\t\t\t$summaryListItem\n\t\t\t\t\t\t\t\t.addClass( 'update-without-summary' )\n\t\t\t\t\t\t\t\t.append( $summaryItem )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tlastEmptySummaryCount = 0;\n\t\t\t\t\t$summaryItem.append(\n\t\t\t\t\t\t$( '<bdi>' )\n\t\t\t\t\t\t\t.prop( 'lang', '' )\n\t\t\t\t\t\t\t.addClass( 'edit-summary-message' )\n\t\t\t\t\t\t\t.html( comment.summary ),\n\t\t\t\t\t\tgetSpacer(),\n\t\t\t\t\t\tgetEditSummaryTimeWithDiff( pageTitle, comment )\n\t\t\t\t\t);\n\n\t\t\t\t\t$summaryList.append( $summaryListItem.append( $summaryItem ) );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t$editSummariesContainer.append( $summaryList );\n\t\t\t$editSummariesTitle.removeClass( 'hide' );\n\t\t},\n\n\t\t/** @internal */\n\t\tupdateEditSummaryTimestamp: function () {\n\t\t\t// If the editor is hidden, don't bother updating anything or setting up another timeout\n\t\t\tif ( this.$editor.hasClass( 'hide' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar $dateEntries = this.$editor.find( '.edit-summary-time' );\n\t\t\t// Edit summaries may not be loaded yet.\n\t\t\t// It is also possible that there are no summary or date entries.\n\t\t\tif ( $dateEntries.length !== 0 ) {\n\t\t\t\t// There are some date entries, load moment.js and update them.\n\t\t\t\tmw.loader.using( 'moment' ).done(\n\t\t\t\t\tfunction () {\n\t\t\t\t\t\t// Update the time for the edit summaries if a user leaves their\n\t\t\t\t\t\t// browser open and comes back later.\n\t\t\t\t\t\t$dateEntries.each( function () {\n\t\t\t\t\t\t\tvar $entry = $( this );\n\t\t\t\t\t\t\tvar timeago = moment\n\t\t\t\t\t\t\t\t.utc( $entry.data( 'commentTimestamp' ), 'YYYYMMDDhhmmss' )\n\t\t\t\t\t\t\t\t.fromNow();\n\t\t\t\t\t\t\t$entry.text( timeago );\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tsetTimeout( this.updateEditSummaryTimestamp.bind( this ), 20000 );\n\t\t},\n\n\t\t/**\n\t\t * Handles any necessary updates to translation helpers when an editor is reopened.\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tupdateTranslationHelpers: function () {\n\t\t\tthis.updateEditSummaryTimestamp();\n\t\t},\n\n\t\t/**\n\t\t * Loads and shows the translation helpers.\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tshowTranslationHelpers: function () {\n\t\t\t// API call to get translation suggestions from other languages\n\t\t\t// callback should render suggestions to the editor's info column\n\t\t\tvar api = new mw.Api();\n\n\t\t\tapi.get( {\n\t\t\t\taction: 'translationaids',\n\t\t\t\ttitle: this.message.title,\n\t\t\t\tuselang: mw.config.get( 'wgUserLanguage' )\n\t\t\t} ).done( function ( result ) {\n\t\t\t\tthis.$editor.find( '.infocolumn .loading' ).remove();\n\n\t\t\t\tif ( !result.helpers ) {\n\t\t\t\t\tmw.log.warn( 'API did not return any translation helpers.' );\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tvar suggestionsProvided = [];\n\t\t\t\tvar mtSuggestions = result.helpers.mt;\n\t\t\t\tif ( Array.isArray( mtSuggestions ) ) {\n\t\t\t\t\tsuggestionsProvided = mtSuggestions.map( function ( suggestion ) {\n\t\t\t\t\t\treturn suggestion.service;\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tvar ttmSuggestions = result.helpers.ttmserver;\n\t\t\t\tif ( Array.isArray( ttmSuggestions ) && ttmSuggestions.length ) {\n\t\t\t\t\tsuggestionsProvided.push( 'translation_memory' );\n\t\t\t\t}\n\n\t\t\t\tif ( suggestionsProvided ) {\n\t\t\t\t\tlogger.logEvent(\n\t\t\t\t\t\t'suggestion',\n\t\t\t\t\t\t'',\n\t\t\t\t\t\tsuggestionsProvided.join( '; ' ),\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tsource_title: this.message.group + '|' + this.message.title,\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\ttarget_title: this.message.title,\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tsource_language: result.helpers.definition.language,\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\ttarget_language: this.message.targetLanguage\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tthis.showMessageDocumentation( result.helpers.documentation );\n\t\t\t\tthis.showUneditableDocumentation( result.helpers.gettext );\n\t\t\t\tthis.showAssistantLanguages( result.helpers.inotherlanguages );\n\t\t\t\tthis.showTranslationMemory( ttmSuggestions );\n\t\t\t\tthis.showMachineTranslations( mtSuggestions );\n\t\t\t\tthis.showSupportOptions( result.helpers.support );\n\t\t\t\tthis.addDefinitionDiff( result.helpers.definitiondiff );\n\t\t\t\tthis.addInsertables( result.helpers.insertables );\n\t\t\t\tthis.showEditSummaries( result.helpers.editsummaries );\n\n\t\t\t\t// Load the possible warnings as soon as possible, do not wait\n\t\t\t\t// for the user to make changes. Otherwise users might try confirming\n\t\t\t\t// translations which fail checks. Confirmation seems to work but\n\t\t\t\t// the message will continue to appear outdated.\n\t\t\t\tif ( this.message.properties &&\n\t\t\t\t\tthis.message.properties.status === 'fuzzy'\n\t\t\t\t) {\n\t\t\t\t\tthis.validateTranslation();\n\t\t\t\t}\n\n\t\t\t\tmw.hook( 'mw.translate.editor.showTranslationHelpers' ).fire(\n\t\t\t\t\tresult.helpers, this.$editor\n\t\t\t\t);\n\n\t\t\t}.bind( this ) ).fail( function ( errorCode, results ) {\n\t\t\t\t// results.error may be undefined\n\t\t\t\tvar errorInfo = results && results.error && results.error.info || 'Unknown error';\n\t\t\t\tthis.$editor.find( '.infocolumn .loading' ).remove();\n\t\t\t\tthis.$editor.find( '.infocolumn' ).append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.text( mw.msg( 'tux-editor-loading-failed', errorInfo ) )\n\t\t\t\t\t\t.addClass( 'mw-message-box-warning mw-message-box tux-translation-aid-error' )\n\t\t\t\t);\n\t\t\t\tmw.log.error( 'Error loading translation aids:', errorCode, results );\n\t\t\t}.bind( this ) );\n\n\t\t\tmw.hook( 'mw.translate.editor.afterEditorShown' ).add( function () {\n\t\t\t\t// Take care of updating any helpers when the editor is opened\n\t\t\t\tthis.updateTranslationHelpers();\n\t\t\t}.bind( this ) );\n\t\t}\n\t};\n\n\tmw.translate = mw.translate || {};\n\n\tmw.translate = $.extend( mw.translate, {\n\t\t/**\n\t\t * Get the documentation edit URL for a title\n\t\t *\n\t\t * @param {string} title Message title with namespace\n\t\t * @return {string} URL for editing the documentation\n\t\t */\n\t\tgetDocumentationEditURL: function ( title ) {\n\t\t\treturn mw.util.getUrl(\n\t\t\t\ttitle + '/' + mw.config.get( 'wgTranslateDocumentationLanguageCode' ),\n\t\t\t\t{ action: 'edit' }\n\t\t\t);\n\t\t}\n\t} );\n\n\t// Extend the translate editor\n\tmw.translate.editor = mw.translate.editor || {};\n\t$.extend( mw.translate.editor, translateEditorHelpers );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.editor.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":270,"column":4,"nodeType":"CallExpression","endLine":310,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":270,"column":4,"nodeType":"CallExpression","endLine":373,"endColumn":7},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":773,"column":6,"nodeType":"CallExpression","endLine":773,"endColumn":67},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":1124,"column":22,"nodeType":"CallExpression","endLine":1163,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":1283,"column":7,"nodeType":"CallExpression","endLine":1288,"endColumn":11},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":1646,"column":24,"nodeType":"CallExpression","endLine":1646,"endColumn":82}],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":143,"column":4,"nodeType":"CallExpression","endLine":144,"endColumn":56,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'target_type' is not in camel case.","line":236,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":236,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":238,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":238,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'modification_rate' is not in camel case.","line":298,"column":9,"nodeType":"Identifier","messageId":"notCamelCase","endLine":298,"endColumn":26,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":300,"column":9,"nodeType":"Identifier","messageId":"notCamelCase","endLine":300,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":325,"column":7,"nodeType":"CallExpression","messageId":"unexpected","endLine":325,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":361,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":361,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":945,"column":9,"nodeType":"Identifier","messageId":"notCamelCase","endLine":945,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_type' is not in camel case.","line":947,"column":9,"nodeType":"Identifier","messageId":"notCamelCase","endLine":947,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":998,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":998,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_type' is not in camel case.","line":1000,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":1000,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":1103,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":1103,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_type' is not in camel case.","line":1105,"column":8,"nodeType":"Identifier","messageId":"notCamelCase","endLine":1105,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":1221,"column":18,"nodeType":"CallExpression","endLine":1222,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-use-before-define","severity":2,"message":"'$messageDescViewer' was used before it was defined.","line":1286,"column":29,"nodeType":"Identifier","messageId":"usedBeforeDefined","endLine":1286,"endColumn":47,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":1532,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":1532,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_type' is not in camel case.","line":1534,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":1534,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":4,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/* global autosize */\n\n( function () {\n\t'use strict';\n\n\tvar logger = require( 'ext.translate.eventlogginghelpers' );\n\tvar mtHelpers = require( 'ext.translate.mtHelpers' );\n\t/**\n\t * Dictionary of classes that will be used by different types of notices\n\t * TODO: Should probably review and rename these classes in the future to\n\t * be more unique to the translate extension? Some themes use warning,\n\t * error classes to style elements, and we do take help from these.\n\t */\n\tvar noticeTypes = {\n\t\twarning: 'warning',\n\t\terror: 'error',\n\t\ttranslateFail: 'translation-saving',\n\t\tdiff: 'diff',\n\t\tfuzzy: 'fuzzy',\n\t\tgetAllClasses: function () {\n\t\t\tvar classes = [];\n\n\t\t\tfor ( var prop in this ) {\n\t\t\t\tif ( typeof this[ prop ] === 'string' ) {\n\t\t\t\t\tclasses.push( this[ prop ] );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn classes;\n\t\t}\n\t};\n\n\t/**\n\t * TranslateEditor Plugin\n\t * Prepare the translation editor UI for a translation unit (message).\n\t * This is mainly used with the messagetable plugin,\n\t * but it is independent of messagetable.\n\t * Example usage:\n\t *\n\t *     $( 'div.messageRow' ).translateeditor( {\n\t *         message: messageObject // Mandatory message object\n\t *     } );\n\t *\n\t * Assumptions: The jquery element to which translateeditor is applied will\n\t * internally contain the editor's generated UI. So it is going to have the same width\n\t * and inherited properies of the container.\n\t * The container can mark the message item with class 'message'. This is not\n\t * mandatory, but if found, when the editor is opened, the message item will be hidden\n\t * and the editor will appear as if the message is replaced by the editor.\n\t * See the UI of Translate messagetable for a demo.\n\t *\n\t * @private\n\t * @param {HTMLElement} element\n\t * @param {Object} options\n\t * @param {Function} [options.beforeSave] Callback to call when translation is going to be saved.\n\t * @param {Function} [options.onReady] Callback to call when the editor is ready.\n\t * @param {Function} [options.onSave] Callback to call when translation has been saved.\n\t * @param {Function} [options.onSkip] Callback to call when a message is skipped.\n\t * @param {Object} options.message Object as returned by messagecollection api.\n\t * @param {mw.translate.TranslationApiStorage} [options.storage]\n\t */\n\tfunction TranslateEditor( element, options ) {\n\t\tthis.$editTrigger = $( element );\n\t\tthis.$editor = null;\n\t\tthis.options = options;\n\t\tthis.message = this.options.message;\n\t\tthis.$messageItem = this.$editTrigger.find( '.message' );\n\t\tthis.shown = false;\n\t\tthis.dirty = false;\n\t\tthis.saving = false;\n\t\tthis.expanded = false;\n\t\tthis.listen();\n\t\tthis.storage = this.options.storage || new mw.translate.TranslationApiStorage();\n\t\tthis.canDelete = mw.translate.canDelete();\n\t\tthis.editFontClass = 'mw-editfont-' + mw.user.options.get( 'editfont' );\n\t\tthis.delayValidation = delayer();\n\t\tthis.validating = null;\n\t}\n\n\tTranslateEditor.prototype = {\n\n\t\t/**\n\t\t * Initialize the plugin\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tinit: function () {\n\t\t\t// In case we have already created the editor earlier,\n\t\t\t// don't add a new one. The existing one may have unsaved\n\t\t\t// changes.\n\t\t\tif ( this.$editor ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.render();\n\t\t\t// onReady callback\n\t\t\tif ( this.options.onReady ) {\n\t\t\t\tthis.options.onReady.call( this );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Render the editor UI\n\t\t *\n\t\t * @private\n\t\t */\n\t\trender: function () {\n\t\t\tthis.$editor = $( '<div>' )\n\t\t\t\t.addClass( 'row tux-message-editor hide' )\n\t\t\t\t.append(\n\t\t\t\t\tthis.prepareEditorColumn(),\n\t\t\t\t\tthis.prepareInfoColumn()\n\t\t\t\t);\n\n\t\t\tthis.expanded = false;\n\t\t\tthis.$editTrigger.append( this.$editor );\n\n\t\t\tif ( this.message.properties && this.message.properties.status === 'fuzzy' ) {\n\t\t\t\tthis.addNotice(\n\t\t\t\t\tmw.message( 'tux-editor-outdated-notice' ).escaped(),\n\t\t\t\t\tnoticeTypes.fuzzy\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.showTranslationHelpers();\n\t\t},\n\n\t\t/**\n\t\t * Mark the message as unsaved because of edits, can be resumed later\n\t\t *\n\t\t * @private\n\t\t * @param {string} [highlightClass] Class for background highlighting\n\t\t */\n\t\tmarkUnsaved: function ( highlightClass ) {\n\t\t\tvar $tuxListStatus = this.$editTrigger.find( '.tux-list-status' );\n\n\t\t\thighlightClass = highlightClass || 'tux-highlight';\n\n\t\t\t$tuxListStatus.children( '.tux-status-unsaved' ).remove();\n\t\t\t$tuxListStatus.children().addClass( 'hide' );\n\t\t\t// `highlightClass` documented above\n\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\t$( '<span>' )\n\t\t\t\t.addClass( 'tux-status-unsaved ' + highlightClass )\n\t\t\t\t.text( mw.msg( 'tux-status-unsaved' ) )\n\t\t\t\t.appendTo( $tuxListStatus );\n\t\t},\n\n\t\t/**\n\t\t * Mark the message as unsaved because of saving failure.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tmarkUnsavedFailure: function () {\n\t\t\tthis.markUnsaved( 'tux-notice' );\n\t\t},\n\n\t\t/**\n\t\t * Mark the message as no longer unsaved\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tmarkUnunsaved: function () {\n\t\t\tvar $tuxListStatus = this.$editTrigger.find( '.tux-list-status' );\n\n\t\t\t$tuxListStatus.children( '.tux-status-unsaved' ).remove();\n\t\t\t$tuxListStatus.children().removeClass( 'hide' );\n\n\t\t\tthis.dirty = false;\n\t\t\tmw.translate.dirty = false;\n\t\t},\n\n\t\t/**\n\t\t * Mark the message as being saved\n\t\t *\n\t\t * @private\n\t\t */\n\t\tmarkSaving: function () {\n\t\t\tvar $tuxListStatus = this.$editTrigger.find( '.tux-list-status' );\n\n\t\t\t// Disable the save button\n\t\t\tthis.$editor.find( '.tux-editor-save-button' )\n\t\t\t\t.prop( 'disabled', true );\n\n\t\t\t// Add a \"Saving\" indicator\n\t\t\t$tuxListStatus.empty();\n\t\t\t$( '<span>' )\n\t\t\t\t.addClass( 'tux-status-unsaved' )\n\t\t\t\t.text( mw.msg( 'tux-status-saving' ) )\n\t\t\t\t.appendTo( $tuxListStatus );\n\t\t},\n\n\t\t/**\n\t\t * Mark the message as translated and successfully saved.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tmarkTranslated: function () {\n\t\t\tthis.$editTrigger.find( '.tux-list-status' )\n\t\t\t\t.empty()\n\t\t\t\t.append( $( '<span>' )\n\t\t\t\t\t.addClass( 'tux-status-translated' )\n\t\t\t\t\t.text( mw.msg( 'tux-status-translated' ) )\n\t\t\t\t);\n\n\t\t\tthis.$messageItem\n\t\t\t\t.removeClass( 'untranslated translated fuzzy proofread' )\n\t\t\t\t.addClass( 'translated' );\n\n\t\t\tthis.dirty = false;\n\n\t\t\tif ( this.message.properties ) {\n\t\t\t\t$( '.tux-action-bar .tux-statsbar' ).trigger(\n\t\t\t\t\t'change',\n\t\t\t\t\t[ 'translated', this.message.properties.status ]\n\t\t\t\t);\n\n\t\t\t\tthis.message.properties.status = 'translated';\n\t\t\t\t// TODO: Update any other statsbar for the same group in the page.\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Save the translation\n\t\t *\n\t\t * @private\n\t\t */\n\t\tsave: function () {\n\t\t\tvar translateEditor = this;\n\n\t\t\tlogger.logClickEvent(\n\t\t\t\t'edit',\n\t\t\t\t'publish_translation_button',\n\t\t\t\t{\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\ttarget_type: 'message',\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tsource_title: translateEditor.message.title\n\t\t\t\t}\n\t\t\t);\n\n\t\t\tmw.hook( 'mw.translate.editor.beforeSubmit' ).fire( translateEditor.$editor );\n\t\t\tvar translation = translateEditor.$editor.find( '.tux-textarea-translation' ).val();\n\t\t\tvar editSummary = translateEditor.$editor.find( '.tux-input-editsummary' ).val() || '';\n\n\t\t\ttranslateEditor.saving = true;\n\n\t\t\t// beforeSave callback\n\t\t\tif ( translateEditor.options.beforeSave ) {\n\t\t\t\ttranslateEditor.options.beforeSave( translation );\n\t\t\t}\n\n\t\t\t// For responsiveness and efficiency,\n\t\t\t// immediately move to the next message.\n\t\t\ttranslateEditor.next();\n\n\t\t\t// Now the message definitely has a history,\n\t\t\t// so make sure the history menu item is shown\n\t\t\ttranslateEditor.$editor.find( '.message-tools-history' )\n\t\t\t\t.removeClass( 'hide' );\n\n\t\t\t// Show the delete menu item if the user can delete\n\t\t\tif ( this.canDelete ) {\n\t\t\t\ttranslateEditor.$editor.find( '.message-tools-delete' )\n\t\t\t\t\t.removeClass( 'hide' );\n\t\t\t}\n\n\t\t\t// Hide translation related to saving failure before saving again.\n\t\t\ttranslateEditor.removeNotices( noticeTypes.translateFail );\n\t\t\tthis.storage.save(\n\t\t\t\ttranslateEditor.message.title,\n\t\t\t\ttranslation,\n\t\t\t\teditSummary\n\t\t\t).done( function ( response, xhr ) {\n\t\t\t\tvar editResp = response.edit;\n\t\t\t\tif ( editResp.result === 'Success' ) {\n\t\t\t\t\ttranslateEditor.message.translation = translation;\n\n\t\t\t\t\tif ( logger.isEventLoggingEnabled() ) {\n\t\t\t\t\t\tvar proposedMTText = translateEditor.$editor.find( '.tux-suggestion-aid-used > .suggestiontext' ).text();\n\t\t\t\t\t\tvar mtModificationPercentage = 1;\n\n\t\t\t\t\t\tif ( proposedMTText ) {\n\t\t\t\t\t\t\tvar contentDifferencePercentage = mtHelpers.calculateUnmodifiedContent(\n\t\t\t\t\t\t\t\tproposedMTText,\n\t\t\t\t\t\t\t\ttranslation,\n\t\t\t\t\t\t\t\ttranslateEditor.message.targetLanguage\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tmtModificationPercentage = 1 - contentDifferencePercentage;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tlogger.logEvent(\n\t\t\t\t\t\t\t'edit',\n\t\t\t\t\t\t\t'publish_success',\n\t\t\t\t\t\t\teditResp.oldrevid === 0 ? 'translation_text' : 'translation_modified',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\tmodification_rate: mtModificationPercentage,\n\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\tsource_title: translateEditor.message.title\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\ttranslateEditor.onSaveSuccess();\n\t\t\t\t} else {\n\t\t\t\t\ttranslateEditor.onSaveFail( [ mw.msg( 'tux-save-unknown-error' ) ] );\n\t\t\t\t\tmw.log( response, xhr );\n\t\t\t\t}\n\t\t\t} ).fail( function ( errorCode, response ) {\n\t\t\t\tif ( errorCode === 'http' || errorCode === 'ok-but-empty' ) {\n\t\t\t\t\tvar api = new mw.Api();\n\t\t\t\t\ttranslateEditor.displayNotices(\n\t\t\t\t\t\tapi.getErrorMessage( errorCode ),\n\t\t\t\t\t\tnoticeTypes.error\n\t\t\t\t\t);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar errors = [];\n\t\t\t\tfor ( var i = 0; i < response.errors.length; i++ ) {\n\t\t\t\t\tvar error = response.errors[ i ];\n\t\t\t\t\tif ( error.code === 'assertuserfailed' ) {\n\t\t\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\t\t\talert( mw.msg( 'tux-session-expired' ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else if ( error.code === 'translate-validation-failed' ) {\n\t\t\t\t\t\t// Cancel the translation check API call to avoid extra\n\t\t\t\t\t\t// notices from appearing.\n\t\t\t\t\t\tif ( translateEditor.validating ) {\n\t\t\t\t\t\t\ttranslateEditor.validating.abort();\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// Cancel the translation check API call that might be made\n\t\t\t\t\t\t\t// in the future.\n\t\t\t\t\t\t\ttranslateEditor.delayValidation( false );\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\ttranslateEditor.removeNotices( [ noticeTypes.error, noticeTypes.warning ] );\n\n\t\t\t\t\t\tif ( error.data && error.data.validation ) {\n\t\t\t\t\t\t\ttranslateEditor.displayNotices(\n\t\t\t\t\t\t\t\terror.data.validation.warnings,\n\t\t\t\t\t\t\t\tnoticeTypes.warning\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\ttranslateEditor.displayNotices(\n\t\t\t\t\t\t\t\terror.data.validation.errors,\n\t\t\t\t\t\t\t\tnoticeTypes.error\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\terrors.push( error.html );\n\t\t\t\t}\n\n\t\t\t\tlogger.logEvent(\n\t\t\t\t\t'edit',\n\t\t\t\t\t'publish_error',\n\t\t\t\t\t'translation_text',\n\t\t\t\t\t{\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tsource_title: translateEditor.message.title\n\t\t\t\t\t}\n\t\t\t\t);\n\n\t\t\t\t// This is placed at the bottom to ensure that the save error appears at the\n\t\t\t\t// top of the notices\n\t\t\t\ttranslateEditor.onSaveFail(\n\t\t\t\t\terrors.length ? errors : [ mw.msg( 'tux-save-unknown-error' ) ]\n\t\t\t\t);\n\n\t\t\t\t// Display all the notices whenever an error occurs.\n\t\t\t\ttranslateEditor.showMoreNotices();\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Success handler for the translation saving.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tonSaveSuccess: function () {\n\t\t\tthis.markTranslated();\n\t\t\tthis.$editTrigger.find( '.tux-list-translation' )\n\t\t\t\t.text( this.message.translation );\n\t\t\tthis.saving = false;\n\n\t\t\t// remove notices if any.\n\t\t\tthis.removeNotices( noticeTypes.getAllClasses() );\n\n\t\t\tthis.$editor.find( '.tux-notice' ).empty();\n\t\t\tthis.$editor.find( '.tux-more-notices' )\n\t\t\t\t.addClass( 'hide' )\n\t\t\t\t.empty();\n\n\t\t\t$( '.tux-editor-clear-translated' )\n\t\t\t\t.removeClass( 'hide' )\n\t\t\t\t.prop( 'disabled', false );\n\n\t\t\tthis.$editor.find( '.tux-input-editsummary' )\n\t\t\t\t.val( '' )\n\t\t\t\t.prop( 'disabled', true );\n\n\t\t\t// Save callback\n\t\t\tif ( this.options.onSave ) {\n\t\t\t\tthis.options.onSave( this.message.translation );\n\t\t\t}\n\n\t\t\tmw.translate.dirty = false;\n\t\t\tmw.hook( 'mw.translate.editor.afterSubmit' ).fire( this.$editor );\n\n\t\t\tif ( mw.track ) {\n\t\t\t\tmw.track( 'ext.translate.event.translation', this.message );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Marks that there was a problem saving a translation.\n\t\t *\n\t\t * @private\n\t\t * @param {string[]} errors Array of HTML notices to display.\n\t\t */\n\t\tonSaveFail: function ( errors ) {\n\t\t\tvar $error;\n\t\t\tif ( errors.length === 1 ) {\n\t\t\t\t$error = $( $.parseHTML( errors[ 0 ] ) );\n\t\t\t} else {\n\t\t\t\tvar $errorList = $( '<ul>' );\n\t\t\t\tfor ( var i = 0; i < errors.length; i++ ) {\n\t\t\t\t\t$errorList.append( $( '<li>' ).html( errors[ i ] ) );\n\t\t\t\t}\n\t\t\t\t$error = $errorList;\n\t\t\t}\n\n\t\t\tthis.addNotice(\n\t\t\t\tmw.message( 'tux-editor-save-failed', $error, errors.length ).parse(),\n\t\t\t\tnoticeTypes.translateFail\n\t\t\t);\n\t\t\tthis.saving = false;\n\t\t\tthis.markUnsavedFailure();\n\n\t\t\t// Enable the save button again\n\t\t\tthis.$editor.find( '.tux-editor-save-button' ).prop( 'disabled', false );\n\t\t},\n\n\t\t/**\n\t\t * Skip the current message. Record it to mark as hard.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tskip: function () {\n\t\t\t// @TODO devise good algorithm for identifying hard to translate messages\n\t\t},\n\n\t\t/**\n\t\t * Jump to the next translation editor row.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tnext: function () {\n\t\t\tvar $next = this.$editTrigger.next( '.tux-message' );\n\n\t\t\t// Determine the next message to show. The immediate next one maybe hidden\n\t\t\t// for example in case of filtering\n\t\t\twhile ( $next.length && $next.hasClass( 'hide' ) ) {\n\t\t\t\t$next = $next.next( '.tux-message' );\n\t\t\t}\n\n\t\t\t// If this is the last message, just hide it\n\t\t\tif ( !$next.length ) {\n\t\t\t\tthis.hide();\n\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$next.data( 'translateeditor' ).show();\n\n\t\t\t// Scroll the page a little bit up, slowly.\n\t\t\tif ( $( document ).height() -\n\t\t\t\t( document.documentElement.clientHeight + window.scrollY ) > 0\n\t\t\t) {\n\t\t\t\tvar scrollTop = window.scrollY + $next.get( 0 ).getBoundingClientRect().top - 85;\n\t\t\t\twindow.scrollTo( {\n\t\t\t\t\ttop: scrollTop,\n\t\t\t\t\tleft: 0,\n\t\t\t\t\tbehavior: 'smooth'\n\t\t\t\t} );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Creates a menu element for the message tools.\n\t\t *\n\t\t * @private\n\t\t * @param {string} className Used as the element's CSS class\n\t\t * @param {Object} query Used as the query in the mw.Uri object\n\t\t * @param {string} message The message of the label of the menu item\n\t\t * @return {jQuery} The new menu item element\n\t\t */\n\t\tcreateMessageToolsItem: function ( className, query, message ) {\n\t\t\tvar uri = new mw.Uri();\n\n\t\t\turi.path = mw.config.get( 'wgScript' );\n\t\t\turi.query = query;\n\n\t\t\treturn $( '<li>' )\n\t\t\t\t.addClass( className )\n\t\t\t\t.append( $( '<a>' )\n\t\t\t\t\t.attr( {\n\t\t\t\t\t\thref: uri.toString(),\n\t\t\t\t\t\ttarget: '_blank'\n\t\t\t\t\t} )\n\t\t\t\t\t.text( mw.msg( message ) )\n\t\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * Creates an element with a dropdown menu including\n\t\t * tools for the translators.\n\t\t *\n\t\t * @private\n\t\t * @return {jQuery} The new message tools menu element\n\t\t */\n\t\tcreateMessageTools: function () {\n\t\t\tvar $editItem = this.createMessageToolsItem(\n\t\t\t\t'message-tools-edit',\n\t\t\t\t{\n\t\t\t\t\ttitle: this.message.title,\n\t\t\t\t\taction: 'edit'\n\t\t\t\t},\n\t\t\t\t'tux-editor-message-tools-show-editor'\n\t\t\t);\n\n\t\t\tif ( !mw.translate.canTranslate() ) {\n\t\t\t\t$editItem.addClass( 'hide' );\n\t\t\t}\n\n\t\t\tvar $historyItem = this.createMessageToolsItem(\n\t\t\t\t'message-tools-history',\n\t\t\t\t{\n\t\t\t\t\ttitle: this.message.title,\n\t\t\t\t\taction: 'history'\n\t\t\t\t},\n\t\t\t\t'tux-editor-message-tools-history'\n\t\t\t);\n\n\t\t\tvar $deleteItem = this.createMessageToolsItem(\n\t\t\t\t'message-tools-delete',\n\t\t\t\t{\n\t\t\t\t\ttitle: this.message.title,\n\t\t\t\t\taction: 'delete'\n\t\t\t\t},\n\t\t\t\t'tux-editor-message-tools-delete'\n\t\t\t);\n\n\t\t\t// Hide these links if the translation doesn't actually exist.\n\t\t\t// They will be shown when a translation will be created.\n\t\t\tif ( this.message.translation === null ) {\n\t\t\t\t$historyItem.addClass( 'hide' );\n\t\t\t\t$deleteItem.addClass( 'hide' );\n\t\t\t} else if ( !this.canDelete ) {\n\t\t\t\t$deleteItem.addClass( 'hide' );\n\t\t\t}\n\n\t\t\t// A link to Special:Translations,\n\t\t\t// with translations of this message to other languages\n\t\t\tvar $translationsItem = this.createMessageToolsItem(\n\t\t\t\t'message-tools-translations',\n\t\t\t\t{\n\t\t\t\t\ttitle: 'Special:Translations',\n\t\t\t\t\tmessage: this.message.title\n\t\t\t\t},\n\t\t\t\t'tux-editor-message-tools-translations'\n\t\t\t);\n\n\t\t\tvar $linkToThisItem = this.createMessageToolsItem(\n\t\t\t\t'message-tools-linktothis',\n\t\t\t\t{\n\t\t\t\t\ttitle: 'Special:Translate',\n\t\t\t\t\tshowMessage: this.message.key,\n\t\t\t\t\tgroup: this.message.primaryGroup,\n\t\t\t\t\tlanguage: this.message.targetLanguage\n\t\t\t\t},\n\t\t\t\t'tux-editor-message-tools-linktothis'\n\t\t\t);\n\n\t\t\treturn $( '<ul>' )\n\t\t\t\t.addClass( 'tux-dropdown-menu tux-message-tools-menu hide' )\n\t\t\t\t.append( $editItem, $historyItem, $deleteItem, $translationsItem, $linkToThisItem );\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t * @return {jQuery}\n\t\t */\n\t\tprepareEditorColumn: function () {\n\t\t\tvar translateEditor = this,\n\t\t\t\t$discardChangesButton = $( [] ),\n\t\t\t\t$saveButton = $( [] ),\n\t\t\t\t$messageTools = translateEditor.createMessageTools(),\n\t\t\t\tcanTranslate = mw.translate.canTranslate();\n\n\t\t\tvar $editorColumn = $( '<div>' )\n\t\t\t\t.addClass( 'seven columns editcolumn' );\n\n\t\t\tvar $messageKeyLabel = $( '<div>' )\n\t\t\t\t.addClass( 'ten columns messagekey' )\n\t\t\t\t.text( this.message.title )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' ).addClass( 'caret' ),\n\t\t\t\t\t$messageTools\n\t\t\t\t)\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t$messageTools.toggleClass( 'hide' );\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t} );\n\n\t\t\tvar $closeIcon = $( '<span>' )\n\t\t\t\t.addClass( 'one column close' )\n\t\t\t\t.attr( 'title', mw.msg( 'tux-editor-close-tooltip' ) )\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\ttranslateEditor.hide();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t\t'close',\n\t\t\t\t\t\t'close_button'\n\t\t\t\t\t);\n\t\t\t\t} );\n\n\t\t\tvar $infoToggleIcon = $( '<span>' )\n\t\t\t\t// Initially the editor column is contracted,\n\t\t\t\t// so show the expand button first\n\t\t\t\t.addClass( 'one column editor-info-toggle editor-expand' )\n\t\t\t\t.attr( 'title', mw.msg( 'tux-editor-expand-tooltip' ) )\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\ttranslateEditor.infoToggle( $( this ) );\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t} );\n\n\t\t\tvar $layoutActions = $( '<div>' )\n\t\t\t\t.addClass( 'two columns layout-actions' )\n\t\t\t\t.append( $closeIcon, $infoToggleIcon );\n\n\t\t\t$editorColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row tux-editor-titletools' )\n\t\t\t\t.append( $messageKeyLabel, $layoutActions )\n\t\t\t);\n\n\t\t\tvar $messageList = $( '.tux-messagelist' );\n\t\t\tvar originalTranslation = this.message.translation;\n\t\t\tvar sourceString = this.message.definition;\n\t\t\t// The following classes are used here:\n\t\t\t// * mw-editfont-serif\n\t\t\t// * mw-editfont-sans-serif\n\t\t\t// * mw-editfont-monospace\n\t\t\tvar $sourceString = $( '<span>' )\n\t\t\t\t.addClass( 'twelve columns sourcemessage ' + this.editFontClass )\n\t\t\t\t.attr( {\n\t\t\t\t\tlang: $messageList.data( 'sourcelangcode' ),\n\t\t\t\t\tdir: $messageList.data( 'sourcelangdir' )\n\t\t\t\t} )\n\t\t\t\t.text( sourceString );\n\n\t\t\t// Adjust the font size for the message string based on the length\n\t\t\tif ( sourceString.length > 100 && sourceString.length < 200 ) {\n\t\t\t\t$sourceString.addClass( 'long' );\n\t\t\t}\n\n\t\t\tif ( sourceString.length > 200 ) {\n\t\t\t\t$sourceString.addClass( 'longer' );\n\t\t\t}\n\n\t\t\tvar $copyOriginalButton = null;\n\t\t\tif ( window.navigator.clipboard ) {\n\t\t\t\t$copyOriginalButton = $( '<button>' )\n\t\t\t\t\t.addClass( 'tux-editor-copy-original-button' )\n\t\t\t\t\t.prop( 'title', mw.msg( 'tux-editor-copy-original-button-label' ) )\n\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\twindow.navigator.clipboard.writeText( sourceString );\n\t\t\t\t\t\tvar $self = $( this );\n\t\t\t\t\t\t$self\n\t\t\t\t\t\t\t.addClass( 'copied' )\n\t\t\t\t\t\t\t.prop( {\n\t\t\t\t\t\t\t\tdisabled: true,\n\t\t\t\t\t\t\t\ttitle: mw.msg( 'tux-editor-copied-original-button-label' )\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\tlogger.logClickEvent( 'copy', 'copy_text_button' );\n\t\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\t\t$self\n\t\t\t\t\t\t\t\t.prop( {\n\t\t\t\t\t\t\t\t\tdisabled: false,\n\t\t\t\t\t\t\t\t\ttitle: mw.msg( 'tux-editor-copy-original-button-label' )\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t.removeClass( 'copied' );\n\t\t\t\t\t\t}, 2000 );\n\t\t\t\t\t} );\n\t\t\t}\n\n\t\t\t$editorColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row tux-editor-sourcemessage-container' )\n\t\t\t\t.append( $sourceString, $copyOriginalButton )\n\t\t\t);\n\n\t\t\tvar $notices = $( '<div>' )\n\t\t\t\t.addClass( 'tux-notice hide' );\n\n\t\t\tvar $moreNoticesButton = $( '<button>' )\n\t\t\t\t.addClass( 'tux-more-notices hide cdx-button cdx-button--weight-quiet' )\n\t\t\t\t.on( 'click', function () {\n\t\t\t\t\tvar $this = $( this ),\n\t\t\t\t\t\t$moreNotices = $notices.children(),\n\t\t\t\t\t\tlastNoticeIndex = $moreNotices.length - 1;\n\n\t\t\t\t\t// If the notice list is not open, only one notice is shown\n\t\t\t\t\tif ( $this.hasClass( 'open' ) ) {\n\t\t\t\t\t\t$moreNotices.each( function ( index, element ) {\n\t\t\t\t\t\t\t// The first element must always be shown\n\t\t\t\t\t\t\tif ( index ) {\n\t\t\t\t\t\t\t\t$( element ).addClass( 'hide' );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t$this\n\t\t\t\t\t\t\t.removeClass( 'open' )\n\t\t\t\t\t\t\t.text( mw.msg( 'tux-notices-more', lastNoticeIndex ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$moreNotices.each( function ( index, element ) {\n\t\t\t\t\t\t\t// The first element must always be shown\n\t\t\t\t\t\t\tif ( index ) {\n\t\t\t\t\t\t\t\t$( element ).removeClass( 'hide' );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t$this\n\t\t\t\t\t\t\t.addClass( 'open' )\n\t\t\t\t\t\t\t.text( mw.msg( 'tux-notices-hide' ) );\n\t\t\t\t\t}\n\n\t\t\t\t\ttranslateEditor.toggleMoreButtonClass();\n\t\t\t\t} );\n\n\t\t\tvar $textarea = this.getTranslationEditor( this.message.targetLanguage );\n\n\t\t\t// Shortcuts for various insertable things\n\t\t\t$textarea.on( 'keyup keydown', function ( e ) {\n\t\t\t\tvar index, $info, direction;\n\n\t\t\t\tif ( e.type === 'keydown' && e.altKey === true ) {\n\t\t\t\t\t// Up and down arrows\n\t\t\t\t\tif ( e.keyCode === 38 || e.keyCode === 40 ) {\n\t\t\t\t\t\tdirection = e.keyCode === 40 ? 1 : -1;\n\t\t\t\t\t\t$info = translateEditor.$editor.find( '.infocolumn' );\n\t\t\t\t\t\t$info.scrollTop( $info.scrollTop() + 100 * direction );\n\t\t\t\t\t\ttranslateEditor.showShortcuts();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Move zero to last\n\t\t\t\tindex = e.keyCode - 49;\n\t\t\t\tif ( index === -1 ) {\n\t\t\t\t\tindex = 9;\n\t\t\t\t}\n\n\t\t\t\t// 0..9 ~ 48..57\n\t\t\t\tif (\n\t\t\t\t\te.type === 'keydown' &&\n\t\t\t\t\te.altKey === true &&\n\t\t\t\t\te.ctrlKey === false &&\n\t\t\t\t\te.shiftKey === false &&\n\t\t\t\t\tindex >= 0 && index < 10\n\t\t\t\t) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\ttranslateEditor.$editor.find( '.shortcut-activated:visible' ).eq( index ).trigger( 'click' );\n\t\t\t\t\t// Update numbers and locations after trigger should be completed\n\t\t\t\t\twindow.setTimeout( function () {\n\t\t\t\t\t\ttranslateEditor.showShortcuts();\n\t\t\t\t\t}, 100 );\n\t\t\t\t}\n\n\t\t\t\tif ( e.which === 18 && e.type === 'keyup' ) {\n\t\t\t\t\ttranslateEditor.hideShortcuts();\n\t\t\t\t} else if ( e.which === 18 && e.type === 'keydown' ) {\n\t\t\t\t\ttranslateEditor.showShortcuts();\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t$textarea.on( 'input', function () {\n\t\t\t\tvar $pasteSourceButton = translateEditor.$editor.find( '.tux-editor-paste-original-button' ),\n\t\t\t\t\toriginal = translateEditor.message.translation || '',\n\t\t\t\t\tcurrent = $textarea.val() || '';\n\n\t\t\t\tif ( original !== '' ) {\n\t\t\t\t\t$discardChangesButton.removeClass( 'hide' );\n\t\t\t\t}\n\n\t\t\t\t/* Avoid Unsaved marking when translated message is not changed in content.\n\t\t\t\t * - translateEditor.dirty: internal book keeping\n\t\t\t\t * - mw.translate.dirty: \"you have unchanged edits\" notice\n\t\t\t\t */\n\t\t\t\tif ( original === current ) {\n\t\t\t\t\ttranslateEditor.markUnunsaved();\n\t\t\t\t} else {\n\t\t\t\t\ttranslateEditor.dirty = true;\n\t\t\t\t\tmw.translate.dirty = true;\n\t\t\t\t}\n\n\t\t\t\ttranslateEditor.makeSaveButtonJustSave( $saveButton );\n\n\t\t\t\t// When there is content in the editor enable the button.\n\t\t\t\t// But do not enable when some saving is not finished yet.\n\t\t\t\tvar enabled = current.trim() && !translateEditor.saving;\n\t\t\t\t$saveButton.prop( 'disabled', !enabled );\n\t\t\t\t$pasteSourceButton.toggleClass( 'hide', enabled );\n\n\t\t\t\ttranslateEditor.resizeInsertables( $textarea );\n\n\t\t\t\ttranslateEditor.delayValidation( function () {\n\t\t\t\t\ttranslateEditor.validateTranslation();\n\t\t\t\t}, 1000 );\n\t\t\t} );\n\n\t\t\tvar $noticesBlock = $( '<div>' )\n\t\t\t\t.addClass( 'tux-notices-block' )\n\t\t\t\t.append( $moreNoticesButton, $notices );\n\n\t\t\tvar $editAreaBlock = $( '<div>' )\n\t\t\t\t.addClass( 'row tux-editor-editarea-block' )\n\t\t\t\t.append( $( '<div>' )\n\t\t\t\t\t.addClass( 'editarea twelve columns' )\n\t\t\t\t\t.append( $noticesBlock, $textarea )\n\t\t\t\t);\n\n\t\t\t$editorColumn.append( $editAreaBlock );\n\n\t\t\tvar $editingButtonBlock, $editSummaryBlock, $requestRight, $skipButton;\n\t\t\tif ( canTranslate ) {\n\t\t\t\tvar $pasteOriginalButton = $( '<button>' )\n\t\t\t\t\t.addClass( 'tux-editor-paste-original-button' )\n\t\t\t\t\t.text( mw.msg( 'tux-editor-paste-original-button-label' ) )\n\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t$textarea\n\t\t\t\t\t\t\t.trigger( 'focus' )\n\t\t\t\t\t\t\t.val( sourceString )\n\t\t\t\t\t\t\t.trigger( 'input' );\n\n\t\t\t\t\t\tlogger.logClickEvent( 'paste', 'paste_source_button' );\n\t\t\t\t\t\t$pasteOriginalButton.addClass( 'hide' );\n\t\t\t\t\t} );\n\n\t\t\t\tvar $editSummary = $( '<input>' )\n\t\t\t\t\t.addClass( 'tux-input-editsummary' )\n\t\t\t\t\t.attr( {\n\t\t\t\t\t\tmaxlength: 255,\n\t\t\t\t\t\tdisabled: true,\n\t\t\t\t\t\tplaceholder: mw.msg( 'tux-editor-editsummary-placeholder' )\n\t\t\t\t\t} )\n\t\t\t\t\t.val( '' );\n\n\t\t\t\t// Enable edit summary if there was a change to translation area\n\t\t\t\t// or disable if there is no text in translation area\n\t\t\t\t$textarea.on( 'input', function () {\n\t\t\t\t\tif ( $editSummary.prop( 'disabled' ) ) {\n\t\t\t\t\t\t$editSummary.prop( 'disabled', false );\n\t\t\t\t\t}\n\t\t\t\t\tif ( $textarea.val().trim() === '' ) {\n\t\t\t\t\t\t$editSummary.prop( 'disabled', true );\n\t\t\t\t\t}\n\t\t\t\t} ).on( 'keydown', function ( e ) {\n\t\t\t\t\tif ( !e.ctrlKey || e.keyCode !== 13 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !$saveButton.is( ':disabled' ) ) {\n\t\t\t\t\t\t$saveButton.trigger( 'click' );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\t$skipButton.trigger( 'click' );\n\t\t\t\t} );\n\n\t\t\t\t// Make the Ctrl+Enter shortcut work in the edit summary field\n\t\t\t\t$editSummary.on( 'keydown', function ( e ) {\n\t\t\t\t\tif ( !e.ctrlKey || e.keyCode !== 13 ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t$saveButton.trigger( 'click' );\n\t\t\t\t} );\n\n\t\t\t\tif ( originalTranslation !== null ) {\n\t\t\t\t\t$discardChangesButton = $( '<button>' )\n\t\t\t\t\t\t.addClass( 'tux-editor-discard-changes-button hide' ) // Initially hidden\n\t\t\t\t\t\t.text( mw.msg( 'tux-editor-discard-changes-button-label' ) )\n\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\t// Restore the translation\n\t\t\t\t\t\t\t$textarea\n\t\t\t\t\t\t\t\t.trigger( 'focus' )\n\t\t\t\t\t\t\t\t.val( originalTranslation );\n\n\t\t\t\t\t\t\t// and go back to hiding.\n\t\t\t\t\t\t\t$discardChangesButton.addClass( 'hide' );\n\n\t\t\t\t\t\t\t// There's nothing new to save...\n\t\t\t\t\t\t\t$editSummary.val( '' ).prop( 'disabled', true );\n\t\t\t\t\t\t\t$saveButton.prop( 'disabled', true );\n\t\t\t\t\t\t\t// ...unless there is other action\n\t\t\t\t\t\t\ttranslateEditor.makeSaveButtonContextSensitive( $saveButton );\n\n\t\t\t\t\t\t\ttranslateEditor.markUnunsaved();\n\t\t\t\t\t\t\ttranslateEditor.resizeInsertables( $textarea );\n\t\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\tif ( this.message.translation ) {\n\t\t\t\t\t$pasteOriginalButton.addClass( 'hide' );\n\t\t\t\t}\n\n\t\t\t\t$editingButtonBlock = $( '<div>' )\n\t\t\t\t\t.addClass( 'twelve columns tux-editor-insert-buttons' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$pasteOriginalButton,\n\t\t\t\t\t\t$discardChangesButton\n\t\t\t\t\t);\n\n\t\t\t\t$editSummaryBlock = $( '<div>' )\n\t\t\t\t\t.addClass( 'row tux-editor-editsummary-block' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'twelve columns' )\n\t\t\t\t\t\t\t.append( $editSummary )\n\t\t\t\t\t);\n\n\t\t\t\t$requestRight = $( [] );\n\n\t\t\t\t$saveButton = $( '<button>' )\n\t\t\t\t\t.prop( 'disabled', true )\n\t\t\t\t\t.addClass( 'tux-editor-save-button mw-ui-button mw-ui-progressive' )\n\t\t\t\t\t.text( mw.msg( 'tux-editor-save-button-label' ) )\n\t\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t\ttranslateEditor.save();\n\t\t\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t\t\t'open',\n\t\t\t\t\t\t\t'publish_translation',\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\tsource_title: translateEditor.message.title,\n\t\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\t\tsource_type: 'message'\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t} );\n\n\t\t\t\tthis.makeSaveButtonContextSensitive( $saveButton, this.$messageItem );\n\t\t\t} else {\n\t\t\t\t$editingButtonBlock = $( [] );\n\n\t\t\t\t$editSummaryBlock = $( [] );\n\n\t\t\t\t$requestRight = $( '<span>' )\n\t\t\t\t\t.addClass( 'tux-editor-request-right' )\n\t\t\t\t\t.text( mw.msg( 'translate-edit-nopermission' ) );\n\t\t\t\t// Make sure wgTranslatePermissionUrl setting is not 'false'\n\t\t\t\tif ( mw.config.get( 'wgTranslatePermissionUrl' ) !== false ) {\n\t\t\t\t\t$requestRight\n\t\t\t\t\t\t.append( $( '<a>' )\n\t\t\t\t\t\t\t.text( mw.msg( 'translate-edit-askpermission' ) )\n\t\t\t\t\t\t\t.addClass( 'tux-editor-ask-permission' )\n\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\thref: mw.util.getUrl(\n\t\t\t\t\t\t\t\t\tmw.config.get( 'wgTranslateUseSandbox' ) ?\n\t\t\t\t\t\t\t\t\t\t'Special:TranslationStash' :\n\t\t\t\t\t\t\t\t\t\tmw.config.get( 'wgTranslatePermissionUrl' )\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Disable the text area if user has no translation rights.\n\t\t\t\t// Use readonly to allow copy-pasting (except for placeholders)\n\t\t\t\t$textarea.prop( 'readonly', true );\n\n\t\t\t\t$saveButton = $( [] );\n\t\t\t}\n\n\t\t\t$skipButton = $( '<button>' )\n\t\t\t\t.addClass( 'tux-editor-skip-button mw-ui-button mw-ui-quiet' )\n\t\t\t\t.text( mw.msg( 'tux-editor-skip-button-label' ) )\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\ttranslateEditor.skip();\n\t\t\t\t\ttranslateEditor.next();\n\t\t\t\t\t// Remove any instances of MT suggestions that were previously clicked.\n\t\t\t\t\ttranslateEditor.$editor.find( '.tux-suggestion-aid-used' ).removeClass( 'tux-suggestion-aid-used' );\n\n\t\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t\t'open',\n\t\t\t\t\t\t'skip_to_next',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tsource_title: translateEditor.message.title,\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tsource_type: 'message'\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\n\t\t\t\t\tif ( translateEditor.options.onSkip ) {\n\t\t\t\t\t\ttranslateEditor.options.onSkip.call( translateEditor );\n\t\t\t\t\t}\n\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t} );\n\n\t\t\t// This appears instead of \"Skip\" on the last message on the page\n\t\t\tvar $cancelButton = $( '<button>' )\n\t\t\t\t.addClass( 'tux-editor-cancel-button mw-ui-button mw-ui-quiet' )\n\t\t\t\t.text( mw.msg( 'tux-editor-cancel-button-label' ) )\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\ttranslateEditor.skip();\n\t\t\t\t\ttranslateEditor.hide();\n\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t} );\n\n\t\t\tvar $controlButtonBlock = $( '<div>' )\n\t\t\t\t.addClass( 'twelve columns tux-editor-control-buttons' )\n\t\t\t\t.append( $requestRight, $saveButton, $skipButton, $cancelButton );\n\n\t\t\t$editorColumn.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'row tux-editor-actions-block' )\n\t\t\t\t\t.append( $editingButtonBlock ),\n\t\t\t\t$editSummaryBlock,\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'row tux-editor-actions-block' )\n\t\t\t\t\t.append( $controlButtonBlock )\n\t\t\t);\n\n\t\t\tif ( canTranslate ) {\n\t\t\t\tvar prefix = $.fn.updateTooltipAccessKeys.getAccessKeyPrefix();\n\t\t\t\t$editorColumn.append( $( '<div>' )\n\t\t\t\t\t.addClass( 'row shortcutinfo' )\n\t\t\t\t\t.text( mw.msg(\n\t\t\t\t\t\t'tux-editor-shortcut-info',\n\t\t\t\t\t\t'CTRL-ENTER',\n\t\t\t\t\t\t( prefix + 'd' ).toUpperCase(),\n\t\t\t\t\t\t'ALT',\n\t\t\t\t\t\t( prefix + 'b' ).toUpperCase()\n\t\t\t\t\t) )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn $editorColumn;\n\t\t},\n\n\t\t/**\n\t\t * Modifies the save button to provide suitable default action for *unchanged*\n\t\t * message. It will revert back to normal save button if the text is changed.\n\t\t *\n\t\t * @private\n\t\t * @param {jQuery} $button The save button.\n\t\t */\n\t\tmakeSaveButtonContextSensitive: function ( $button ) {\n\t\t\tvar self = this;\n\n\t\t\tif ( this.message.properties.status === 'fuzzy' ) {\n\t\t\t\t$button.prop( 'disabled', false )\n\t\t\t\t\t.text( mw.msg( 'tux-editor-confirm-button-label' ) )\n\t\t\t\t\t.off( 'click' )\n\t\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t\tself.save();\n\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t} );\n\t\t\t} else if ( this.message.proofreadable ) {\n\t\t\t\t$button.prop( 'disabled', false )\n\t\t\t\t\t.text( mw.msg( 'tux-editor-proofread-button-label' ) )\n\t\t\t\t\t.off( 'click' )\n\t\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t\t$button.prop( 'disabled', true );\n\t\t\t\t\t\tself.message.proofreadAction();\n\t\t\t\t\t\tself.next();\n\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t} );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Modifies the save button to just save the translation as usual. Whether the\n\t\t * button is enabled or not is controlled elsewhere.\n\t\t *\n\t\t * @private\n\t\t * @param {jQuery} $button The save button.\n\t\t */\n\t\tmakeSaveButtonJustSave: function ( $button ) {\n\t\t\tvar self = this;\n\n\t\t\t$button.text( mw.msg( 'tux-editor-save-button-label' ) )\n\t\t\t\t.off( 'click' )\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\tself.save();\n\t\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t\t'open',\n\t\t\t\t\t\t'publish_translation',\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tsource_title: self.message.title,\n\t\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\t\tsource_type: 'message'\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Validate the current translation using the API\n\t\t * and show the notices.\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tvalidateTranslation: function () {\n\t\t\tvar translateEditor = this,\n\t\t\t\t$textarea = translateEditor.$editor.find( '.tux-textarea-translation' );\n\n\t\t\tvar api = new mw.Api();\n\n\t\t\tthis.validating = api.post( {\n\t\t\t\taction: 'translationcheck',\n\t\t\t\ttitle: this.message.title,\n\t\t\t\ttranslation: $textarea.val(),\n\t\t\t\tuselang: mw.config.get( 'wgUserLanguage' )\n\t\t\t} ).done( function ( data ) {\n\t\t\t\tvar warnings = data.validation.warnings,\n\t\t\t\t\terrors = data.validation.errors;\n\n\t\t\t\ttranslateEditor.removeNotices( [ noticeTypes.error, noticeTypes.warning ] );\n\n\t\t\t\tif ( ( !warnings || !warnings.length ) &&\n\t\t\t\t\t( !errors || !errors.length ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// Remove useless fuzzy notice if we have more details\n\t\t\t\ttranslateEditor.removeNotices( noticeTypes.fuzzy );\n\n\t\t\t\t// Disable confirm translation button, since fuzzy translations\n\t\t\t\t// cannot be confirmed. The check for dirty state can be removed\n\t\t\t\t// to prevent translations with notices.\n\t\t\t\tif ( !translateEditor.dirty ) {\n\t\t\t\t\ttranslateEditor.$editor.find( '.tux-editor-save-button' )\n\t\t\t\t\t\t.prop( 'disabled', true );\n\t\t\t\t}\n\n\t\t\t\t// Don't allow users to save if there are errors but allow admins to save\n\t\t\t\t// even if there are errors.\n\t\t\t\tif ( !mw.translate.canManage() ) {\n\t\t\t\t\tif ( errors && errors.length > 0 ) {\n\t\t\t\t\t\ttranslateEditor.$editor.find( '.tux-editor-save-button' )\n\t\t\t\t\t\t\t.prop( 'disabled', true );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\ttranslateEditor.displayNotices( warnings, noticeTypes.warning );\n\t\t\t\ttranslateEditor.displayNotices( errors, noticeTypes.error );\n\n\t\t\t} ).always( function () {\n\t\t\t\ttranslateEditor.validating = null;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Remove all notices of given types\n\t\t *\n\t\t * @internal\n\t\t * @param {(string|string[])} types\n\t\t */\n\t\tremoveNotices: function ( types ) {\n\t\t\tvar $tuxNotice = this.$editor.find( '.tux-notice' ),\n\t\t\t\tstringTypes = [],\n\t\t\t\tallNoticeTypes = noticeTypes.getAllClasses();\n\n\t\t\tif ( typeof types === 'string' ) {\n\t\t\t\tstringTypes.push( types );\n\t\t\t} else {\n\t\t\t\tstringTypes = types;\n\t\t\t}\n\n\t\t\tfor ( var index = 0; index < stringTypes.length; index++ ) {\n\t\t\t\tif ( !allNoticeTypes.includes( stringTypes[ index ] ) ) {\n\t\t\t\t\tvar errMsg = 'tux: Invalid notice type removeNotice - ' + stringTypes[ index ];\n\t\t\t\t\tmw.log.error( errMsg );\n\t\t\t\t\tthrow new Error( errMsg );\n\t\t\t\t}\n\t\t\t\t$tuxNotice.find( '.' + stringTypes[ index ] ).remove();\n\t\t\t}\n\n\t\t\tvar $currentNotices = $tuxNotice.children();\n\t\t\t// If a single notice is shown, we can hide the more notice button,\n\t\t\t// and display the hidden notice.\n\t\t\tif ( $currentNotices.length <= 1 ) {\n\t\t\t\tthis.$editor.find( '.tux-more-notices' ).addClass( 'hide' );\n\t\t\t\t$currentNotices.removeClass( 'hide' );\n\t\t\t}\n\t\t\tthis.toggleMoreButtonClass();\n\t\t},\n\n\t\t/**\n\t\t * Displays the supplied notice above the translation edit area.\n\t\t * Newer notices are added to the top while older notices are\n\t\t * added to the bottom. This also means that older notices will\n\t\t * not be shown by default unless the user clicks the \"more notices\"\n\t\t * button.\n\t\t *\n\t\t * @private\n\t\t * @param {string} notice used as html for the notices display\n\t\t * @param {string} type used to group the notices.eg: warning, diff, error\n\t\t * @return {jQuery} the new notice element\n\t\t */\n\t\taddNotice: function ( notice, type ) {\n\t\t\tvar $notices = this.$editor.find( '.tux-notice' ),\n\t\t\t\t$moreNoticesButton = this.$editor.find( '.tux-more-notices' ),\n\t\t\t\t// `noticeTypes` documented above\n\t\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\t\t$newNotice = $( '<div>' )\n\t\t\t\t\t.addClass( 'tux-notice-message ' + type )\n\t\t\t\t\t.html( notice );\n\n\t\t\tthis.$editor.find( '.tux-notice-message' ).addClass( 'hide' );\n\n\t\t\t$notices\n\t\t\t\t.removeClass( 'hide' )\n\t\t\t\t.prepend( $newNotice );\n\n\t\t\tvar noticeCount = $notices.find( '.tux-notice-message' ).length;\n\n\t\t\tif ( noticeCount > 1 ) {\n\t\t\t\t$moreNoticesButton\n\t\t\t\t\t.text( mw.msg( 'tux-notices-more', noticeCount - 1 ) )\n\t\t\t\t\t.removeClass( 'hide open' );\n\t\t\t} else {\n\t\t\t\t$moreNoticesButton.addClass( 'hide' );\n\t\t\t}\n\t\t\tthis.toggleMoreButtonClass();\n\n\t\t\treturn $newNotice;\n\t\t},\n\n\t\t/**\n\t\t * Toggles the class on the more button based on the types of notice displayed, and whether\n\t\t * the more section is expanded. This is done in order to change the background color of the\n\t\t * button.\n\t\t *\n\t\t * @private\n\t\t */\n\t\ttoggleMoreButtonClass: function () {\n\t\t\tvar $allNotices = this.$editor.find( '.tux-notice-message' ),\n\t\t\t\terrorCount = $allNotices.filter( '.tux-notice-message.' + noticeTypes.error ).length +\n\t\t\t\t\t$allNotices.filter( '.tux-notice-message.' + noticeTypes.translateFail ).length,\n\t\t\t\totherErrorsCount = $allNotices.length - errorCount,\n\t\t\t\t$moreButton = this.$editor.find( '.tux-more-notices' );\n\n\t\t\t// there are other notices, and more section is expanded.\n\t\t\tvar expanded = otherErrorsCount > 0 && $moreButton.hasClass( 'open' );\n\t\t\t$moreButton.toggleClass( 'tux-has-errors', errorCount > 0 && !expanded );\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t * @return {jQuery}\n\t\t */\n\t\tprepareInfoColumn: function () {\n\t\t\tvar $infoColumn = $( '<div>' ).addClass( 'infocolumn' ),\n\t\t\t\ttranslateEditor = this;\n\n\t\t\t$infoColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row loading' )\n\t\t\t\t.text( mw.msg( 'tux-editor-loading' ) )\n\t\t\t);\n\n\t\t\tif ( mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\t\tvar $messageDescSaveButton = $( '<button>' )\n\t\t\t\t\t.addClass( 'tux-editor-savedoc-button mw-ui-button mw-ui-progressive' )\n\t\t\t\t\t.prop( 'disabled', true )\n\t\t\t\t\t.text( mw.msg( 'tux-editor-doc-editor-save' ) )\n\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\ttranslateEditor.saveDocumentation()\n\t\t\t\t\t\t\t.done( function () {\n\t\t\t\t\t\t\t\t// eslint-disable-next-line no-use-before-define\n\t\t\t\t\t\t\t\tvar $descEditLink = $messageDescViewer.find( '.message-desc-edit' );\n\t\t\t\t\t\t\t\t$descEditLink.text( mw.msg( 'tux-editor-edit-desc' ) );\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t} );\n\n\t\t\t\tvar $messageDescCancelButton = $( '<button>' )\n\t\t\t\t\t.addClass( 'tux-editor-skipdoc-button mw-ui-button mw-ui-quiet' )\n\t\t\t\t\t.text( mw.msg( 'tux-editor-doc-editor-cancel' ) )\n\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\ttranslateEditor.hideDocumentationEditor();\n\t\t\t\t\t} );\n\n\t\t\t\tvar $messageDescTextarea = $( '<textarea>' )\n\t\t\t\t\t.addClass( 'tux-textarea-documentation' )\n\t\t\t\t\t.on( 'input', function () {\n\t\t\t\t\t\t$messageDescSaveButton.prop( 'disabled', false );\n\t\t\t\t\t} )\n\t\t\t\t\t.prop( 'placeholder', mw.msg( 'tux-editor-doc-editor-placeholder' ) );\n\n\t\t\t\tvar $messageDescEditor = $( '<div>' )\n\t\t\t\t\t.addClass( 'row message-desc-editor hide' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$messageDescTextarea,\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'row' )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t$messageDescSaveButton,\n\t\t\t\t\t\t\t\t$messageDescCancelButton\n\t\t\t\t\t\t\t)\n\t\t\t\t\t);\n\n\t\t\t\tvar $messageDescViewer = $( '<div>' )\n\t\t\t\t\t.addClass( 'message-desc-viewer hide' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'row message-desc mw-parser-output' ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'row message-desc-control' )\n\t\t\t\t\t\t\t.append( $( '<a>' )\n\t\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\t\thref: mw.translate.getDocumentationEditURL(\n\t\t\t\t\t\t\t\t\t\tthis.message.title.replace( /\\/[a-z-]+$/, '' )\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\t\ttarget: '_blank'\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t.addClass( 'message-desc-edit' )\n\t\t\t\t\t\t\t\t.on( 'click', this.showDocumentationEditor.bind( this ) )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t);\n\n\t\t\t\tif ( !mw.translate.canTranslate() ) {\n\t\t\t\t\t$messageDescViewer.find( '.message-desc-control' ).addClass( 'hide' );\n\t\t\t\t}\n\n\t\t\t\t$infoColumn.append(\n\t\t\t\t\t$messageDescEditor,\n\t\t\t\t\t$messageDescViewer\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t$infoColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row uneditable-documentation hide mw-parser-output' )\n\t\t\t);\n\n\t\t\t$infoColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row edit-summaries-title hide' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' ).text( mw.msg( 'tux-editor-latest-updates-title' ) )\n\t\t\t\t)\n\t\t\t\t.append( $( '<a>' )\n\t\t\t\t\t.attr(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\thref: mw.util.getUrl( this.message.title, { action: 'history' } ),\n\t\t\t\t\t\t\ttarget: '_blank'\n\t\t\t\t\t\t}\n\t\t\t\t\t)\n\t\t\t\t\t.text( mw.msg( 'tux-editor-all-changes' ) )\n\t\t\t\t\t.addClass( 'edit-summaries-all-changes' ) ) );\n\n\t\t\t$infoColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row tm-suggestions-title hide' )\n\t\t\t\t.text( mw.msg( 'tux-editor-suggestions-title' ) )\n\t\t\t);\n\n\t\t\t$infoColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row in-other-languages-title hide' )\n\t\t\t\t.text( mw.msg( 'tux-editor-in-other-languages' ) )\n\t\t\t);\n\n\t\t\t// The actual href is set when translationhelpers are loaded\n\t\t\t$infoColumn.append( $( '<div>' )\n\t\t\t\t.addClass( 'row help hide' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.text( mw.msg( 'tux-editor-need-more-help' ) ),\n\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\thref: '#',\n\t\t\t\t\t\t\ttarget: '_blank'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.text( mw.msg( 'tux-editor-ask-help' ) )\n\t\t\t\t)\n\t\t\t);\n\n\t\t\treturn $( '<div>' )\n\t\t\t\t.addClass( 'five columns infocolumn-block' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' ).addClass( 'tux-message-editor__caret' ),\n\t\t\t\t\t$infoColumn\n\t\t\t\t);\n\t\t},\n\n\t\t/**\n\t\t * @internal\n\t\t * @return {boolean}\n\t\t */\n\t\tshow: function () {\n\t\t\tif ( !this.$editor ) {\n\t\t\t\tthis.init();\n\t\t\t}\n\n\t\t\tvar $textarea = this.$editor.find( '.editcolumn textarea' );\n\t\t\t// Hide all other open editors in the page\n\t\t\t$( '.tux-message.open' ).each( function () {\n\t\t\t\t$( this ).data( 'translateeditor' ).hide();\n\t\t\t} );\n\n\t\t\tthis.$editor.find( '.tux-editor-save-button' ).attr( 'accesskey', 's' );\n\t\t\tthis.$editor.find( '.tux-editor-skip-button' ).attr( 'accesskey', 'd' );\n\t\t\tthis.$editor.find( '.tux-input-editsummary' ).attr( 'accesskey', 'b' );\n\t\t\t// @todo access key for the cancel button\n\n\t\t\tthis.$messageItem.addClass( 'hide' );\n\t\t\tthis.$editor.removeClass( 'hide' );\n\t\t\t$textarea.trigger( 'focus' );\n\n\t\t\tautosize( $textarea );\n\t\t\tthis.resizeInsertables( $textarea );\n\n\t\t\tthis.shown = true;\n\t\t\tthis.$editTrigger.addClass( 'open' );\n\n\t\t\t// don't waste time, get ready with next message\n\t\t\tvar $next = this.$editTrigger.next( '.tux-message' );\n\n\t\t\tif ( $next.length ) {\n\t\t\t\t$next.data( 'translateeditor' ).init();\n\t\t\t}\n\n\t\t\tmw.hook( 'mw.translate.editor.afterEditorShown' ).fire( this.$editor );\n\n\t\t\treturn false;\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t * @return {boolean}\n\t\t */\n\t\thide: function () {\n\t\t\t// If the user has made changes, make sure they are either\n\t\t\t// in process of being saved or highlighted as unsaved.\n\t\t\tif ( this.dirty ) {\n\t\t\t\tif ( this.saving ) {\n\t\t\t\t\tthis.markSaving();\n\t\t\t\t} else {\n\t\t\t\t\tthis.markUnsaved();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( this.$editor ) {\n\t\t\t\tthis.$editor.addClass( 'hide' );\n\n\t\t\t\t// Remove access keys to avoid duplicates in DOM (T306141)\n\t\t\t\tthis.$editor.find( '.tux-editor-save-button' ).removeAttr( 'accesskey' );\n\t\t\t\tthis.$editor.find( '.tux-editor-skip-button' ).removeAttr( 'accesskey' );\n\t\t\t\tthis.$editor.find( '.tux-input-editsummary' ).removeAttr( 'accesskey' );\n\t\t\t}\n\n\t\t\tthis.hideShortcuts();\n\t\t\tthis.$editTrigger.removeClass( 'open' );\n\t\t\tthis.$messageItem.removeClass( 'hide' );\n\t\t\tthis.shown = false;\n\n\t\t\treturn false;\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t * @param {jQuery} toggleIcon\n\t\t */\n\t\tinfoToggle: function ( toggleIcon ) {\n\t\t\tthis.expanded = !this.expanded;\n\n\t\t\t// Change the icon image\n\t\t\ttoggleIcon\n\t\t\t\t.toggleClass( 'editor-expand', !this.expanded )\n\t\t\t\t.toggleClass( 'editor-contract', this.expanded )\n\t\t\t\t.attr( 'title', mw.msg( this.expanded ? 'tux-editor-collapse-tooltip' : 'tux-editor-expand-tooltip' ) );\n\n\t\t\tthis.$editor.toggleClass( 'tux-message-editor--expanded', this.expanded );\n\t\t},\n\n\t\t/**\n\t\t * Adds the diff between old and current definitions to the view.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} definitiondiff A definitiondiff object as returned by API.\n\t\t */\n\t\taddDefinitionDiff: function ( definitiondiff ) {\n\t\t\tif ( !definitiondiff || definitiondiff.error ) {\n\t\t\t\tmw.log( 'Error loading translation diff ' + definitiondiff && definitiondiff.error );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Load the diff styles\n\t\t\tmw.loader.load( 'mediawiki.diff.styles' );\n\n\t\t\tvar $trigger = $( '<span>' )\n\t\t\t\t.addClass( 'show-diff-link' )\n\t\t\t\t.text( mw.msg( 'tux-editor-outdated-notice-diff-link' ) )\n\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t$( this ).parent().html( definitiondiff.html );\n\t\t\t\t} );\n\n\t\t\tthis.removeNotices( noticeTypes.fuzzy );\n\t\t\tthis.addNotice(\n\t\t\t\tmw.message( 'tux-editor-outdated-notice' ).escaped(),\n\t\t\t\tnoticeTypes.diff\n\t\t\t).append( $trigger );\n\t\t},\n\n\t\t/**\n\t\t * Attach event listeners\n\t\t *\n\t\t * @internal\n\t\t */\n\t\tlisten: function () {\n\t\t\tvar translateEditor = this;\n\n\t\t\tthis.$editTrigger.find( '.tux-message-item' ).on( 'click', function () {\n\t\t\t\ttranslateEditor.show();\n\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t'open',\n\t\t\t\t\t'edit_translation_button',\n\t\t\t\t\t{\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tsource_title: translateEditor.message.title,\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tsource_type: 'message'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Makes the textarea large enough for insertables and positions the insertables.\n\t\t *\n\t\t * @internal\n\t\t * @param {jQuery} $textarea Text area.\n\t\t */\n\t\tresizeInsertables: function ( $textarea ) {\n\t\t\tvar $buttonArea = this.$editor.find( '.tux-editor-insert-buttons' );\n\t\t\tvar buttonAreaHeight = $buttonArea.height();\n\t\t\t$textarea.css( 'padding-bottom', buttonAreaHeight + 5 );\n\t\t\t$buttonArea.css( 'top', -buttonAreaHeight );\n\t\t\tautosize.update( $textarea );\n\t\t},\n\n\t\t/**\n\t\t * Utility method to display a list of notices on the UI\n\t\t *\n\t\t * @private\n\t\t * @param {string[]} notices\n\t\t * @param {string} noticeType\n\t\t */\n\t\tdisplayNotices: function ( notices, noticeType ) {\n\t\t\tfor ( var index = 0; index < notices.length; ++index ) {\n\t\t\t\tthis.addNotice( notices[ index ], noticeType );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Ensures that all the notices are displayed\n\t\t *\n\t\t * @private\n\t\t */\n\t\tshowMoreNotices: function () {\n\t\t\tvar $moreNoticesButton = this.$editor.find( '.tux-more-notices' );\n\t\t\tif ( $moreNoticesButton.hasClass( 'open' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t$moreNoticesButton.trigger( 'click' );\n\t\t},\n\n\t\t/**\n\t\t * Generates the translation editor element based on target language\n\t\t *\n\t\t * @private\n\t\t * @param {string} targetLangCode\n\t\t * @return {jQuery} Returns translation editor element\n\t\t */\n\t\tgetTranslationEditor: function ( targetLangCode ) {\n\t\t\tvar targetLangAttrib, placeholder;\n\t\t\tif ( targetLangCode === mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\t\ttargetLangAttrib = mw.config.get( 'wgContentLanguage' );\n\t\t\t\tplaceholder = mw.msg( 'tux-editor-placeholder-documentation' );\n\t\t\t} else {\n\t\t\t\tvar userLangCode = mw.config.get( 'wgUserLanguage' );\n\t\t\t\tvar targetLangName = mw.language.getData( userLangCode, 'languageNames' )[ targetLangCode ] || $.uls.data.getAutonym( targetLangCode );\n\t\t\t\ttargetLangAttrib = targetLangCode;\n\t\t\t\tplaceholder = mw.msg( 'tux-editor-placeholder-language', targetLangName );\n\t\t\t}\n\n\t\t\tvar targetLangDir = $.uls.data.getDir( targetLangAttrib );\n\n\t\t\t// The following classes are used here:\n\t\t\t// * mw-editfont-serif\n\t\t\t// * mw-editfont-sans-serif\n\t\t\t// * mw-editfont-monospace\n\t\t\treturn $( '<textarea>' )\n\t\t\t\t.addClass( 'tux-textarea-translation ' + this.editFontClass )\n\t\t\t\t.attr( {\n\t\t\t\t\tlang: targetLangAttrib,\n\t\t\t\t\tdir: targetLangDir\n\t\t\t\t} )\n\t\t\t\t.val( this.message.translation || '' )\n\t\t\t\t.prop( 'placeholder', placeholder )\n\t\t\t\t.on( 'paste', function () {\n\t\t\t\t\tlogger.logClickEvent( 'paste', 'direct_paste' );\n\t\t\t\t} );\n\t\t}\n\t};\n\n\t/**\n\t * translateeditor PLUGIN DEFINITION\n\t *\n\t * @internal\n\t * @param {Object} options\n\t * @return {jQuery}\n\t */\n\t$.fn.translateeditor = function ( options ) {\n\t\treturn this.each( function () {\n\t\t\tvar $this = $( this ),\n\t\t\t\tdata = $this.data( 'translateeditor' );\n\n\t\t\tif ( !data ) {\n\t\t\t\t$this.data( 'translateeditor',\n\t\t\t\t\t( data = new TranslateEditor( this, options ) )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( typeof options === 'string' ) {\n\t\t\t\tdata[ options ].call( $this );\n\t\t\t}\n\t\t} );\n\t};\n\n\tmw.translate.editor = mw.translate.editor || {};\n\tmw.translate.editor = $.extend( TranslateEditor.prototype, mw.translate.editor );\n\n\tfunction delayer() {\n\t\treturn ( function () {\n\t\t\tvar timer = 0;\n\n\t\t\treturn function ( callback, milliseconds ) {\n\t\t\t\tclearTimeout( timer );\n\n\t\t\t\tif ( callback === false ) {\n\t\t\t\t\t// sometimes we need to just cancel the timer without\n\t\t\t\t\t// setting up another one\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\ttimer = setTimeout( callback, milliseconds );\n\t\t\t};\n\t\t}() );\n\t}\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.editor.shortcuts.js","messages":[{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":37,"column":4,"nodeType":"CallExpression","endLine":37,"endColumn":54},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":73,"column":2,"nodeType":"CallExpression","endLine":73,"endColumn":59}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * Translate editor shortcuts\n */\n( function () {\n\t'use strict';\n\tvar translateEditorShortcuts = {\n\t\t/**\n\t\t * @internal\n\t\t */\n\t\tshowShortcuts: function () {\n\t\t\t// Any better way?\n\t\t\tvar rtl = $( document.body ).is( '.rtl' );\n\n\t\t\tvar editorOffset = this.$editor.offset();\n\t\t\tvar minTop = editorOffset.top;\n\t\t\tvar maxTop = minTop + this.$editor.outerHeight();\n\t\t\tvar middle = minTop + ( maxTop - minTop ) / 2;\n\t\t\tvar maxLeft = rtl ? editorOffset.left : editorOffset.left + this.$editor.outerWidth();\n\n\t\t\tthis.hideShortcuts();\n\n\t\t\t// For scrolling up and down\n\t\t\t$( '<div>' )\n\t\t\t\t.text( '↑' )\n\t\t\t\t.addClass( 'shortcut-popup' )\n\t\t\t\t.appendTo( document.body )\n\t\t\t\t.offset( { top: middle - 15, left: maxLeft } )\n\t\t\t\t.css( 'transform', 'translate( -50%, 0 )' );\n\n\t\t\t$( '<div>' )\n\t\t\t\t.text( '↓' )\n\t\t\t\t.addClass( 'shortcut-popup' )\n\t\t\t\t.appendTo( document.body )\n\t\t\t\t.offset( { top: middle + 15, left: maxLeft } )\n\t\t\t\t.css( 'transform', 'translate( -50%, 0 )' );\n\n\t\t\tthis.$editor.find( '.shortcut-activated:visible' ).each( function ( index ) {\n\t\t\t\tvar offset = getStartCornerOffsetOf( $( this ), rtl );\n\n\t\t\t\t// Let's not have numbers appear outside the editor over other content\n\t\t\t\tif ( offset.top > maxTop || offset.top < minTop ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.text( index + 1 )\n\t\t\t\t\t.addClass( 'shortcut-popup' )\n\t\t\t\t\t.appendTo( document.body )\n\t\t\t\t\t.offset( offset )\n\t\t\t\t\t.css( 'transform', 'translate( -50%, -50% )' );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * @internal\n\t\t */\n\t\thideShortcuts: function () {\n\t\t\t$( '.shortcut-popup' ).remove();\n\t\t}\n\t};\n\n\tfunction getStartCornerOffsetOf( $element, rtl ) {\n\t\tvar offset = $element.offset();\n\n\t\tif ( rtl ) {\n\t\t\toffset.left += $element.outerWidth();\n\t\t}\n\n\t\treturn offset;\n\t}\n\n\tmw.translate.editor = mw.translate.editor || {};\n\t$.extend( mw.translate.editor, translateEditorShortcuts );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.messagerenamedialog.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":250,"column":2,"nodeType":"CallExpression","endLine":252,"endColumn":5},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":250,"column":2,"nodeType":"CallExpression","endLine":261,"endColumn":5}],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":299,"column":2,"nodeType":"CallExpression","endLine":299,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":301,"column":2,"nodeType":"CallExpression","endLine":301,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/**\n * Dialog for displaying possible renamed messages.\n * Note that methods are not safe to call before the dialog has initialized.\n *\n * @copyright See AUTHORS.txt\n * @license GPL-2.0-or-later\n */\n\n'use strict';\n\nmw.translate = mw.translate || {};\n\n/**\n * @class\n * @extends OO.ui.ProcessDialog\n *\n * @private\n * @constructor\n * @param {Object} [config] Similar configuration as the OO.ui.ProcessDialog\n * @param {Function} [onRenameSelect] Function to call when the rename button is pressed\n */\nmw.translate.MessageRenameDialog = function ( config, onRenameSelect ) {\n\t// HTML Elements\n\tthis.messageSearch = null;\n\tthis.searchButton = null;\n\tthis.panel = null;\n\tthis.form = null;\n\tthis.$notice = null;\n\n\t// Data properties\n\tthis.possibleRenames = null;\n\tthis.currentGroupId = null;\n\tthis.targetKey = null;\n\tthis.selectedMessage = null;\n\tthis.resetProperties();\n\n\tif ( !onRenameSelect ) {\n\t\tvar errMsg = 'Must provide the \"onRenameSelect\" callback function.';\n\t\tmw.log.error( errMsg );\n\t\tthrow new Error( errMsg );\n\t}\n\tthis.onRenameSelect = onRenameSelect;\n\n\t// Parent constructor\n\tmw.translate.MessageRenameDialog.super.call( this, config );\n};\n\n/* Inheritance */\nOO.inheritClass( mw.translate.MessageRenameDialog, OO.ui.ProcessDialog );\n\n/* Static Properties */\nmw.translate.MessageRenameDialog.static.name = 'MessageRenameDialog';\n\nmw.translate.MessageRenameDialog.static.actions = [\n\t{\n\t\tflags: [ 'primary', 'progressive' ],\n\t\tlabel: mw.msg( 'translate-smg-rename-select' ),\n\t\taction: 'select',\n\t\tactive: true\n\t},\n\t{\n\t\tflags: 'safe',\n\t\tlabel: mw.msg( 'translate-smg-rename-cancel' ),\n\t\taction: 'cancel'\n\t}\n];\n\n/**\n * @inheritdoc\n */\nmw.translate.MessageRenameDialog.prototype.initialize = function () {\n\tmw.translate.MessageRenameDialog.super.prototype.initialize.call( this );\n\n\tthis.messageSearch = new OO.ui.TextInputWidget( {\n\t\tplaceholder: mw.msg( 'translate-smg-rename-search' )\n\t} );\n\n\tthis.searchButton = new OO.ui.ButtonWidget( {\n\t\ticon: 'search',\n\t\tinvisibleLabel: true\n\t} );\n\n\tthis.panel = new OO.ui.PanelLayout( {\n\t\tpadded: true,\n\t\texpanded: false\n\t} );\n\n\tthis.form = new OO.ui.FormLayout( {\n\t\tpadded: true,\n\t\texpanded: false,\n\t\titems: [\n\t\t\tnew OO.ui.ActionFieldLayout( this.messageSearch, this.searchButton, {\n\t\t\t\tclasses: [ 'smg-rename-msg-search' ]\n\t\t\t} )\n\t\t],\n\t\tmethod: 'post'\n\t} );\n\n\tthis.$notice = $( '<p>' )\n\t\t.addClass( 'smg-rename-notice hide' );\n\n\tthis.form.$element.append( this.$notice );\n\tthis.panel.$element.append( this.form.$element );\n\tthis.$body.append( this.panel.$element );\n\n\tthis.addEvents();\n};\n\nmw.translate.MessageRenameDialog.prototype.addEvents = function () {\n\tthis.form.$element.on( 'click', '.smg-rename-list', this.selectMessage.bind( this ) );\n\tthis.messageSearch.on( 'change', OO.ui.debounce( this.filterMessages.bind( this ), 300 ) );\n};\n\n/**\n * @inheritdoc\n */\nmw.translate.MessageRenameDialog.prototype.getSetupProcess = function ( renameDialogData ) {\n\tvar dialogData = renameDialogData || {};\n\treturn mw.translate.MessageRenameDialog.super.prototype.getSetupProcess.call( this, dialogData )\n\t\t.next( function () {\n\t\t\t// Set up contents based on data\n\t\t\tthis.possibleRenames = dialogData.messages;\n\t\t\tthis.currentGroupId = dialogData.groupId;\n\t\t\tthis.targetKey = dialogData.targetKey;\n\t\t\tthis.selectedMessage = null;\n\n\t\t\tthis.displayMessages( this.possibleRenames );\n\t\t}, this );\n};\n\n/**\n * @inheritdoc\n */\nmw.translate.MessageRenameDialog.prototype.getActionProcess = function ( action ) {\n\tif ( action === 'cancel' ) {\n\t\treturn new OO.ui.Process( function () {\n\t\t\tthis.close();\n\t\t\tthis.emit( action );\n\t\t}, this );\n\t} else if ( action === 'select' ) {\n\t\tif ( !this.selectedMessage ) {\n\t\t\treturn new OO.ui.Process( function () {\n\t\t\t\tthis.displayNotice( mw.msg( 'translate-smg-rename-select-err' ), 'error' );\n\t\t\t}, this );\n\t\t}\n\t\treturn mw.translate.MessageRenameDialog.super.prototype.getActionProcess.call( this, action )\n\t\t\t.next( this.rename.bind( this ) )\n\t\t\t.next( function () {\n\t\t\t\treturn this.close().closed;\n\t\t\t}.bind( this ) );\n\t}\n\n\treturn mw.translate.MessageRenameDialog.super.prototype.getActionProcess.call( this, action );\n};\n\n/**\n * @inheritdoc\n */\nmw.translate.MessageRenameDialog.prototype.getTeardownProcess = function ( data ) {\n\treturn mw.translate.MessageRenameDialog.super.prototype.getTeardownProcess.call( this, data )\n\t\t.first( function () {\n\t\t\t// Perform any cleanup as needed\n\t\t\tthis.clearMessages();\n\t\t\tthis.messageSearch.setValue( '' );\n\n\t\t\tthis.resetProperties();\n\t\t}, this );\n};\n\n/**\n * Displays the given messages on the dialog box.\n *\n * @param {Array} messages\n */\nmw.translate.MessageRenameDialog.prototype.displayMessages = function ( messages ) {\n\tif ( !messages.length ) {\n\t\tthis.displayNotice( mw.msg( 'translate-smg-rename-no-msg' ), 'info' );\n\t\treturn;\n\t}\n\n\tfor ( var i = 0; i < messages.length; i++ ) {\n\t\tthis.displayMessage( messages[ i ] );\n\t}\n};\n\n/**\n * Generates the HTML to display a single message\n *\n * @param {Object} message\n */\nmw.translate.MessageRenameDialog.prototype.displayMessage = function ( message ) {\n\tvar $title = $( '<div>' ).append(\n\t\t$( '<a>' ).text( message.title ).addClass( 'smg-rename-msg-key' )\n\t\t\t.prop( 'href', message.link )\n\t\t\t.data( 'msg-key', message.key ),\n\t\t$( '<span>' ).text(\n\t\t\tmw.msg( 'percent', mw.language.convertNumber( ( message.similarity * 100 ).toFixed() ) )\n\t\t).addClass( 'smg-rename-similarity' )\n\t);\n\n\tvar $content = $( '<div>' ).text( message.content ).addClass( 'smg-rename-msg-content' );\n\n\tvar $container = $( '<div>' ).addClass( 'smg-rename-list' );\n\n\t$container.append( $title, $content );\n\n\tthis.form.$element.append( $container );\n};\n\n/**\n * Callback triggered when a message is selected.\n *\n * @param {Object} event\n */\nmw.translate.MessageRenameDialog.prototype.selectMessage = function ( event ) {\n\tvar $target = $( event.currentTarget );\n\tthis.selectedMessage = $target.find( '.smg-rename-msg-key' ).data( 'msgKey' );\n\n\tthis.form.$element.find( '.smg-rename-list' ).removeClass( 'smg-rename-selected' );\n\t$target.addClass( 'smg-rename-selected' );\n\n\tthis.hideNotice();\n};\n\n/**\n * Used to reset the state properties for the dialog box.\n */\nmw.translate.MessageRenameDialog.prototype.resetProperties = function () {\n\tthis.possibleRenames = [];\n\tthis.currentGroupId = null;\n\tthis.targetKey = null;\n\tthis.selectedMessage = null;\n};\n\n/**\n * Perform the actual rename\n *\n * @return {jQuery.Promise} Resolves after making call to the onRenameSelect function.\n */\nmw.translate.MessageRenameDialog.prototype.rename = function () {\n\tvar deferred = $.Deferred();\n\tvar promise = deferred.promise();\n\n\tvar renameData = {\n\t\tgroupId: this.currentGroupId,\n\t\ttargetKey: this.targetKey,\n\t\tselectedKey: this.selectedMessage\n\t};\n\n\tthis.onRenameSelect( renameData ).done( function () {\n\t\treturn deferred.resolve();\n\t} ).fail( function ( code, result ) {\n\t\tif ( result.error ) {\n\t\t\tif ( result.error.code === 'permissiondenied' ) {\n\t\t\t\treturn deferred.reject( new OO.ui.Error( result.error.info,\n\t\t\t\t\t{ recoverable: false } ) );\n\t\t\t}\n\n\t\t\treturn deferred.reject( new OO.ui.Error( result.error.info ) );\n\t\t}\n\t} );\n\n\treturn promise;\n};\n\n/**\n * Callback function triggered to handle the search.\n *\n * @param {Object} searchValue\n */\nmw.translate.MessageRenameDialog.prototype.filterMessages = function ( searchValue ) {\n\tvar normalizedSearchVal = searchValue.toLowerCase(), filteredMessages = [];\n\n\t// if the dialog is closing, let's not do anything.\n\tif ( this.isClosing() || !this.isVisible() ) {\n\t\treturn;\n\t}\n\n\tfilteredMessages = this.possibleRenames.filter( function ( message ) {\n\t\treturn message.key.toLowerCase().includes( normalizedSearchVal ) &&\n\t\t\tmessage.content.toLowerCase().includes( normalizedSearchVal );\n\t} );\n\n\tthis.clearMessages();\n\tthis.displayMessages( filteredMessages );\n\tthis.updateSize();\n};\n\n/**\n * Method use to display a notice on the dialog box\n *\n * @param {string} msg\n * @param {string} type Type of notice to display.\n */\nmw.translate.MessageRenameDialog.prototype.displayNotice = function ( msg, type ) {\n\tvar possibleTypes = [ 'info', 'error', 'warning' ];\n\t// `type` classes documented above. Will be one of \"possibleTypes\".\n\t// eslint-disable-next-line mediawiki/class-doc\n\tthis.$notice.removeClass( possibleTypes );\n\t// eslint-disable-next-line mediawiki/class-doc\n\tthis.$notice.text( msg ).addClass( type ).removeClass( 'hide' );\n\tthis.updateSize();\n};\n\n/**\n * Hide displayed notice.\n */\nmw.translate.MessageRenameDialog.prototype.hideNotice = function () {\n\tthis.$notice.addClass( 'hide' );\n\tthis.updateSize();\n};\n\n/**\n * Clears all messages from the DOM.\n */\nmw.translate.MessageRenameDialog.prototype.clearMessages = function () {\n\tthis.form.$element.find( '.smg-rename-list' ).remove();\n\tthis.hideNotice();\n};\n\n/**\n * @inheritDoc\n */\nmw.translate.MessageRenameDialog.prototype.getReadyProcess = function ( data ) {\n\treturn mw.translate.MessageRenameDialog.super.prototype.getReadyProcess.call( this, data )\n\t\t.next( function () {\n\t\t\tthis.messageSearch.$element.find( 'input' ).trigger( 'focus' );\n\t\t}, this );\n};\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.messagetable.js","messages":[{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":11,"column":17,"nodeType":"CallExpression","endLine":31,"endColumn":5},{"ruleId":"es-x/no-resizable-and-growable-arraybuffers","severity":1,"message":"ES2024 Resizable ArrayBuffer is forbidden.","line":73,"column":5,"nodeType":"MemberExpression","messageId":"forbiddenForResizableArrayBuffer","endLine":73,"endColumn":24},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":275,"column":4,"nodeType":"CallExpression","endLine":306,"endColumn":7},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":285,"column":25,"nodeType":"CallExpression","endLine":285,"endColumn":52},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":392,"column":9,"nodeType":"CallExpression","endLine":392,"endColumn":41},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Positional selector extensions are not allowed","line":406,"column":16,"nodeType":"CallExpression","endLine":406,"endColumn":65},{"ruleId":"es-x/no-resizable-and-growable-arraybuffers","severity":1,"message":"ES2024 Resizable ArrayBuffer is forbidden.","line":409,"column":5,"nodeType":"MemberExpression","messageId":"forbiddenForResizableArrayBuffer","endLine":409,"endColumn":16},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":422,"column":20,"nodeType":"CallExpression","endLine":422,"endColumn":54},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":488,"column":4,"nodeType":"CallExpression","endLine":576,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":488,"column":4,"nodeType":"CallExpression","endLine":578,"endColumn":7},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Positional selector extensions are not allowed","line":535,"column":7,"nodeType":"CallExpression","endLine":535,"endColumn":32}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":8,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\tvar logger = require( 'ext.translate.eventlogginghelpers' );\n\tvar itemsClass = {\n\t\tproofread: '.tux-message-proofread',\n\t\tpage: '.tux-message-pagemode',\n\t\ttranslate: '.tux-message'\n\t};\n\n\tmw.translate = mw.translate || {};\n\tmw.translate = $.extend( mw.translate, {\n\t\t/** @ignore */\n\t\tgetMessages: function ( messageGroup, language, offset, limit, filter ) {\n\t\t\tvar api = new mw.Api();\n\n\t\t\treturn api.get( {\n\t\t\t\taction: 'query',\n\t\t\t\tlist: 'messagecollection',\n\t\t\t\tmcgroup: messageGroup,\n\t\t\t\tmclanguage: language,\n\t\t\t\tmcoffset: offset,\n\t\t\t\tmclimit: limit,\n\t\t\t\tmcfilter: filter,\n\t\t\t\tmcprop: 'definition|translation|tags|properties',\n\t\t\t\trawcontinue: 1,\n\t\t\t\terrorformat: 'html',\n\t\t\t\tformatversion: 2,\n\t\t\t\tuselang: mw.config.get( 'wgUserLanguage' )\n\t\t\t} );\n\t\t}\n\t} );\n\n\tfunction MessageTable( container, options, settings ) {\n\t\tthis.$container = $( container );\n\t\tthis.options = options;\n\t\tthis.options = Object.assign( {}, $.fn.messagetable.defaults, options );\n\t\tthis.settings = settings;\n\t\t// mode can be proofread, page or translate\n\t\tthis.mode = this.options.mode;\n\t\tthis.firstProofreadTipShown = false;\n\t\tthis.initialized = false;\n\t\tthis.$header = this.$container.siblings( '.tux-messagetable-header' );\n\t\t// Container is between these in the dom.\n\t\tthis.$loader = this.$container.siblings( '.tux-messagetable-loader' );\n\t\tthis.$loaderIcon = this.$loader.find( '.tux-loading-indicator' );\n\t\tthis.$loaderInfo = this.$loader.find( '.tux-messagetable-loader-info' );\n\t\tthis.$actionBar = this.$container.siblings( '.tux-action-bar' );\n\t\tthis.$statsBar = this.$actionBar.find( '.tux-message-list-statsbar' );\n\t\tthis.$proofreadOwnTranslations = this.$actionBar.find( '.tux-proofread-own-translations-button' );\n\t\tthis.messages = [];\n\t\tthis.loading = false;\n\t\tthis.init();\n\t\tthis.listen();\n\t}\n\n\tMessageTable.prototype = {\n\t\t/** @private */\n\t\tinit: function () {\n\t\t\tthis.$actionBar.removeClass( 'hide' );\n\t\t},\n\n\t\t/** @private */\n\t\tlisten: function () {\n\t\t\tvar messageTable = this,\n\t\t\t\t$filterInput = this.$container.parent().find( '.tux-message-filter-box' );\n\n\t\t\t// Vector has transitions of 250ms which affect layout. Let those finish.\n\t\t\t$( window ).on( 'scroll', mw.util.debounce( function () {\n\t\t\t\tif ( isLoaderVisible( messageTable.$loader ) ) {\n\t\t\t\t\tmessageTable.load();\n\t\t\t\t}\n\t\t\t}, 250 ) ).on( 'resize', mw.util.throttle( function () {\n\t\t\t\tmessageTable.resize();\n\t\t\t}, 250 ) );\n\n\t\t\t$filterInput.on( 'input', mw.util.debounce( function () {\n\t\t\t\tmessageTable.search( $filterInput.val() );\n\t\t\t}, 250 ) );\n\n\t\t\tthis.$actionBar.find( 'button.proofread-mode-button' ).on( 'click', function () {\n\t\t\t\tmessageTable.switchMode( 'proofread' );\n\t\t\t\tlogger.logClickEvent( 'change_mode', 'review' );\n\t\t\t} );\n\n\t\t\tthis.$actionBar.find( 'button.translate-mode-button' ).on( 'click', function () {\n\t\t\t\tmessageTable.switchMode( 'translate' );\n\t\t\t\tlogger.logClickEvent( 'change_mode', 'list' );\n\t\t\t} );\n\n\t\t\tthis.$actionBar.find( 'button.page-mode-button' ).on( 'click', function () {\n\t\t\t\tmessageTable.switchMode( 'page' );\n\t\t\t\tlogger.logClickEvent( 'change_mode', 'page' );\n\t\t\t} );\n\n\t\t\tthis.$proofreadOwnTranslations.on( 'click', function () {\n\t\t\t\tvar $this = $( this ),\n\t\t\t\t\tenable = !$this.hasClass( 'down' );\n\t\t\t\tmessageTable.$container.toggleClass( 'tux-hide-own', enable );\n\t\t\t\t$this.toggleClass( 'down', enable ).text( mw.msg( enable ?\n\t\t\t\t\t'tux-editor-proofreading-show-own-translations' :\n\t\t\t\t\t'tux-editor-proofreading-hide-own-translations' ) );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Clear the message table\n\t\t *\n\t\t * @private\n\t\t */\n\t\tclear: function () {\n\t\t\tthis.$container.empty();\n\t\t\t$( '.translate-tooltip' ).remove();\n\t\t\tthis.messages = [];\n\t\t\t// Any ongoing loading process will notice this and will reject results.\n\t\t\tthis.loading = false;\n\t\t},\n\n\t\t/**\n\t\t * Adds a new message using current mode.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} message\n\t\t */\n\t\tadd: function ( message ) {\n\t\t\t// Prepare the message for display\n\t\t\tmw.hook( 'mw.translate.messagetable.formatMessageBeforeTable' ).fire( message );\n\n\t\t\tif ( this.mode === 'translate' ) {\n\t\t\t\tthis.addTranslate( message );\n\t\t\t} else if ( this.mode === 'proofread' ) {\n\t\t\t\tthis.addProofread( message );\n\t\t\t} else if ( this.mode === 'page' ) {\n\t\t\t\tthis.addPageModeMessage( message );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Add a message to the message table for translation.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} message\n\t\t */\n\t\taddTranslate: function ( message ) {\n\t\t\tvar targetLangCode = this.$container.data( 'targetlangcode' ),\n\t\t\t\tsourceLangCode = this.$container.data( 'sourcelangcode' ),\n\t\t\t\tsourceLangDir = $.uls.data.getDir( sourceLangCode ),\n\t\t\t\tstatus = message.properties.status,\n\t\t\t\tstatusClass = 'tux-status-' + status,\n\t\t\t\t$messageWrapper = $( '<div>' ).addClass( 'row tux-message' ),\n\t\t\t\tstatusMsg = '';\n\n\t\t\tmessage.proofreadable = false;\n\n\t\t\tif ( message.tags.length &&\n\t\t\t\tmessage.tags.includes( 'optional' ) &&\n\t\t\t\tstatus === 'untranslated'\n\t\t\t) {\n\t\t\t\tstatus = 'optional';\n\t\t\t\tstatusClass = 'tux-status-optional';\n\t\t\t}\n\n\t\t\t// Fuzzy translations need warning class\n\t\t\tif ( status === 'fuzzy' ) {\n\t\t\t\tstatusClass = statusClass + ' tux-notice';\n\t\t\t}\n\n\t\t\t// Label the status if it is not untranslated\n\t\t\tif ( status !== 'untranslated' ) {\n\t\t\t\t// Give grep a chance to find the usages:\n\t\t\t\t// tux-status-optional, tux-status-fuzzy, tux-status-proofread,\n\t\t\t\t// tux-status-translated, tux-status-saving, tux-status-unsaved\n\t\t\t\tstatusMsg = 'tux-status-' + status;\n\t\t\t}\n\n\t\t\tvar targetLangDir, targetLangAttrib;\n\t\t\tif ( targetLangCode === mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\t\ttargetLangAttrib = mw.config.get( 'wgContentLanguage' );\n\t\t\t\ttargetLangDir = $.uls.data.getDir( targetLangAttrib );\n\t\t\t} else {\n\t\t\t\ttargetLangAttrib = targetLangCode;\n\t\t\t\ttargetLangDir = this.$container.data( 'targetlangdir' );\n\t\t\t}\n\n\t\t\tvar $message = $( '<div>' )\n\t\t\t\t.addClass( 'row message tux-message-item ' + status )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'eight columns tux-list-message' )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t\t.addClass( 'tux-list-source' )\n\t\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\t\tlang: sourceLangCode,\n\t\t\t\t\t\t\t\t\tdir: sourceLangDir\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t.text( message.definition ),\n\t\t\t\t\t\t\t// Bidirectional isolation.\n\t\t\t\t\t\t\t// This should be removed some day when proper\n\t\t\t\t\t\t\t// unicode-bidi: isolate\n\t\t\t\t\t\t\t// is supported everywhere\n\t\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t\t.html( $( document.body ).hasClass( 'rtl' ) ? '&rlm;' : '&lrm;' ),\n\t\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t\t.addClass( 'tux-list-translation' )\n\t\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\t\tlang: targetLangAttrib,\n\t\t\t\t\t\t\t\t\tdir: targetLangDir\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t.text( message.translation || '' )\n\t\t\t\t\t\t),\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'two columns tux-list-status text-center' )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t\t.addClass( statusClass )\n\t\t\t\t\t\t\t\t// The following messages are used here:\n\t\t\t\t\t\t\t\t// * tux-status-optional\n\t\t\t\t\t\t\t\t// * tux-status-fuzzy\n\t\t\t\t\t\t\t\t// * tux-status-proofread\n\t\t\t\t\t\t\t\t// * tux-status-translated\n\t\t\t\t\t\t\t\t// * tux-status-saving\n\t\t\t\t\t\t\t\t// * tux-status-unsaved\n\t\t\t\t\t\t\t\t.text( statusMsg ? mw.msg( statusMsg ) : '' )\n\t\t\t\t\t\t),\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'two column tux-list-edit text-right' )\n\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\t\ttitle: mw.msg( 'translate-edit-title', message.key ),\n\t\t\t\t\t\t\t\t\thref: mw.util.getUrl( message.title, { action: 'edit' } )\n\t\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t\t.text( mw.msg( 'tux-edit' ) )\n\t\t\t\t\t\t)\n\t\t\t\t);\n\n\t\t\t$messageWrapper.append( $message );\n\t\t\tthis.$container.append( $messageWrapper );\n\n\t\t\t// Attach translate editor to the message\n\t\t\t$messageWrapper.translateeditor( {\n\t\t\t\tmessage: message\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Add a message to the message table for proofreading.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} message\n\t\t */\n\t\taddProofread: function ( message ) {\n\t\t\tvar $message = $( '<div>' )\n\t\t\t\t.addClass( 'row tux-message tux-message-proofread' );\n\n\t\t\tthis.$container.append( $message );\n\t\t\t$message.proofread( {\n\t\t\t\tmessage: message,\n\t\t\t\tsourcelangcode: this.$container.data( 'sourcelangcode' ),\n\t\t\t\ttargetlangcode: this.$container.data( 'targetlangcode' )\n\t\t\t} );\n\n\t\t\tvar $icon = $message.find( '.tux-proofread-action' );\n\t\t\tif ( $icon.length === 0 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Add autotooltip to first available proofread action icon\n\t\t\tif ( this.firstProofreadTipShown ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.firstProofreadTipShown = true;\n\t\t\t$icon.addClass( 'autotooltip' );\n\n\t\t\tmw.loader.using( 'oojs-ui-core' ).done( function () {\n\t\t\t\tvar tooltip = new OO.ui.PopupWidget( {\n\t\t\t\t\tpadded: true,\n\t\t\t\t\talign: 'center',\n\t\t\t\t\twidth: 250,\n\t\t\t\t\tclasses: [ 'translate-tooltip' ],\n\t\t\t\t\t$content: $( '<p>' ).text( $icon.prop( 'title' ) )\n\t\t\t\t} );\n\n\t\t\t\tsetTimeout( function () {\n\t\t\t\t\tvar $visibleIcon = $( '.autotooltip:visible' );\n\t\t\t\t\tif ( !$visibleIcon.length ) {\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tvar offset = $visibleIcon.offset();\n\t\t\t\t\ttooltip.$element.appendTo( document.body );\n\t\t\t\t\ttooltip\n\t\t\t\t\t\t.toggle( true )\n\t\t\t\t\t\t.toggleClipping( false )\n\t\t\t\t\t\t.togglePositioning( false )\n\t\t\t\t\t\t.setAnchorEdge( 'top' );\n\t\t\t\t\ttooltip.$element.css( {\n\t\t\t\t\t\ttop: offset.top + $visibleIcon.outerHeight() + 5,\n\t\t\t\t\t\tleft: offset.left + $visibleIcon.outerWidth() - tooltip.$element.width() / 2 - 15\n\t\t\t\t\t} );\n\n\t\t\t\t\tsetTimeout( function () {\n\t\t\t\t\t\ttooltip.$element.remove();\n\t\t\t\t\t}, 4000 );\n\t\t\t\t}, 1000 );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Add a message to the message table for wiki page mode.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} message\n\t\t */\n\t\taddPageModeMessage: function ( message ) {\n\t\t\tvar $message = $( '<div>' )\n\t\t\t\t.addClass( 'row tux-message tux-message-pagemode' );\n\n\t\t\tthis.$container.append( $message );\n\t\t\t$message.pagemode( {\n\t\t\t\tmessage: message,\n\t\t\t\tsourcelangcode: this.$container.data( 'sourcelangcode' ),\n\t\t\t\ttargetlangcode: this.$container.data( 'targetlangcode' )\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Search the message filter\n\t\t *\n\t\t * @private\n\t\t * @param {string} query\n\t\t */\n\t\tsearch: function ( query ) {\n\t\t\tvar resultCount = 0,\n\t\t\t\tmatcher = new RegExp( '(^|\\\\s|\\\\b)' + escapeRegex( query ), 'i' );\n\n\t\t\tthis.$container.find( itemsClass[ this.mode ] ).each( function () {\n\t\t\t\tvar $message = $( this ),\n\t\t\t\t\tmessage = ( $message.data( 'translateeditor' ) ||\n\t\t\t\t\t\t$message.data( 'pagemode' ) ||\n\t\t\t\t\t\t$message.data( 'proofread' ) ).message;\n\n\t\t\t\tif (\n\t\t\t\t\tmatcher.test( message.definition ) ||\n\t\t\t\t\tmatcher.test( message.translation ) ||\n\t\t\t\t\tmatcher.test( message.key )\n\t\t\t\t) {\n\t\t\t\t\t$message.removeClass( 'hide' );\n\t\t\t\t\tresultCount++;\n\t\t\t\t} else {\n\t\t\t\t\t$message.addClass( 'hide' );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tvar $result = this.$container.find( '.tux-message-filter-result' );\n\t\t\tif ( !$result.length ) {\n\t\t\t\tvar $note = $( '<div>' )\n\t\t\t\t\t.addClass( 'advanced-search' );\n\n\t\t\t\tvar $button = $( '<button>' )\n\t\t\t\t\t.addClass( 'mw-ui-button' )\n\t\t\t\t\t.text( mw.msg( 'tux-message-filter-advanced-button' ) );\n\n\t\t\t\t$result = $( '<div>' )\n\t\t\t\t\t.addClass( 'tux-message-filter-result' )\n\t\t\t\t\t.append( $note, $button );\n\n\t\t\t\tthis.$container.prepend( $result );\n\t\t\t}\n\n\t\t\tif ( !query ) {\n\t\t\t\t$result.addClass( 'hide' );\n\t\t\t} else {\n\t\t\t\t$result.removeClass( 'hide' )\n\t\t\t\t\t.find( '.advanced-search' )\n\t\t\t\t\t.text( mw.msg( 'tux-message-filter-result', resultCount, query ) );\n\t\t\t\t$result.find( 'button' ).on( 'click', function () {\n\t\t\t\t\twindow.location.href = mw.util.getUrl( 'Special:SearchTranslations', { query: query } );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tthis.updateLastMessage();\n\n\t\t\t// Trigger a scroll event to make sure enough messages are loaded\n\t\t\t$( window ).trigger( 'scroll' );\n\t\t},\n\n\t\t/** @private */\n\t\tresize: function () {\n\t\t\tvar $messageSelector = $( '.row.tux-message-selector' );\n\n\t\t\tif ( $messageSelector.is( ':hidden' ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar actualWidth = 0;\n\t\t\t// Calculate the total width required for the filters\n\t\t\t$messageSelector.children( 'li' ).each( function () {\n\t\t\t\tactualWidth += $( this ).outerWidth( true );\n\t\t\t} );\n\n\t\t\t// Grid row has a min width. After that scrollbars will appear.\n\t\t\t// We are checking whether the message table is wider than the current grid row width.\n\t\t\tif ( actualWidth >= parseInt( $( '.nine.columns' ).width(), 10 ) ) {\n\t\t\t\t$( '.tux-message-selector .more ul' ) // Overflow menu\n\t\t\t\t\t.prepend( $( '.row.tux-message-selector > li.column:last' ).prev() );\n\n\t\t\t\t// See if more items to be pushed to the overflow menu\n\t\t\t\tthis.resize();\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Start loading messages again with new settings.\n\t\t *\n\t\t * @internal\n\t\t * @param {Object} changes\n\t\t */\n\t\tchangeSettings: function ( changes ) {\n\t\t\t// Clear current messages\n\t\t\tthis.clear();\n\t\t\tthis.settings = $.extend( this.settings, changes );\n\n\t\t\tif ( this.initialized === false ) {\n\t\t\t\tthis.switchMode( this.mode );\n\t\t\t}\n\n\t\t\t// Reset the number of messages remaining\n\t\t\tthis.$loaderInfo.text(\n\t\t\t\tmw.msg( 'tux-messagetable-loading-messages', this.$loader.data( 'pagesize' ) )\n\t\t\t);\n\n\t\t\t// Update the target language\n\t\t\tvar languageDetails = mw.translate.getLanguageDetailsForHtml( this.settings.language );\n\t\t\tthis.$container.data( 'targetlangcode', languageDetails.code );\n\t\t\tthis.$container.data( 'targetlangdir', languageDetails.direction );\n\n\t\t\t// Reset the statsbar\n\t\t\tthis.$statsBar\n\t\t\t\t.empty()\n\t\t\t\t.removeData()\n\t\t\t\t.languagestatsbar( {\n\t\t\t\t\tlanguage: this.settings.language,\n\t\t\t\t\tgroup: this.settings.group,\n\t\t\t\t\tonlyLoadCurrentGroupData: true\n\t\t\t\t} );\n\n\t\t\tthis.initialized = true;\n\t\t\t// Reset other info and make visible\n\t\t\tthis.$loader\n\t\t\t\t.removeData( 'offset' )\n\t\t\t\t.removeAttr( 'data-offset' )\n\t\t\t\t.removeClass( 'hide' );\n\n\t\t\tif ( changes.offset ) {\n\t\t\t\tthis.$loader.data( 'offset', changes.offset );\n\t\t\t}\n\n\t\t\tthis.$header.removeClass( 'hide' );\n\t\t\tthis.$actionBar.removeClass( 'hide' );\n\n\t\t\t// Start loading messages\n\t\t\tthis.load( changes.limit );\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t * @param {number} [limit] Only load this many messages and then stop even if there is more.\n\t\t */\n\t\tload: function ( limit ) {\n\t\t\tvar self = this,\n\t\t\t\toffset = this.$loader.data( 'offset' ),\n\t\t\t\tpageSize = limit || this.$loader.data( 'pagesize' );\n\n\t\t\tif ( offset === -1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( this.loading ) {\n\t\t\t\t// Avoid duplicate loading - the offset will be wrong and it will result\n\t\t\t\t// in duplicate messages shown in the page\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.loading = true;\n\t\t\tthis.$loaderIcon.removeClass( 'tux-loading-indicator--stopped' );\n\n\t\t\tmw.translate.getMessages(\n\t\t\t\tthis.settings.group,\n\t\t\t\tthis.settings.language,\n\t\t\t\toffset,\n\t\t\t\tpageSize,\n\t\t\t\tthis.settings.filter\n\t\t\t).done( function ( result ) {\n\t\t\t\tvar messages = result.query.messagecollection;\n\n\t\t\t\tif ( !self.loading ) {\n\t\t\t\t\t// reject. This was cancelled.\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tself.clearLoadErrors();\n\t\t\t\tif ( result.warnings ) {\n\t\t\t\t\tfor ( var i = 0; i !== result.warnings.length; i++ ) {\n\t\t\t\t\t\tvar currentWarning = result.warnings[ i ];\n\t\t\t\t\t\tif ( currentWarning.code === 'translate-language-disabled-source' ) {\n\t\t\t\t\t\t\tself.handleLoadErrors( [ currentWarning ] );\n\t\t\t\t\t\t\tlogger.logEvent(\n\t\t\t\t\t\t\t\t'message_prompt',\n\t\t\t\t\t\t\t\t'change_lang'\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t// Since translation to source language is disabled, do not display any messages\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( currentWarning.code === 'translate-language-targetlang-variant-of-source' ) {\n\t\t\t\t\t\t\tself.displayLoadErrors( [ currentWarning ] );\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( messages.length === 0 ) {\n\t\t\t\t\t// And this is the first load for the filter...\n\t\t\t\t\tif ( self.$container.children().length === 0 ) {\n\t\t\t\t\t\tself.displayEmptyListHelp();\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmessages.forEach( function ( message, index ) {\n\t\t\t\t\tmessage.group = self.settings.group;\n\t\t\t\t\tself.add( message );\n\t\t\t\t\tself.messages.push( message );\n\n\t\t\t\t\tif ( index === 0 && self.mode === 'translate' ) {\n\t\t\t\t\t\t$( '.tux-message:first' ).data( 'translateeditor' ).init();\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tvar state = result.query.metadata && result.query.metadata.state;\n\t\t\t\t$( '.tux-workflow' ).workflowselector(\n\t\t\t\t\tself.settings.group,\n\t\t\t\t\tself.settings.language,\n\t\t\t\t\tstate\n\t\t\t\t).removeClass( 'hide' );\n\n\t\t\t\t// Dynamically loaded messages should pass the search filter if present.\n\t\t\t\tvar query = $( '.tux-message-filter-box' ).val();\n\n\t\t\t\tif ( query ) {\n\t\t\t\t\tself.search( query );\n\t\t\t\t}\n\n\t\t\t\tif ( result[ 'query-continue' ] === undefined || limit ) {\n\t\t\t\t\t// End of messages\n\t\t\t\t\tself.$loader.data( 'offset', -1 )\n\t\t\t\t\t\t.addClass( 'hide' );\n\t\t\t\t} else {\n\t\t\t\t\tself.$loader.data( 'offset', result[ 'query-continue' ].messagecollection.mcoffset );\n\n\t\t\t\t\tvar remaining = result.query.metadata.remaining;\n\n\t\t\t\t\tself.$loaderInfo.text(\n\t\t\t\t\t\tmw.msg( 'tux-messagetable-more-messages', remaining )\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t// Helpfully open the first message in show mode on page load\n\t\t\t\t// But do not open it if we are at the bottom of the page waiting for more translation units\n\t\t\t\tif ( self.messages.length <= pageSize ) {\n\t\t\t\t\t// TODO: Refactor to avoid direct DOM access\n\t\t\t\t\t$( '.tux-message-item' ).first().trigger( 'click' );\n\t\t\t\t}\n\n\t\t\t\tself.updateHideOwnInProofreadingToggleVisibility();\n\t\t\t\tself.updateLastMessage();\n\t\t\t} ).fail( function ( errorCode, response ) {\n\t\t\t\tself.handleLoadErrors( response.errors, errorCode );\n\t\t\t} ).always( function () {\n\t\t\t\tself.$loaderIcon.addClass( 'tux-loading-indicator--stopped' );\n\t\t\t\tself.loading = false;\n\t\t\t} );\n\t\t},\n\n\t\tupdateLastMessage: function () {\n\t\t\tvar $messages = this.$container.find( itemsClass[ this.mode ] );\n\n\t\t\t// If a message was previously marked as \"last\", restore it to normal state\n\t\t\t$messages.filter( '.last-message' ).removeClass( 'last-message' );\n\n\t\t\t// At the class to the current last shown message\n\t\t\t$messages\n\t\t\t\t.not( '.hide' )\n\t\t\t\t.last()\n\t\t\t\t.addClass( 'last-message' );\n\t\t},\n\n\t\t/**\n\t\t * Creates a uniformly styled button for different actions,\n\t\t * shown when there are no messages to display.\n\t\t *\n\t\t * @private\n\t\t * @param {string} labelMsg A message key for the button label.\n\t\t * @param {Function} callback A callback for clicking the button.\n\t\t * @return {jQuery} A button element.\n\t\t */\n\t\totherActionButton: function ( labelMsg, callback ) {\n\t\t\treturn $( '<button>' )\n\t\t\t\t.addClass( 'mw-ui-button mw-ui-progressive mw-ui-big' )\n\t\t\t\t.text( mw.msg( labelMsg ) )\n\t\t\t\t.on( 'click', callback );\n\t\t},\n\n\t\tupdateHideOwnInProofreadingToggleVisibility: function () {\n\t\t\tvar ownTranslations = this.$container.find( '.tux-message-proofread.own-translation' ).length;\n\t\t\tthis.$proofreadOwnTranslations.toggleClass( 'hide', !ownTranslations );\n\t\t},\n\n\t\t/**\n\t\t * If the user selection doesn't show anything,\n\t\t * give some pointers to other things to do.\n\t\t */\n\t\tdisplayEmptyListHelp: function () {\n\t\t\tvar messageTable = this,\n\t\t\t\t// @todo Ugly! This should be provided somehow\n\t\t\t\tselectedTab = $( '.tux-message-selector .selected' ).data( 'title' ),\n\t\t\t\t$wrap = $( '<div>' ).addClass( 'tux-empty-list' ),\n\t\t\t\t$emptyListHeader = $( '<div>' ).addClass( 'tux-empty-list-header' ),\n\t\t\t\t$guide = $( '<div>' ).addClass( 'tux-empty-list-guide' ),\n\t\t\t\t$actions = $( '<div>' ).addClass( 'tux-empty-list-actions' );\n\n\t\t\tif ( messageTable.mode === 'proofread' ) {\n\t\t\t\tif ( selectedTab === 'all' ) {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-no-messages-to-display' ) );\n\t\t\t\t\t$guide.append(\n\t\t\t\t\t\t$( '<p>' )\n\t\t\t\t\t\t\t.text( mw.msg( 'tux-empty-there-are-optional' ) ),\n\t\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t\t.attr( 'href', '#' )\n\t\t\t\t\t\t\t.text( mw.msg( 'tux-empty-show-optional-messages' ) )\n\t\t\t\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t\t\t\t$( '#tux-option-optional' ).trigger( 'click' );\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t} else if ( selectedTab === 'outdated' ) {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-no-outdated-messages' ) );\n\t\t\t\t\t$guide.text( mw.msg( 'tux-empty-list-other-guide' ) );\n\t\t\t\t\t$actions.append( messageTable.otherActionButton(\n\t\t\t\t\t\t'tux-empty-list-other-action',\n\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t$( '.tux-tab-unproofread' ).trigger( 'click' );\n\t\t\t\t\t\t\t// @todo untranslated\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t\t// @todo View all\n\t\t\t\t} else if ( selectedTab === 'translated' ) {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-nothing-to-proofread' ) );\n\t\t\t\t\t$guide.text( mw.msg( 'tux-empty-you-can-help-providing' ) );\n\t\t\t\t\t$actions.append( messageTable.otherActionButton(\n\t\t\t\t\t\t'tux-empty-list-translated-action',\n\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\tmessageTable.switchMode( 'translate' );\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t} else if ( selectedTab === 'unproofread' ) {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-nothing-new-to-proofread' ) );\n\t\t\t\t\t$guide.text( mw.msg( 'tux-empty-you-can-help-providing' ) );\n\t\t\t\t\t$actions.append( messageTable.otherActionButton(\n\t\t\t\t\t\t'tux-empty-you-can-review-already-proofread',\n\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t$( '.tux-tab-translated' ).trigger( 'click' );\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif ( selectedTab === 'all' ) {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-list-all' ) );\n\t\t\t\t\t$guide.text( mw.msg( 'tux-empty-list-all-guide' ) );\n\t\t\t\t} else if ( selectedTab === 'translated' ) {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-list-translated' ) );\n\t\t\t\t\t$guide.text( mw.msg( 'tux-empty-list-translated-guide' ) );\n\t\t\t\t\t$actions.append( messageTable.otherActionButton(\n\t\t\t\t\t\t'tux-empty-list-translated-action',\n\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t$( '.tux-tab-untranslated' ).trigger( 'click' );\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t$emptyListHeader.text( mw.msg( 'tux-empty-list-other' ) );\n\n\t\t\t\t\tif ( mw.translate.canProofread() ) {\n\t\t\t\t\t\t$guide.text( mw.msg( 'tux-empty-list-other-guide' ) );\n\t\t\t\t\t\t$actions.append( messageTable.otherActionButton(\n\t\t\t\t\t\t\t'tux-empty-list-other-action',\n\t\t\t\t\t\t\tfunction () {\n\t\t\t\t\t\t\t\tmessageTable.switchMode( 'proofread' );\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\t$actions.append( $( '<a>' )\n\t\t\t\t\t\t.text( mw.msg( 'tux-empty-list-other-link' ) )\n\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\t$( '.tux-tab-all' ).trigger( 'click' );\n\t\t\t\t\t\t} )\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$wrap.append( $emptyListHeader, $guide, $actions );\n\t\t\tthis.$container.append( $wrap );\n\t\t},\n\n\t\t/**\n\t\t * Switch the message table mode\n\t\t *\n\t\t * @private\n\t\t * @param {string} mode The message table mode to switch to: translate, page or proofread\n\t\t */\n\t\tswitchMode: function ( mode ) {\n\t\t\tvar messageTable = this,\n\t\t\t\tfilter = this.settings.filter,\n\t\t\t\tuserId = mw.config.get( 'wgUserId' );\n\n\t\t\tmessageTable.$actionBar.find( '.tux-view-switcher .down' ).removeClass( 'down' );\n\t\t\tif ( mode === 'translate' ) {\n\t\t\t\tmessageTable.$actionBar.find( '.translate-mode-button' ).addClass( 'down' );\n\t\t\t}\n\t\t\tif ( mode === 'proofread' ) {\n\t\t\t\tmessageTable.$actionBar.find( '.proofread-mode-button' ).addClass( 'down' );\n\t\t\t}\n\t\t\tif ( mode === 'page' ) {\n\t\t\t\tmessageTable.$actionBar.find( '.page-mode-button' ).addClass( 'down' );\n\t\t\t}\n\n\t\t\tmessageTable.firstProofreadTipShown = false;\n\n\t\t\tmessageTable.mode = mode;\n\t\t\tmw.translate.changeUrl( { action: messageTable.mode } );\n\n\t\t\t// Emulate clear without clearing loaded messages\n\t\t\tmessageTable.$container.empty();\n\t\t\t$( '.translate-tooltip' ).remove();\n\n\t\t\tvar $tuxTabUntranslated = $( '.tux-message-selector > .tux-tab-untranslated' );\n\t\t\tvar $tuxTabUnproofread = $( '.tux-message-selector > .tux-tab-unproofread' );\n\t\t\tvar $hideTranslatedButton = messageTable.$actionBar.find( '.tux-editor-clear-translated' );\n\n\t\t\tif ( messageTable.mode === 'proofread' ) {\n\t\t\t\t$tuxTabUntranslated.addClass( 'hide' );\n\t\t\t\t$tuxTabUnproofread.removeClass( 'hide' );\n\n\t\t\t\t// Fix the filter if it is untranslated. Untranslated does not make sense\n\t\t\t\t// for proofread mode. Keep the filter if it is not 'untranslated'\n\t\t\t\tif ( !filter || filter.includes( '!translated' ) ) {\n\t\t\t\t\tmessageTable.messages = [];\n\t\t\t\t\t// default filter for proofread mode\n\t\t\t\t\tmw.translate.changeFilter( 'translated|!reviewer:' + userId +\n\t\t\t\t\t\t'|!last-translator:' + userId );\n\t\t\t\t\t$tuxTabUnproofread.addClass( 'selected' );\n\t\t\t\t\t// Own translations are not present in proofread + unreviewed mode\n\t\t\t\t}\n\n\t\t\t\t$hideTranslatedButton.addClass( 'hide' );\n\t\t\t} else {\n\t\t\t\t$tuxTabUntranslated.removeClass( 'hide' );\n\t\t\t\t$tuxTabUnproofread.addClass( 'hide' );\n\n\t\t\t\tif ( filter.includes( '!translated' ) ) {\n\t\t\t\t\t$hideTranslatedButton.removeClass( 'hide' );\n\t\t\t\t}\n\n\t\t\t\tif ( filter && filter.includes( '!last-translator' ) ) {\n\t\t\t\t\tmessageTable.messages = [];\n\t\t\t\t\t// default filter for translate mode\n\t\t\t\t\tmw.translate.changeFilter( '!translated' );\n\t\t\t\t\t$tuxTabUntranslated.addClass( 'selected' );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( messageTable.messages.length ) {\n\t\t\t\tmessageTable.messages.forEach( function ( message ) {\n\t\t\t\t\tmessageTable.add( message );\n\t\t\t\t} );\n\t\t\t} else if ( messageTable.initialized && !messageTable.loading ) {\n\t\t\t\tmessageTable.displayEmptyListHelp();\n\t\t\t}\n\n\t\t\tthis.$loaderInfo.text(\n\t\t\t\tmw.msg( 'tux-messagetable-loading-messages', this.$loader.data( 'pagesize' ) )\n\t\t\t);\n\n\t\t\tmessageTable.updateHideOwnInProofreadingToggleVisibility();\n\t\t\tmessageTable.updateLastMessage();\n\t\t},\n\n\t\t/**\n\t\t * Clear errors encountered during the loading state\n\t\t *\n\t\t * @private\n\t\t */\n\t\tclearLoadErrors: function () {\n\t\t\t$( '.tux-editor-header .tux-group-warning .tux-api-load-error' ).remove();\n\t\t},\n\n\t\t/**\n\t\t * Display errors encountered during the loading state.\n\t\t *\n\t\t * @private\n\t\t * @param {Array} errors\n\t\t * @param {string} errorCode\n\t\t */\n\t\tdisplayLoadErrors: function ( errors, errorCode ) {\n\t\t\tvar $warningContainer = $( '.tux-editor-header .tux-group-warning' );\n\n\t\t\tif ( errors ) {\n\t\t\t\terrors.forEach( function ( error ) {\n\t\t\t\t\t$warningContainer.append(\n\t\t\t\t\t\t$( '<p>' )\n\t\t\t\t\t\t\t.addClass( 'tux-api-load-error' )\n\t\t\t\t\t\t\t.html( error.html )\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t$warningContainer.append(\n\t\t\t\t\t$( '<p>' )\n\t\t\t\t\t\t.addClass( 'tux-api-load-error' )\n\t\t\t\t\t\t.text( mw.msg( 'api-error-unknownerror', errorCode ) )\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Displays the errors and updates the state of the table.\n\t\t *\n\t\t * @private\n\t\t * @param {Array} errors\n\t\t * @param {string} errorCode\n\t\t */\n\t\thandleLoadErrors: function ( errors, errorCode ) {\n\t\t\tthis.displayLoadErrors( errors, errorCode );\n\n\t\t\t$( '.tux-workflow' ).addClass( 'hide' );\n\t\t\tthis.$loader.data( 'offset', -1 ).addClass( 'hide' );\n\t\t\tthis.$actionBar.addClass( 'hide' );\n\t\t\tthis.$header.addClass( 'hide' );\n\t\t}\n\t};\n\n\t/*\n\t * messagetable PLUGIN DEFINITION\n\t */\n\n\t$.fn.messagetable = function ( options ) {\n\t\treturn this.each( function () {\n\t\t\tvar $this = $( this ),\n\t\t\t\tdata = $this.data( 'messagetable' );\n\n\t\t\tif ( !data ) {\n\t\t\t\t$this.data( 'messagetable', ( data = new MessageTable( this, options ) ) );\n\t\t\t}\n\n\t\t\tif ( typeof options === 'string' ) {\n\t\t\t\tdata[ options ].call( $this );\n\t\t\t}\n\t\t} );\n\t};\n\n\t$.fn.messagetable.Constructor = MessageTable;\n\n\t$.fn.messagetable.defaults = {\n\t\tmode: new mw.Uri().query.action || 'translate'\n\t};\n\n\t/**\n\t * Escape the search query for regex match.\n\t *\n\t * @param {string} value A search string to be escaped.\n\t * @return {string} Escaped string that is safe to use for a search.\n\t */\n\tfunction escapeRegex( value ) {\n\t\treturn value.replace( /[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&' );\n\t}\n\n\tfunction isLoaderVisible( $loader ) {\n\t\tvar $window = $( window );\n\n\t\tvar viewportBottom = ( window.innerHeight ? window.innerHeight : $window.height() ) +\n\t\t\t$window.scrollTop();\n\n\t\tvar elementTop = $loader.offset().top;\n\n\t\t// Start already if user is reaching close to the bottom\n\t\treturn elementTop - viewportBottom < 200;\n\t}\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.navitoggle.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.pagemode.js","messages":[],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":62,"column":6,"nodeType":"CallExpression","endLine":64,"endColumn":50,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":87,"column":4,"nodeType":"CallExpression","endLine":115,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":90,"column":5,"nodeType":"CallExpression","endLine":91,"endColumn":91,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":95,"column":7,"nodeType":"CallExpression","endLine":96,"endColumn":87,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.pagetranslation.uls.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.parsers.js","messages":[{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":13,"column":17,"nodeType":"CallExpression","endLine":88,"endColumn":5}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * A set of simple tools for partial parsing and formatting of translatable\n * messages.\n *\n * @author Niklas Laxström\n * @license GPL-2.0-or-later\n */\n\n( function () {\n\t'use strict';\n\n\tmw.translate = mw.translate || {};\n\tmw.translate = $.extend( mw.translate, {\n\t\t/**\n\t\t * Formats some common wikitext elements.\n\t\t *\n\t\t * @internal\n\t\t * @param {string} text Message text\n\t\t * @param {string} [key] Message key\n\t\t * @return {string} Formatted text in html\n\t\t */\n\t\tformatMessageGently: function ( text, key ) {\n\t\t\tvar protocols = mw.config.get( 'wgUrlProtocols' );\n\n\t\t\t// Try to keep simple.\n\t\t\ttext = $( '<div>' ).text( text ).html();\n\n\t\t\t// Hack for page translation page titles\n\t\t\tif ( text && key && key.match( /\\/Page_display_title$/ ) ) {\n\t\t\t\ttext = '=' + text + '=';\n\t\t\t}\n\n\t\t\ttext = text.replace( /^(=+) ?(.*?) ?(=+)$/gm, function ( match, p1, p2, p3 ) {\n\t\t\t\tvar len = Math.min( p1.length, p3.length, 6 );\n\t\t\t\treturn $( '<div>' ).append( $( '<h' + len + '>' ).html( p2 ) ).html();\n\t\t\t} );\n\n\t\t\ttext = text.replace( /(^\\*.*(\\n|$))+/gm, function ( match ) {\n\t\t\t\tmatch = match.replace( /^\\*(.*)/gm, function ( fullMatch, p1 ) {\n\t\t\t\t\treturn $( '<div>' ).append( $( '<li>' ).html( p1 ) ).html();\n\t\t\t\t} );\n\t\t\t\treturn $( '<div>' ).append( $( '<ul>' ).html( match ) ).html();\n\t\t\t} );\n\n\t\t\ttext = text.replace( /(^#.*(\\n|$))+/gm, function ( match ) {\n\t\t\t\tmatch = match.replace( /^#(.*)/gm, function ( fullMatch, p1 ) {\n\t\t\t\t\treturn $( '<div>' ).append( $( '<li>' ).html( p1 ) ).html();\n\t\t\t\t} );\n\t\t\t\treturn $( '<div>' ).append( $( '<ol>' ).html( match ) ).html();\n\t\t\t} );\n\n\t\t\ttext = text.replace( /\\[\\[([^\\]|]+?)\\|(.+?)\\]\\]/g, function ( match, p1, p2 ) {\n\t\t\t\tvar $link = $( '<a>' ).html( p2 ).prop( 'href', mw.util.getUrl( p1 ) );\n\t\t\t\treturn $( '<div>' ).append( $link ).html();\n\t\t\t} );\n\n\t\t\ttext = text.replace( /\\[\\[(.+?)\\]\\]/g, function ( match, p1 ) {\n\t\t\t\tvar $link = $( '<a>' ).html( p1 ).prop( 'href', mw.util.getUrl( p1 ) );\n\t\t\t\treturn $( '<div>' ).append( $link ).html();\n\t\t\t} );\n\n\t\t\tvar externals = new RegExp( '\\\\[((' + protocols + ')[^ ]+) (.+?)\\\\]', 'g' );\n\t\t\ttext = text.replace( externals, function ( match, p1, p2, p3 ) {\n\t\t\t\tvar $link = $( '<a>' ).html( p3 ).prop( 'href', p1 );\n\t\t\t\treturn $( '<div>' ).append( $link ).html();\n\t\t\t} );\n\n\t\t\ttext = text.replace( /('')?'''(.+?)('')?'''/g, function ( match, p1, p2, p3 ) {\n\t\t\t\tp1 = p1 || '';\n\t\t\t\tp3 = p3 || '';\n\t\t\t\tif ( /''/.test( p2 ) && ( p1 || p3 ) ) {\n\t\t\t\t\t// Move p1 and p3 to p2 (inside <strong> tags)\n\t\t\t\t\t// if italic text ends inside bold\n\t\t\t\t\tp2 = p1 + p2 + p3;\n\t\t\t\t\tp1 = '';\n\t\t\t\t\tp3 = '';\n\t\t\t\t}\n\t\t\t\treturn p1 + $( '<div>' ).append( $( '<strong>' ).html( p2 ) ).html() + p3;\n\t\t\t} );\n\n\t\t\ttext = text.replace( /''(.+?)''/g, function ( match, p1 ) {\n\t\t\t\treturn $( '<div>' ).append( $( '<em>' ).html( p1 ) ).html();\n\t\t\t} );\n\n\t\t\ttext = text.replace( /\\n\\n/gm, '<br />' );\n\t\t\treturn text;\n\t\t}\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.proofread.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":235,"column":4,"nodeType":"CallExpression","endLine":255,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":235,"column":4,"nodeType":"CallExpression","endLine":261,"endColumn":7}],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":77,"column":6,"nodeType":"CallExpression","endLine":79,"endColumn":50,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":106,"column":27,"nodeType":"CallExpression","endLine":110,"endColumn":6,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":136,"column":4,"nodeType":"CallExpression","endLine":171,"endColumn":48,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":142,"column":7,"nodeType":"CallExpression","endLine":143,"endColumn":100,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":259,"column":6,"nodeType":"CallExpression","messageId":"unexpected","endLine":259,"endColumn":46,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\tvar logger = require( 'ext.translate.eventlogginghelpers' );\n\n\t/**\n\t * Proofread Plugin\n\t *\n\t * Prepare a proofread UI with all the required actions\n\t * for a translation unit (message).\n\t * This is mainly used with the messagetable plugin in proofread mode,\n\t * but it is independent of messagetable.\n\t * Example usage:\n\t *\n\t * $( 'div.proofread' ).proofread( {\n\t *     message: messageObject, // Mandatory message object\n\t *     sourcelangcode: 'en', // Mandatory source language code\n\t *     targetlangcode: 'hi' // Mandatory target language code\n\t * } );\n\t *\n\t * @private\n\t * @param {Element} element\n\t * @param {Object} options\n\t * @param {Object} options.message\n\t * @param {string} options.sourcelangcode Language code.\n\t * @param {string} options.targetlangcode Language code.\n\t */\n\tfunction Proofread( element, options ) {\n\t\tthis.$message = $( element );\n\t\tthis.options = options;\n\t\tthis.message = this.options.message;\n\t\tthis.init();\n\t\tthis.listen();\n\t}\n\n\tProofread.prototype = {\n\n\t\t/**\n\t\t * Initialize the plugin\n\t\t *\n\t\t * @private\n\t\t */\n\t\tinit: function () {\n\t\t\tvar that = this;\n\n\t\t\tthis.render();\n\n\t\t\t// No review before translating.\n\t\t\tif ( !this.message.translation ) {\n\t\t\t\tthis.disableProofread();\n\t\t\t}\n\n\t\t\t// No review for fuzzy messages.\n\t\t\tif ( this.message.properties.status === 'fuzzy' ) {\n\t\t\t\tthis.disableProofread();\n\t\t\t}\n\n\t\t\tif ( !mw.translate.canProofread() ) {\n\t\t\t\tthis.disableProofread();\n\t\t\t}\n\n\t\t\tthis.$message.translateeditor( {\n\t\t\t\tmessage: this.message,\n\t\t\t\tbeforeSave: function ( translation ) {\n\t\t\t\t\tthat.$message.find( '.tux-proofread-translation' )\n\t\t\t\t\t\t.html( mw.translate.formatMessageGently( translation || '', that.message.key ) )\n\t\t\t\t\t\t.addClass( 'highlight' );\n\t\t\t\t},\n\t\t\t\tonSave: function ( translation ) {\n\t\t\t\t\tthat.$message.find( '.tux-proofread-translation' )\n\t\t\t\t\t\t.text( translation )\n\t\t\t\t\t\t.removeClass( 'highlight' );\n\t\t\t\t\tthat.message.translation = translation;\n\t\t\t\t\tthat.markSelfTranslation();\n\n\t\t\t\t\t// `status` class is documented elsewhere\n\t\t\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\t\t\tthat.$message.find( '.tux-proofread-status' )\n\t\t\t\t\t\t.removeClass( 'translated fuzzy proofread untranslated' )\n\t\t\t\t\t\t.addClass( that.message.properties.status );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t */\n\t\trender: function () {\n\t\t\t// List of all reviewers\n\t\t\tvar reviewers = this.message.properties.reviewers || [];\n\t\t\t// The id of the current user, converted to string as the are in reviewers\n\t\t\tvar userId = String( mw.config.get( 'wgUserId' ) );\n\t\t\t// List of all reviewers excluding the current user.\n\t\t\tvar otherReviewers = reviewers.filter( function ( element ) {\n\t\t\t\treturn element !== userId;\n\t\t\t} );\n\t\t\t/* Whether the current user if the last translator of this message.\n\t\t\t * Accepting own translations is prohibited. */\n\t\t\tvar translatedBySelf = ( this.message.properties[ 'last-translator-text' ] === mw.user.getName() );\n\t\t\tvar proofreadBySelf = reviewers.includes( userId );\n\n\t\t\tvar sourceLangDir = $.uls.data.getDir( this.options.sourcelangcode );\n\n\t\t\t// `status` class is documented elsewhere\n\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\tvar $proofreadAction = $( '<div>' )\n\t\t\t\t.attr( 'title', mw.msg( 'tux-proofread-action-tooltip' ) )\n\t\t\t\t.addClass(\n\t\t\t\t\t'tux-proofread-action ' + this.message.properties.status + ' ' + ( proofreadBySelf ? 'accepted' : '' )\n\t\t\t\t);\n\n\t\t\tvar $proofreadEdit = $( '<div>' )\n\t\t\t\t.addClass( 'tux-proofread-edit' )\n\t\t\t\t.append( $( '<span>' )\n\t\t\t\t\t.addClass( 'tux-proofread-edit-label hide' )\n\t\t\t\t\t.text( mw.msg( 'tux-proofread-edit-label' ) )\n\t\t\t\t)\n\t\t\t\t.on( 'mouseover', function () {\n\t\t\t\t\t$( this ).find( '.tux-proofread-edit-label' ).removeClass( 'hide' );\n\t\t\t\t} )\n\t\t\t\t.on( 'mouseout', function () {\n\t\t\t\t\t$( this ).find( '.tux-proofread-edit-label' ).addClass( 'hide' );\n\t\t\t\t} );\n\n\t\t\tvar targetLangAttrib;\n\t\t\tif ( this.options.targetlangcode === mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\t\ttargetLangAttrib = mw.config.get( 'wgContentLanguage' );\n\t\t\t} else {\n\t\t\t\ttargetLangAttrib = this.options.targetlangcode;\n\t\t\t}\n\n\t\t\tvar targetLangDir = $.uls.data.getDir( targetLangAttrib );\n\n\t\t\t// `status` class is documented elsewhere\n\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\tthis.$message.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'row tux-message-item-compact message' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t// `status` class is documented elsewhere\n\t\t\t\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'one column tux-proofread-status skin-invert ' + this.message.properties.status ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'five columns tux-proofread-source' )\n\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\tlang: this.options.sourcelangcode,\n\t\t\t\t\t\t\t\tdir: sourceLangDir\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.text( this.message.definition ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'five columns tux-proofread-translation' )\n\t\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\t\tlang: targetLangAttrib,\n\t\t\t\t\t\t\t\tdir: targetLangDir\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.text( this.message.translation || '' ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'tux-proofread-action-block one column' )\n\t\t\t\t\t\t\t.append(\n\t\t\t\t\t\t\t\t$proofreadAction,\n\t\t\t\t\t\t\t\totherReviewers.length ?\n\t\t\t\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t\t\t\t.addClass( 'tux-proofread-count' )\n\t\t\t\t\t\t\t\t\t\t.data( 'reviewCount', reviewers.length ) // To update when accepting\n\t\t\t\t\t\t\t\t\t\t.text( mw.language.convertNumber( reviewers.length ) ) :\n\t\t\t\t\t\t\t\t\t$( [] ),\n\t\t\t\t\t\t\t\t$proofreadEdit\n\t\t\t\t\t\t\t)\n\t\t\t\t\t)\n\t\t\t).addClass( this.message.properties.status );\n\n\t\t\tif ( !translatedBySelf && !proofreadBySelf ) {\n\t\t\t\t// This will get removed later if any of various other reasons prevent it\n\t\t\t\tthis.message.proofreadable = true;\n\t\t\t\tthis.message.proofreadAction = this.proofread.bind( this );\n\t\t\t}\n\n\t\t\tif ( translatedBySelf ) {\n\t\t\t\tthis.markSelfTranslation();\n\t\t\t}\n\n\t\t\t/* Here we need to check that there are reviewers in the first place\n\t\t\t * before adding review markers */\n\t\t\tif ( reviewers.length && otherReviewers.length ) {\n\t\t\t\tthis.$message.addClass( 'proofread-by-others' );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t */\n\t\tdisableProofread: function () {\n\t\t\tthis.message.proofreadable = false;\n\t\t\tthis.$message.find( '.tux-proofread-action' )\n\t\t\t\t.remove();\n\t\t},\n\n\t\t/**\n\t\t * Mark the message self translated.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tmarkSelfTranslation: function () {\n\t\t\t// Own translations cannot be reviewed, so disable proofread\n\t\t\tthis.disableProofread();\n\t\t\tif ( !this.$message.hasClass( 'own-translation' ) ) {\n\t\t\t\tthis.$message.addClass( 'own-translation' )\n\t\t\t\t\t.find( '.tux-proofread-action-block' )\n\t\t\t\t\t.append( $( '<div>' )\n\t\t\t\t\t\t.addClass( 'translated-by-self' )\n\t\t\t\t\t\t.attr( 'title', mw.msg( 'tux-proofread-translated-by-self' ) )\n\t\t\t\t\t);\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * Mark this message as proofread.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tproofread: function () {\n\t\t\tvar message = this.message,\n\t\t\t\t$message = this.$message,\n\t\t\t\tapi = new mw.Api();\n\n\t\t\tvar params = {\n\t\t\t\taction: 'translationreview',\n\t\t\t\trevision: this.message.properties.revision\n\t\t\t};\n\n\t\t\tif ( !mw.user.isAnon() ) {\n\t\t\t\tparams.assert = 'user';\n\t\t\t}\n\n\t\t\tapi.postWithToken( 'csrf', params ).done( function () {\n\t\t\t\t$message.find( '.tux-proofread-action' )\n\t\t\t\t\t.removeClass( 'tux-notice' ) // in case, it failed previously\n\t\t\t\t\t.addClass( 'accepted' );\n\n\t\t\t\tvar $counter = $message.find( '.tux-proofread-count' );\n\t\t\t\tvar reviews = $counter.data( 'reviewCount' );\n\t\t\t\t$counter.text( mw.language.convertNumber( reviews + 1 ) );\n\n\t\t\t\t// Update stats\n\t\t\t\t$( '.tux-action-bar .tux-statsbar' ).trigger(\n\t\t\t\t\t'change',\n\t\t\t\t\t[ 'proofread', message.properties.status ]\n\t\t\t\t);\n\n\t\t\t\tmessage.properties.status = 'proofread';\n\n\t\t\t\tif ( mw.track ) {\n\t\t\t\t\tmw.track( 'ext.translate.event.proofread', message );\n\t\t\t\t}\n\t\t\t} ).fail( function ( errorCode ) {\n\t\t\t\t$message.find( '.tux-proofread-action' ).addClass( 'tux-notice' );\n\t\t\t\tif ( errorCode === 'assertuserfailed' ) {\n\t\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\t\talert( mw.msg( 'tux-session-expired' ) );\n\t\t\t\t}\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Attach event listeners\n\t\t *\n\t\t * @private\n\t\t */\n\t\tlisten: function () {\n\t\t\tvar that = this;\n\n\t\t\tthis.$message.find( '.tux-proofread-action' ).on( 'click', function () {\n\t\t\t\tthat.proofread();\n\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t'review',\n\t\t\t\t\t'review_button'\n\t\t\t\t);\n\t\t\t\treturn false;\n\t\t\t} );\n\n\t\t\tthis.$message.find( '.tux-proofread-edit' ).on( 'click', function () {\n\t\t\t\t// Make sure that the tooltip is hidden when going to the editor\n\t\t\t\t$( '.translate-tooltip' ).remove();\n\t\t\t\tthat.$message.data( 'translateeditor' ).show();\n\n\t\t\t\treturn false;\n\t\t\t} );\n\t\t}\n\t};\n\n\t/**\n\t * proofread PLUGIN DEFINITION\n\t *\n\t * @internal\n\t * @param {Object} options\n\t * @return {jQuery}\n\t */\n\t$.fn.proofread = function ( options ) {\n\t\treturn this.each( function () {\n\t\t\tvar $this = $( this ),\n\t\t\t\tdata = $this.data( 'proofread' );\n\n\t\t\tif ( !data ) {\n\t\t\t\t$this.data( 'proofread', new Proofread( this, options ) );\n\t\t\t}\n\n\t\t} );\n\t};\n\n\t$.fn.proofread.Constructor = Proofread;\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.recentgroups.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.selecttoinput.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.aggregategroups.js","messages":[{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":19,"column":16,"nodeType":"CallExpression","endLine":22,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":24,"column":3,"nodeType":"CallExpression","endLine":25,"endColumn":28},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":24,"column":3,"nodeType":"CallExpression","endLine":29,"endColumn":7},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":70,"column":17,"nodeType":"CallExpression","endLine":73,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":75,"column":4,"nodeType":"CallExpression","endLine":76,"endColumn":29},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":75,"column":4,"nodeType":"CallExpression","endLine":80,"endColumn":8},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":99,"column":17,"nodeType":"CallExpression","endLine":101,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":103,"column":4,"nodeType":"CallExpression","endLine":104,"endColumn":29},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":103,"column":4,"nodeType":"CallExpression","endLine":108,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":145,"column":3,"nodeType":"CallExpression","endLine":146,"endColumn":28},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":145,"column":3,"nodeType":"CallExpression","endLine":150,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":397,"column":4,"nodeType":"CallExpression","endLine":398,"endColumn":29},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":397,"column":4,"nodeType":"CallExpression","endLine":402,"endColumn":8}],"suppressedMessages":[{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":28,"column":5,"nodeType":"CallExpression","messageId":"unexpected","endLine":28,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":79,"column":6,"nodeType":"CallExpression","messageId":"unexpected","endLine":79,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":83,"column":4,"nodeType":"CallExpression","messageId":"unexpected","endLine":83,"endColumn":42,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected confirm.","line":98,"column":4,"nodeType":"CallExpression","messageId":"unexpected","endLine":98,"endColumn":67,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":107,"column":6,"nodeType":"CallExpression","messageId":"unexpected","endLine":107,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":149,"column":5,"nodeType":"CallExpression","messageId":"unexpected","endLine":149,"endColumn":29,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":235,"column":5,"nodeType":"CallExpression","messageId":"unexpected","endLine":235,"endColumn":43,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":401,"column":6,"nodeType":"CallExpression","messageId":"unexpected","endLine":401,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":10,"fatalErrorCount":0,"warningCount":3,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\n\tfunction getApiParams( $target ) {\n\t\treturn {\n\t\t\taction: 'aggregategroups',\n\t\t\taggregategroup: $target.parents( '.mw-tpa-group' ).data( 'groupid' )\n\t\t};\n\t}\n\n\tfunction dissociate( event ) {\n\t\tvar $target = $( event.target ),\n\t\t\tapi = new mw.Api();\n\n\t\tfunction successFunction() {\n\t\t\t$target.parent( 'li' ).remove();\n\t\t}\n\n\t\tvar params = $.extend( getApiParams( $target ), {\n\t\t\tdo: 'dissociate',\n\t\t\tgroup: $target.data( 'groupid' )\n\t\t} );\n\n\t\tapi.postWithToken( 'csrf', params )\n\t\t\t.done( successFunction )\n\t\t\t.fail( function ( code, data ) {\n\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\talert( data.error && data.error.info );\n\t\t\t} );\n\t}\n\n\tfunction associate( event, subGroupId ) {\n\t\tvar $target = $( event.target ),\n\t\t\t$parent = $target.parents( '.mw-tpa-group' ),\n\t\t\tparentId = $parent.data( 'id' ),\n\t\t\tsubgroupName = $parent\n\t\t\t\t.find( '.tes-entity-selector' )\n\t\t\t\t.find( 'input[type=\"text\"]' )\n\t\t\t\t.val(),\n\t\t\tapi = new mw.Api();\n\n\t\t// Clear the selected group value\n\t\t$parent.find( '.tes-entity-selector' ).find( 'input[type=\"text\"]' ).val( '' );\n\n\t\tvar successFunction = function ( data ) {\n\t\t\tvar aAttr, $a, spanAttr, $span, $ol;\n\n\t\t\taAttr = {\n\t\t\t\thref: data.aggregategroups.groupUrls[ subGroupId ],\n\t\t\t\ttitle: subgroupName\n\t\t\t};\n\n\t\t\t$a = $( '<a>', aAttr ).text( subgroupName );\n\n\t\t\tspanAttr = {\n\t\t\t\tclass: 'tp-aggregate-remove-button',\n\t\t\t\t'data-groupid': subGroupId\n\t\t\t};\n\n\t\t\t$span = $( '<span>', spanAttr );\n\n\t\t\t$ol = $( '#mw-tpa-grouplist-' + parentId );\n\t\t\t$ol.append( $( '<li>' ).append( $a, $span ) );\n\t\t\t$span.on( 'click', dissociate );\n\t\t};\n\n\t\t// Get the label for the value and make API request if valid\n\n\t\tif ( subGroupId ) {\n\t\t\tvar params = $.extend( getApiParams( $target ), {\n\t\t\t\tdo: 'associate',\n\t\t\t\tgroup: subGroupId\n\t\t\t} );\n\n\t\t\tapi.postWithToken( 'csrf', params )\n\t\t\t\t.done( successFunction )\n\t\t\t\t.fail( function ( code, data ) {\n\t\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\t\talert( data.error && data.error.info );\n\t\t\t\t} );\n\t\t} else {\n\t\t\t// eslint-disable-next-line no-alert\n\t\t\talert( mw.msg( 'tpt-invalid-group' ) );\n\t\t}\n\t}\n\n\tfunction removeGroup( event ) {\n\t\tvar $target = $( event.target ),\n\t\t\tapi = new mw.Api();\n\n\t\tfunction successFunction() {\n\t\t\t$( event.target ).parents( '.mw-tpa-group' ).remove();\n\t\t}\n\n\t\t// XXX: 'confirm' is nonstandard.\n\t\tif ( typeof window.confirm === 'function' &&\n\t\t\t// eslint-disable-next-line no-alert\n\t\t\twindow.confirm( mw.msg( 'tpt-aggregategroup-remove-confirm' ) ) ) {\n\t\t\tvar params = $.extend( getApiParams( $target ), {\n\t\t\t\tdo: 'remove'\n\t\t\t} );\n\n\t\t\tapi.postWithToken( 'csrf', params )\n\t\t\t\t.done( successFunction )\n\t\t\t\t.fail( function ( code, data ) {\n\t\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\t\talert( data.error && data.error.info );\n\t\t\t\t} );\n\t\t}\n\t}\n\n\tfunction editGroup( event ) {\n\t\tvar $target = $( event.target ),\n\t\t\t$parent = $target.closest( '.mw-tpa-group' ),\n\t\t\taggregateGroupId = $parent.data( 'groupid' ),\n\t\t\t$displayGroup = $parent.children( '.tp-display-group' ),\n\t\t\t$editGroup = $parent.children( '.tp-edit-group' ),\n\t\t\t$aggGroupNameInputName = $editGroup.children( 'input.tp-aggregategroup-edit-name' ),\n\t\t\t$aggGroupNameInputDesc = $editGroup.children( 'input.tp-aggregategroup-edit-description' ),\n\t\t\t$aggGroupNameInputLanguage = $editGroup.children( 'select.tp-aggregategroup-edit-source-language' ),\n\t\t\taggregateGroupName = $aggGroupNameInputName.val(),\n\t\t\taggregateGroupDesc = $aggGroupNameInputDesc.val(),\n\t\t\taggregateGroupLanguage = $aggGroupNameInputLanguage.val(),\n\t\t\tapi = new mw.Api();\n\n\t\tvar successFunction = function () {\n\t\t\t// Replace the text by the new text without altering the other 2 span tags\n\t\t\t$displayGroup.children( '.tp-name' ).contents().filter( function () {\n\t\t\t\treturn this.nodeType === 3;\n\t\t\t} ).replaceWith( aggregateGroupName );\n\t\t\t$displayGroup.children( '.tp-desc' ).text( aggregateGroupDesc );\n\t\t\t$displayGroup.removeClass( 'hidden' );\n\t\t\t$editGroup.addClass( 'hidden' );\n\t\t};\n\n\t\tvar params = {\n\t\t\taction: 'aggregategroups',\n\t\t\tdo: 'update',\n\t\t\tgroupname: aggregateGroupName,\n\t\t\tgroupdescription: aggregateGroupDesc,\n\t\t\taggregategroup: aggregateGroupId,\n\t\t\tgroupsourcelanguagecode: aggregateGroupLanguage\n\t\t};\n\n\t\tapi.postWithToken( 'csrf', params )\n\t\t\t.done( successFunction )\n\t\t\t.fail( function ( code, data ) {\n\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\talert( data.error.info );\n\t\t\t} );\n\t}\n\n\tfunction cancelEditGroup( event ) {\n\t\tvar $parent = $( event.target ).closest( '.mw-tpa-group' );\n\n\t\t$parent.children( '.tp-display-group' ).removeClass( 'hidden' );\n\t\t$parent.children( '.tp-edit-group' ).addClass( 'hidden' );\n\t}\n\n\tfunction getToggleAllGroupsLink() {\n\t\tvar $toggleLink = $( '<a>' )\n\t\t\t.addClass( 'js-tp-toggle-all-groups' )\n\t\t\t.attr( 'href', '#' )\n\t\t\t.text( mw.msg( 'tpt-aggregategroup-expand-all-groups' ) );\n\n\t\tvar $toggleLinkParent = $( '<div>' )\n\t\t\t.append( '[', $toggleLink, ']' );\n\n\t\t$toggleLink.on( 'click', function ( event ) {\n\t\t\tvar $target = $( event.target );\n\t\t\tvar isExpanded = $target.hasClass( 'expanded' );\n\t\t\tvar $groupContainers = $( '.js-mw-tpa-group' );\n\n\t\t\tfor ( var i = 0; i < $groupContainers.length; i++ ) {\n\t\t\t\tvar $groupContainer = $groupContainers.eq( i );\n\t\t\t\tvar isContainerOpen = $groupContainer.hasClass( 'mw-tpa-group-open' );\n\t\t\t\tif ( isExpanded === isContainerOpen ) {\n\t\t\t\t\ttoggleGroupContainer( $groupContainer );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$target.toggleClass( 'expanded' )\n\t\t\t\t.text( mw.msg( isExpanded ?\n\t\t\t\t\t'tpt-aggregategroup-expand-all-groups' :\n\t\t\t\t\t'tpt-aggregategroup-collapse-all-groups'\n\t\t\t\t) );\n\n\t\t\tevent.preventDefault();\n\t\t} );\n\n\t\treturn $toggleLinkParent;\n\t}\n\n\tfunction toggleGroupContainer( $groupContainer ) {\n\t\tvar $toggleTrigger = $groupContainer.find( '.js-tp-toggle-groups' );\n\t\tvar isOpen = $groupContainer.hasClass( 'mw-tpa-group-open' );\n\t\tchangeGroupToggleIconState( $toggleTrigger, !isOpen );\n\t\t$groupContainer.toggleClass( 'mw-tpa-group-open' );\n\t}\n\n\tfunction changeGroupToggleIconState( $icon, isOpen ) {\n\t\tvar title = mw.msg( 'tpt-aggregategroup-expand-group' );\n\t\tvar ariaExpanded = 'false';\n\t\tif ( isOpen ) {\n\t\t\ttitle = mw.msg( 'tpt-aggregategroup-collapse-group' );\n\t\t\tariaExpanded = 'true';\n\t\t}\n\n\t\t$icon.attr( 'title', title )\n\t\t\t.attr( 'aria-expanded', ariaExpanded );\n\t}\n\n\t$( function () {\n\t\tvar api = new mw.Api(),\n\t\t\tlastSelectedGroup = null;\n\n\t\tfunction onEntityItemSelect( selectedItem ) {\n\t\t\t// Remove selections made in other entity selectors on the page\n\t\t\t$( '.tes-entity-selector' )\n\t\t\t\t.not( this.$element )\n\t\t\t\t.find( 'input[type=\"text\"]' )\n\t\t\t\t.val( '' );\n\t\t\tlastSelectedGroup = selectedItem;\n\t\t\t// Clear the request cache so that the entity selector requests for data again\n\t\t\t// This way the recently selected group can be removed from the menu items displayed\n\t\t\tthis.requestCache = {};\n\t\t}\n\n\t\tfunction associateSelectedGroup( event ) {\n\t\t\tif ( lastSelectedGroup ) {\n\t\t\t\tassociate( event, lastSelectedGroup.data );\n\t\t\t\tlastSelectedGroup = null;\n\t\t\t} else {\n\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\talert( mw.msg( 'tpt-invalid-group' ) );\n\t\t\t}\n\t\t}\n\n\t\tvar $subGroups = $( '.tp-sub-groups' ), $button;\n\t\t$subGroups.each( function () {\n\t\t\t$button = $( '<button>' )\n\t\t\t\t.addClass( 'tp-aggregate-add-button' )\n\t\t\t\t.text( mw.msg( 'tpt-aggregategroup-add' ) );\n\t\t\t$( this ).append( getEntitySelector( onEntityItemSelect, filterSelectedGroups ).$element, $button );\n\t\t} );\n\n\t\t$( '.tp-aggregate-add-button' ).on( 'click', associateSelectedGroup );\n\t\t$( '.tp-aggregate-remove-button' ).on( 'click', dissociate );\n\t\t$( '.tp-aggregate-remove-ag-button' ).on( 'click', removeGroup );\n\t\t$( '.tp-aggregategroup-update' ).on( 'click', editGroup );\n\t\t$( '.tp-aggregategroup-update-cancel' ).on( 'click', cancelEditGroup );\n\n\t\t$( 'a.tpt-add-new-group' ).on( 'click', function ( event ) {\n\t\t\t$( 'div.tpt-add-new-group' ).removeClass( 'hidden' );\n\t\t\t// Link has anchor which goes top of the page\n\t\t\tevent.preventDefault();\n\t\t} );\n\n\t\t$( '.tp-aggregate-edit-ag-button' ).on( 'click', function ( event ) {\n\t\t\tvar $parent = $( event.target ).closest( '.mw-tpa-group' );\n\n\t\t\t$parent.children( '.tp-display-group' ).addClass( 'hidden' );\n\t\t\t$parent.children( '.tp-edit-group' ).removeClass( 'hidden' );\n\t\t} );\n\n\t\t$( '#tpt-aggregategroups-save' ).on( 'click', function () {\n\t\t\tvar $aggGroupNameInputName = $( 'input.tp-aggregategroup-add-name' ),\n\t\t\t\t$aggGroupNameInputDesc = $( 'input.tp-aggregategroup-add-description' ),\n\t\t\t\t$aggGroupNameInputLanguage = $( 'select.tp-aggregategroup-add-source-language' ),\n\t\t\t\taggregateGroupName = $aggGroupNameInputName.val(),\n\t\t\t\taggregateGroupDesc = $aggGroupNameInputDesc.val(),\n\t\t\t\taggregateGroupLanguage = $aggGroupNameInputLanguage.val();\n\n\t\t\t// Empty the fields. If they are not emptied, then when another group\n\t\t\t// is added, the values will appear again.\n\t\t\t$aggGroupNameInputName.val( '' );\n\t\t\t$aggGroupNameInputDesc.val( '' );\n\t\t\t$aggGroupNameInputLanguage.val( 'und' );\n\n\t\t\tvar successFunction = function ( data ) {\n\t\t\t\tvar aggregateGroupId = data.aggregategroups.aggregategroupId;\n\t\t\t\tvar subGroupId = 'tp-subgroup-' + aggregateGroupId;\n\n\t\t\t\tvar $removeSpan = $( '<span>' ).attr( 'id', aggregateGroupId )\n\t\t\t\t\t.addClass( 'tp-aggregate-remove-ag-button' );\n\t\t\t\tvar $editSpan = $( '<span>' ).attr( 'id', aggregateGroupId )\n\t\t\t\t\t.addClass( 'tp-aggregate-edit-ag-button' );\n\t\t\t\tvar $toggleIcon = $( '<a>' ).addClass( 'js-tp-toggle-groups tp-toggle-group-icon' )\n\t\t\t\t\t.attr( 'aria-controls', subGroupId )\n\t\t\t\t\t.attr( 'role', 'button' );\n\n\t\t\t\tvar isOpen = true;\n\t\t\t\tchangeGroupToggleIconState( $toggleIcon, isOpen );\n\n\t\t\t\t// Prints the name and the two spans in a single row\n\t\t\t\tvar $displayHeader = $( '<h2>' ).addClass( 'tp-name' ).text( aggregateGroupName )\n\t\t\t\t\t.append( $editSpan, $removeSpan )\n\t\t\t\t\t.prepend( $toggleIcon );\n\n\t\t\t\tvar $divDisplay = $( '<div>' ).addClass( 'tp-display-group' )\n\t\t\t\t\t.append( $displayHeader )\n\t\t\t\t\t.append( $( '<p>' ).addClass( 'tp-desc' ).text( aggregateGroupDesc ) );\n\n\t\t\t\tvar $saveButton = $( '<input>' )\n\t\t\t\t\t.attr( {\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tclass: 'tp-aggregategroup-update'\n\t\t\t\t\t} )\n\t\t\t\t\t.val( mw.msg( 'tpt-aggregategroup-update' ) );\n\t\t\t\tvar $cancelButton = $( '<input>' )\n\t\t\t\t\t.attr( {\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tclass: 'tp-aggregategroup-update-cancel'\n\t\t\t\t\t} )\n\t\t\t\t\t.val( mw.msg( 'tpt-aggregategroup-update-cancel' ) );\n\t\t\t\tvar $sourceLanguages = $( '.tp-aggregategroup-add-source-language' ).clone();\n\t\t\t\tvar $divEdit = $( '<div>' )\n\t\t\t\t\t.addClass( 'tp-edit-group hidden' )\n\t\t\t\t\t.append( $( '<label>' )\n\t\t\t\t\t\t.text( mw.msg( 'tpt-aggregategroup-edit-name' ) ) )\n\t\t\t\t\t.append( $( '<input>' )\n\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\tclass: 'tp-aggregategroup-edit-name',\n\t\t\t\t\t\t\tid: 'tp-agg-name'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.val( aggregateGroupName )\n\t\t\t\t\t)\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<br>' ),\n\t\t\t\t\t\t$( '<label>' )\n\t\t\t\t\t\t\t.text( mw.msg( 'tpt-aggregategroup-edit-description' ) )\n\t\t\t\t\t)\n\t\t\t\t\t.append( $( '<input>' )\n\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\tclass: 'tp-aggregategroup-edit-description',\n\t\t\t\t\t\t\tid: 'tp-agg-desc'\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.val( aggregateGroupDesc )\n\t\t\t\t\t)\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<br>' ),\n\t\t\t\t\t\t$( '<label>' )\n\t\t\t\t\t\t\t.text( mw.msg( 'tpt-aggregategroup-select-source-language' ) )\n\t\t\t\t\t)\n\t\t\t\t\t.append( $sourceLanguages\n\t\t\t\t\t\t.removeClass( 'tp-aggregategroup-add-source-language' )\n\t\t\t\t\t\t.addClass( 'tp-aggregategroup-edit-source-language' )\n\t\t\t\t\t\t.val( aggregateGroupLanguage )\n\t\t\t\t\t)\n\t\t\t\t\t.append( $( '<br>' ) )\n\t\t\t\t\t.append( $saveButton, $cancelButton );\n\n\t\t\t\tvar $div = $( '<div>' )\n\t\t\t\t\t.addClass( 'mw-tpa-group js-mw-tpa-group mw-tpa-group-open' )\n\t\t\t\t\t.append( $divDisplay, $divEdit )\n\t\t\t\t\t.data( { groupid: aggregateGroupId, id: aggregateGroupId } );\n\n\t\t\t\tvar $subGroupContents = $( '<div>' ).addClass( 'tp-sub-groups' )\n\t\t\t\t\t.attr( 'id', subGroupId )\n\t\t\t\t\t.append( $( '<ol id=\\'mw-tpa-grouplist-' + aggregateGroupId + '\\'>' ) );\n\n\t\t\t\tvar $addButton = $( '<input>' )\n\t\t\t\t\t.attr( {\n\t\t\t\t\t\ttype: 'button',\n\t\t\t\t\t\tclass: 'tp-aggregate-add-button',\n\t\t\t\t\t\tid: aggregateGroupId\n\t\t\t\t\t} )\n\t\t\t\t\t.val( mw.msg( 'tpt-aggregategroup-add' ) );\n\n\t\t\t\t$addButton.on( 'click', associateSelectedGroup );\n\n\t\t\t\tvar entitySelector = getEntitySelector( onEntityItemSelect, filterSelectedGroups );\n\t\t\t\t$subGroupContents.append( entitySelector.$element, $addButton );\n\t\t\t\t$div.append( $subGroupContents );\n\n\t\t\t\t$editSpan.on( 'click', function ( event ) {\n\t\t\t\t\tvar $parent = $( event.target ).closest( '.mw-tpa-group' );\n\t\t\t\t\t$parent.children( '.tp-display-group' ).addClass( 'hidden' );\n\t\t\t\t\t$parent.children( '.tp-edit-group' ).removeClass( 'hidden' );\n\t\t\t\t} );\n\n\t\t\t\t$saveButton.on( 'click', editGroup );\n\t\t\t\t$cancelButton.on( 'click', cancelEditGroup );\n\t\t\t\t$removeSpan.on( 'click', removeGroup );\n\t\t\t\t$( 'div.tpt-add-new-group' ).addClass( 'hidden' );\n\t\t\t\t$( 'div.mw-tpa-groups' ).prepend( $div );\n\t\t\t};\n\n\t\t\tvar params = {\n\t\t\t\taction: 'aggregategroups',\n\t\t\t\tdo: 'add',\n\t\t\t\tgroupname: aggregateGroupName,\n\t\t\t\tgroupdescription: aggregateGroupDesc,\n\t\t\t\tgroupsourcelanguagecode: aggregateGroupLanguage\n\t\t\t};\n\n\t\t\tapi.postWithToken( 'csrf', params )\n\t\t\t\t.done( successFunction )\n\t\t\t\t.fail( function ( code, data ) {\n\t\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\t\talert( data.error && data.error.info );\n\t\t\t\t} );\n\t\t} );\n\n\t\t$( '#tpt-aggregategroups-close' ).on( 'click', function ( event ) {\n\t\t\t$( 'div.tpt-add-new-group' ).addClass( 'hidden' );\n\t\t\tevent.preventDefault();\n\t\t} );\n\n\t\t$( '#mw-content-text' ).on( 'click', '.js-tp-toggle-groups', function ( event ) {\n\t\t\tvar $target = $( event.target );\n\t\t\tvar $groupContainer = $target.parents( '.js-mw-tpa-group' );\n\t\t\ttoggleGroupContainer( $groupContainer );\n\t\t} );\n\n\t\t$( 'div.mw-tpa-group' ).first().before( getToggleAllGroupsLink() );\n\t} );\n\n\tvar entitySelectorLimit = 50;\n\tfunction getEntitySelector( onSelect, filterResults ) {\n\t\tvar EntitySelector = require( 'ext.translate.entity.selector' );\n\t\treturn new EntitySelector( {\n\t\t\tonSelect: onSelect,\n\t\t\tentityType: [ 'groups' ],\n\t\t\tgroupTypes: [ 'translatable-pages', 'message-bundles' ],\n\t\t\tlimit: entitySelectorLimit,\n\t\t\tallowSuggestionsWhenEmpty: true,\n\t\t\tfilterResults: filterResults\n\t\t} );\n\t}\n\n\tfunction filterSelectedGroups( apiResult ) {\n\t\tvar filteredGroups = [];\n\t\tvar alreadySelectedGroups = getSelectedGroups( this.$element );\n\t\tfor ( var i = 0; i < apiResult.groups.length; ++i ) {\n\t\t\tvar currentGroup = apiResult.groups[ i ];\n\t\t\tif ( alreadySelectedGroups[ currentGroup.label ] !== true ) {\n\t\t\t\tfilteredGroups.push( currentGroup );\n\t\t\t}\n\n\t\t\tif ( filteredGroups.length === entitySelectorLimit ) {\n\t\t\t\treturn { groups: filteredGroups };\n\t\t\t}\n\t\t}\n\n\t\treturn { groups: filteredGroups };\n\t}\n\n\tfunction getSelectedGroups( $entitySelector ) {\n\t\tvar exclude = {};\n\t\t$entitySelector.closest( '.mw-tpa-group' ).find( 'li' ).each(\n\t\t\tfunction ( _key, data ) {\n\t\t\t\t// Need to trim to remove the trailing whitespace\n\t\t\t\t// Can't use innerText not supported by Firefox\n\t\t\t\texclude[ $( data ).text().trim() ] = true;\n\t\t\t}\n\t\t);\n\n\t\treturn exclude;\n\t}\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.importtranslations.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.managegroups.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":18,"column":11,"nodeType":"CallExpression","endLine":22,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":18,"column":11,"nodeType":"CallExpression","endLine":29,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":68,"column":4,"nodeType":"CallExpression","endLine":77,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":68,"column":4,"nodeType":"CallExpression","endLine":84,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":98,"column":4,"nodeType":"CallExpression","endLine":103,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":98,"column":4,"nodeType":"CallExpression","endLine":110,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":368,"column":4,"nodeType":"CallExpression","endLine":378,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":368,"column":4,"nodeType":"CallExpression","endLine":380,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":391,"column":4,"nodeType":"CallExpression","endLine":396,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":391,"column":4,"nodeType":"CallExpression","endLine":398,"endColumn":7}],"suppressedMessages":[],"errorCount":10,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\tvar RenameDropdown,\n\t\tGroupSynchronization;\n\n\t$( function () {\n\t\tRenameDropdown.init();\n\t\tGroupSynchronization.init();\n\n\t\t// Create and append a window manager.\n\t\tvar windowManager = new OO.ui.WindowManager();\n\t\twindowManager.$element.appendTo( document.body );\n\n\t\t// Create a new process dialog window.\n\t\tvar renameDialog = new mw.translate.MessageRenameDialog( {\n\t\t\tclasses: [ 'smg-rename-dialog' ],\n\t\t\tsize: 'large'\n\t\t}, function ( renameParams ) {\n\t\t\treturn setRename( renameParams ).done( function ( data ) {\n\t\t\t\tif ( data.managemessagegroups && data.managemessagegroups.success ) {\n\t\t\t\t\tlocation.reload();\n\t\t\t\t}\n\t\t\t} ).fail( function ( code, result ) {\n\t\t\t\tif ( result.error ) {\n\t\t\t\t\tmw.notify( result.error.info, {\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\ttag: 'new-error'\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\t// Add the window to window manager using the addWindows() method.\n\t\twindowManager.addWindows( [ renameDialog ] );\n\n\t\t/**\n\t\t * Attach the click handler to display the rename dropdown.\n\t\t */\n\t\t$( '#mw-content-text' ).on( 'click', '.smg-rename-actions', function ( event ) {\n\t\t\tvar $target = $( event.target );\n\t\t\tvar $parentContainer = $target.parents( '.mw-translate-smg-change' );\n\t\t\tRenameDropdown.appendTo( event.target, $parentContainer, {\n\t\t\t\tgroupId: $target.data( 'groupId' ),\n\t\t\t\tmsgKey: $target.data( 'msgkey' ),\n\t\t\t\tmsgTitle: $target.data( 'msgtitle' )\n\t\t\t} ).show();\n\n\t\t\tif ( $parentContainer.hasClass( 'smg-change-addition' ) ) {\n\t\t\t\t// For a new message, the \"add as new\" option is hidden.\n\t\t\t\tRenameDropdown.hideOption( '.smg-rename-new-action' );\n\t\t\t}\n\t\t\tevent.preventDefault();\n\t\t} );\n\n\t\t$( document.documentElement ).on( 'click', function ( event ) {\n\t\t\tif ( !event.isDefaultPrevented() ) {\n\t\t\t\tRenameDropdown.hide();\n\t\t\t}\n\t\t} );\n\n\t\t/**\n\t\t * Click handler triggered when \"Add as rename\" is clicked in the dropdown.\n\t\t */\n\t\t$( '.smg-rename-rename-action' ).on( 'click', function () {\n\t\t\tvar keyData = RenameDropdown.getData(),\n\t\t\t\t$renameButton = getRenameButton( $( event.target ) );\n\t\t\ttoggleLoading( $renameButton, true );\n\n\t\t\tgetRenames( keyData.groupId, keyData.msgKey )\n\t\t\t\t.done( function ( data ) {\n\t\t\t\t// Open the dialog, and display possible renames.\n\t\t\t\t\twindowManager.openWindow( renameDialog, {\n\t\t\t\t\t\tmessages: data.managemessagegroups[ 0 ],\n\t\t\t\t\t\ttitle: mw.msg( 'translate-smg-rename-dialog-title', keyData.msgTitle ),\n\t\t\t\t\t\tgroupId: keyData.groupId,\n\t\t\t\t\t\ttargetKey: keyData.msgKey\n\t\t\t\t\t} );\n\t\t\t\t} ).fail( function ( code, result ) {\n\t\t\t\t\tif ( result.error ) {\n\t\t\t\t\t\tmw.notify( result.error.info, {\n\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\ttag: 'rename-error'\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t} ).always( function () {\n\t\t\t\t\ttoggleLoading( $renameButton, false );\n\t\t\t\t} );\n\t\t} );\n\n\t\t/**\n\t\t * Click handler triggered when \"Add as new\" is clicked in the dropdown.\n\t\t */\n\t\t$( '.smg-rename-new-action' ).on( 'click', function () {\n\t\t\tvar keyData = RenameDropdown.getData(),\n\t\t\t\t$renameButton = getRenameButton( $( event.target ) ),\n\t\t\t\tisReloading = false;\n\t\t\ttoggleLoading( $renameButton, true );\n\n\t\t\tsetAsNew( keyData.groupId, keyData.msgKey ).done( function ( data ) {\n\t\t\t\tif ( data.managemessagegroups && data.managemessagegroups.success ) {\n\t\t\t\t\tlocation.reload();\n\t\t\t\t\tisReloading = true;\n\t\t\t\t}\n\t\t\t} ).fail( function ( code, result ) {\n\t\t\t\tif ( result.error ) {\n\t\t\t\t\tmw.notify( result.error.info, {\n\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\ttag: 'new-error'\n\t\t\t\t\t} );\n\t\t\t\t}\n\t\t\t} ).always( function () {\n\t\t\t\t// If page is reloading, don't bother hiding the loader.\n\t\t\t\tif ( isReloading === false ) {\n\t\t\t\t\ttoggleLoading( $renameButton, false );\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t} );\n\n\tfunction getRenameButton( $target ) {\n\t\treturn $target.parents( '.mw-translate-smg-change' ).find( '.smg-rename-actions' );\n\t}\n\n\tfunction toggleLoading( $element, isLoading ) {\n\t\tif ( isLoading ) {\n\t\t\t// hide all the rename buttons, but show the current one with loading animation\n\t\t\t$( '.smg-rename-actions' ).addClass( 'mw-translate-hide' );\n\t\t\t$element.removeClass( 'mw-translate-hide' ).addClass( 'tux-loading-indicator' );\n\t\t} else {\n\t\t\t$( '.smg-rename-actions' ).removeClass( 'mw-translate-hide' );\n\t\t\t$element.removeClass( 'tux-loading-indicator' );\n\t\t}\n\t}\n\n\t/**\n\t * Fetch the possible renames for a given message.\n\t *\n\t * @param {string} groupId\n\t * @param {string} msgKey\n\t * @return {jQuery.Promise}\n\t */\n\tfunction getRenames( groupId, msgKey ) {\n\t\tvar api = new mw.Api();\n\t\tvar params = {\n\t\t\taction: 'query',\n\t\t\tmeta: 'managemessagegroups',\n\t\t\tformatversion: 2,\n\t\t\tmmgchangesetName: getChangesetName(),\n\t\t\tmmggroupId: groupId,\n\t\t\tmmgmessageKey: msgKey\n\t\t};\n\n\t\treturn api.get( params ).then( function ( result ) {\n\t\t\treturn result.query;\n\t\t} );\n\t}\n\n\t/**\n\t * Get our form.\n\t *\n\t * @return {HTMLFormElement}\n\t */\n\tfunction getForm() {\n\t\treturn document.getElementById( 'smgForm' );\n\t}\n\n\t/**\n\t * Get the group name. It always returns a value; that value may be\n\t * `default` if nothing else was specified as special page subpage.\n\t *\n\t * @return {string}\n\t */\n\tfunction getChangesetName() {\n\t\treturn getForm().dataset.name;\n\t}\n\n\tfunction getChangesetModifiedTime() {\n\t\tvar modifiedTime = getForm().elements.namedItem( 'changesetModifiedTime' ).value;\n\t\tmodifiedTime = +modifiedTime;\n\t\tif ( isNaN( modifiedTime ) ) {\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn modifiedTime;\n\t}\n\n\t/**\n\t * Update the rename associated with a message\n\t *\n\t * @param {Object} renameParams\n\t * @param {string} renameParams.groupId\n\t * @param {string} renameParams.selectedKey Key to be matched to. This message will be renamed.\n\t * @param {string} renameParams.targetKey Key from the source\n\t * @return {jQuery.Promise}\n\t */\n\tfunction setRename( renameParams ) {\n\t\tvar api = new mw.Api();\n\n\t\tvar params = {\n\t\t\taction: 'managemessagegroups',\n\t\t\tgroupId: renameParams.groupId,\n\t\t\trenameMessageKey: renameParams.selectedKey,\n\t\t\tmessageKey: renameParams.targetKey,\n\t\t\toperation: 'rename',\n\t\t\tchangesetName: getChangesetName(),\n\t\t\tchangesetModified: getChangesetModifiedTime(),\n\t\t\tassert: 'user',\n\t\t\tformatversion: 2\n\t\t};\n\n\t\treturn api.postWithToken( 'csrf', params );\n\t}\n\n\t/**\n\t * Mark the message as a new message\n\t *\n\t * @param {string} groupId\n\t * @param {string} msgKey\n\t * @return {jQuery.Promise}\n\t */\n\tfunction setAsNew( groupId, msgKey ) {\n\t\tvar api = new mw.Api();\n\n\t\tvar params = {\n\t\t\taction: 'managemessagegroups',\n\t\t\tgroupId: groupId,\n\t\t\tmessageKey: msgKey,\n\t\t\toperation: 'new',\n\t\t\tchangesetName: getChangesetName(),\n\t\t\tchangesetModified: getChangesetModifiedTime(),\n\t\t\tassert: 'user',\n\t\t\tformatversion: 2\n\t\t};\n\n\t\treturn api.postWithToken( 'csrf', params );\n\t}\n\n\t/**\n\t * @class RenameDropdown\n\t */\n\tRenameDropdown = ( function () {\n\t\tvar $renameMenu;\n\n\t\t/**\n\t\t * Initialization function. Creates the elements for the rename dropdown\n\t\t *\n\t\t * @return {RenameDropdown}\n\t\t * @chainable\n\t\t */\n\t\tfunction init() {\n\t\t\t$renameMenu = getRenameDropdown().appendTo( document.body );\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Returns the HTML element for the dropdown\n\t\t *\n\t\t * @return {jQuery}\n\t\t */\n\t\tfunction getRenameDropdown() {\n\t\t\tvar $addAsRename = $( '<li>' ).append(\n\t\t\t\t\t$( '<button>' )\n\t\t\t\t\t\t.attr( 'type', 'button' )\n\t\t\t\t\t\t.addClass( 'smg-rename-new-action mw-translate-hide' )\n\t\t\t\t\t\t.text( mw.msg( 'translate-smg-rename-new' ) )\n\t\t\t\t),\n\t\t\t\t$addAsNew = $( '<li>' ).append(\n\t\t\t\t\t$( '<button>' )\n\t\t\t\t\t\t.attr( 'type', 'button' )\n\t\t\t\t\t\t.addClass( 'smg-rename-rename-action mw-translate-hide' )\n\t\t\t\t\t\t.text( mw.msg( 'translate-smg-rename-rename' ) )\n\t\t\t\t);\n\n\t\t\treturn $( '<ul>' ).addClass( 'smg-rename-dropdown-menu' ).append(\n\t\t\t\t$addAsRename,\n\t\t\t\t$addAsNew\n\t\t\t);\n\t\t}\n\n\t\t/**\n\t\t * Displays the rename menu\n\t\t *\n\t\t * @return {RenameDropdown}\n\t\t * @chainable\n\t\t */\n\t\tfunction show() {\n\t\t\t$renameMenu.addClass( 'show' );\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Hides the rename menu\n\t\t *\n\t\t * @return {RenameDropdown}\n\t\t * @chainable\n\t\t */\n\t\tfunction hide() {\n\t\t\t$renameMenu.removeClass( 'show' );\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Appends the dropdown to a container element\n\t\t *\n\t\t * @param {jQuery} target Target trigger element\n\t\t * @param {jQuery} $container Container to which to append the menu\n\t\t * @param {Object} customData Custom data to be associated with the menu\n\t\t * @return {RenameDropdown}\n\t\t * @chainable\n\t\t */\n\t\tfunction appendTo( target, $container, customData ) {\n\t\t\tvar $currentTarget = $( target );\n\t\t\t$container.append( $renameMenu );\n\t\t\t$renameMenu.css( {\n\t\t\t\ttop: $currentTarget.position().top + $currentTarget.height(),\n\t\t\t\tleft: $currentTarget.position().left - $renameMenu.width() + $currentTarget.width()\n\t\t\t} ).data( 'custom-data', customData );\n\n\t\t\t// When appending, show all the li's by default since based on the\n\t\t\t// message type (RENAME / NEW) some li's may be hidden previously\n\t\t\t$renameMenu.find( 'li' ).removeClass( 'mw-translate-hide' );\n\t\t\treturn this;\n\t\t}\n\n\t\t/**\n\t\t * Fetch the custom data associated with rename menu\n\t\t *\n\t\t * @return {Object}\n\t\t */\n\t\tfunction getData() {\n\t\t\treturn $renameMenu.data( 'custom-data' );\n\t\t}\n\n\t\t/**\n\t\t * Hide a specific option in the dropdown\n\t\t *\n\t\t * @param {string} optSelector\n\t\t * @return {RenameDropdown}\n\t\t * @chainable\n\t\t */\n\t\tfunction hideOption( optSelector ) {\n\t\t\t$renameMenu.find( optSelector ).parent().addClass( 'mw-translate-hide' );\n\t\t\treturn this;\n\t\t}\n\n\t\treturn {\n\t\t\tinit: init,\n\t\t\tappendTo: appendTo,\n\t\t\tshow: show,\n\t\t\thide: hide,\n\t\t\tgetData: getData,\n\t\t\thideOption: hideOption\n\t\t};\n\t}() );\n\n\tGroupSynchronization = ( function () {\n\t\tfunction init() {\n\t\t\t$( '.js-group-sync-message-resolve' ).on( 'click', markMessageAsResolved );\n\t\t\t$( '.js-group-sync-group-resolve' ).on( 'click', markGroupAsResolved );\n\t\t}\n\n\t\tfunction markMessageAsResolved() {\n\t\t\tvar $target = $( this ),\n\t\t\t\tgroupId = $target.data( 'groupId' ),\n\t\t\t\tmessageTitle = $target.data( 'msgTitle' );\n\n\t\t\tshowLoading( $target );\n\n\t\t\tmarkAsResolved( 'resolveMessage', groupId, messageTitle ).done( function ( response ) {\n\t\t\t\tvar responseData = response.managegroupsynchronizationcache || null;\n\t\t\t\tif ( responseData && responseData.success ) {\n\t\t\t\t\tif ( responseData.data.groupRemainingMessageCount === 0 ) {\n\t\t\t\t\t\tremoveParentGroupBlock( $target );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Remove the message from the DOM\n\t\t\t\t\t\t$target.parents( '.js-group-sync-message-error' ).remove();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} ).fail( function ( code, result ) {\n\t\t\t\thandleResolutionFailure( code, result, groupId, messageTitle );\n\t\t\t} ).always( function () {\n\t\t\t\thideLoading( $target );\n\t\t\t} );\n\t\t}\n\n\t\tfunction markGroupAsResolved() {\n\t\t\tvar $target = $( this ),\n\t\t\t\tgroupId = $target.data( 'groupId' );\n\n\t\t\tshowLoading( $target );\n\n\t\t\tmarkAsResolved( 'resolveGroup', groupId ).done( function ( response ) {\n\t\t\t\tvar responseData = response.managegroupsynchronizationcache || null;\n\t\t\t\tif ( responseData && responseData.success ) {\n\t\t\t\t\tremoveParentGroupBlock( $target );\n\t\t\t\t}\n\t\t\t} ).fail( function ( code, result ) {\n\t\t\t\thandleResolutionFailure( code, result, groupId );\n\t\t\t} ).always( function () {\n\t\t\t\thideLoading( $target );\n\t\t\t} );\n\t\t}\n\n\t\tfunction markAsResolved( operation, groupId, messageTitle ) {\n\t\t\tvar api = new mw.Api();\n\n\t\t\tvar params = {\n\t\t\t\taction: 'managegroupsynchronizationcache',\n\t\t\t\tgroup: groupId,\n\t\t\t\toperation: operation,\n\t\t\t\tassert: 'user',\n\t\t\t\tformatversion: 2\n\t\t\t};\n\n\t\t\tif ( messageTitle ) {\n\t\t\t\tparams.title = messageTitle;\n\t\t\t}\n\n\t\t\treturn api.postWithToken( 'csrf', params );\n\t\t}\n\n\t\tfunction removeParentGroupBlock( $child ) {\n\t\t\t// Remove the entire group block from DOM\n\t\t\t$child.parents( '.js-group-sync-group-errors' ).remove();\n\t\t\t// If all groups are resolved, remove the group sync error block\n\t\t\tif ( !$( '.js-group-sync-group-errors' ).length ) {\n\t\t\t\t$( '.js-group-sync-groups-with-error' ).remove();\n\t\t\t}\n\t\t}\n\n\t\tfunction handleResolutionFailure( code, result, groupId, messageTitle ) {\n\t\t\tvar errorInfo = result && result.error ? result.error.info : null;\n\t\t\tif ( errorInfo ) {\n\t\t\t\tmw.notify( result.error.info, {\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttag: 'new-error'\n\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t// Unknown error\n\t\t\t\tmw.notify( mw.msg( 'translate-smg-unknown-error' ), {\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttag: 'new-error'\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tmw.log.error( 'Error while resolving group or message. Param: ' + JSON.stringify( {\n\t\t\t\tgroupId: groupId,\n\t\t\t\tmessageTitle: messageTitle,\n\t\t\t\terrorCode: code,\n\t\t\t\terrorInfo: errorInfo\n\t\t\t} ) );\n\t\t}\n\n\t\tfunction showLoading( $target ) {\n\t\t\t$target.addClass( 'loading' )\n\t\t\t\t.text( mw.msg( 'translate-smg-loading' ) )\n\t\t\t\t.removeAttr( 'href' );\n\t\t}\n\n\t\tfunction hideLoading( $target ) {\n\t\t\t$target.removeClass( 'loading' )\n\t\t\t\t.text( mw.msg( 'translate-smg-group-action-resolve' ) )\n\t\t\t\t.prop( 'href', '#' );\n\t\t}\n\n\t\treturn {\n\t\t\tinit: init\n\t\t};\n\t}() );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.managetranslatorsandbox.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":100,"column":8,"nodeType":"CallExpression","endLine":107,"endColumn":11},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":100,"column":8,"nodeType":"CallExpression","endLine":109,"endColumn":11},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":128,"column":8,"nodeType":"CallExpression","endLine":135,"endColumn":11},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":145,"column":8,"nodeType":"CallExpression","endLine":152,"endColumn":11},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":185,"column":3,"nodeType":"CallExpression","endLine":185,"endColumn":67},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":305,"column":8,"nodeType":"CallExpression","endLine":312,"endColumn":11},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":322,"column":8,"nodeType":"CallExpression","endLine":329,"endColumn":11}],"suppressedMessages":[],"errorCount":7,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * JS for special page.\n * @author Niklas Laxström\n * @author Sucheta Ghoshal\n * @author Amir E. Aharoni\n * @author Pau Giner\n * @license GPL-2.0-or-later\n */\n\n( function () {\n\t'use strict';\n\n\tvar delay;\n\n\t/**\n\t * A callback for sorting translations.\n\t *\n\t * @param {Object} translationA Object loaded from translation stash\n\t * @param {Object} translationB Object loaded from translation stash\n\t * @return {number} String comparison of language codes\n\t */\n\tfunction sortTranslationsByLanguage( translationA, translationB ) {\n\t\tvar a = translationA.title.split( '/' ).pop(),\n\t\t\tb = translationB.title.split( '/' ).pop();\n\n\t\treturn a.localeCompare( b );\n\t}\n\n\tfunction doApiAction( options ) {\n\t\tvar api = new mw.Api(),\n\t\t\toptionsWithDefaults = Object.assign( {}, { action: 'translatesandbox' }, options );\n\n\t\treturn api.postWithToken( 'csrf', optionsWithDefaults ).promise();\n\t}\n\n\tfunction removeSelectedRequests() {\n\t\tvar $selectedRequests = $( '.request-selector:checked' );\n\n\t\tvar $nextRequest = $selectedRequests\n\t\t\t.first() // First selected request\n\t\t\t.closest( '.request' ) // The request corresponds that checkbox\n\t\t\t.prevAll( ':not(.hide)' ) // Go back till a non-hidden request\n\t\t\t.first(); // The above selector gives list from bottom to top. Select the bottom one.\n\n\t\t$selectedRequests.closest( '.request' ).remove();\n\n\t\tupdateRequestCount();\n\n\t\tif ( !$nextRequest.length ) {\n\t\t\t// If there's no request above the first checked request,\n\t\t\t// try to get the first request in the column\n\t\t\t$nextRequest = $( '.requests .request:not(.hide)' ).first();\n\t\t}\n\n\t\tif ( $nextRequest.length ) {\n\t\t\t$nextRequest.trigger( 'click' );\n\t\t\tupdateSelectedIndicator( 1 );\n\t\t} else {\n\t\t\tupdateSelectedIndicator( 0 );\n\t\t}\n\t}\n\n\t/**\n\t * Display the request details when user clicks on a request item\n\t *\n\t * @param {Object} request The request data set from backend on request items\n\t */\n\tfunction displayRequestDetails( request ) {\n\t\tvar $reminderStatus = $( '<span>' ).addClass( 'reminder-status' ),\n\t\t\t$detailsPane = $( '.details.pane' );\n\t\tif ( request.reminderscount ) {\n\t\t\tvar agoText = moment.isMoment( request.lastreminder ) ? moment( request.lastreminder ).fromNow() : request.lastreminder;\n\t\t\t$reminderStatus.text( mw.msg(\n\t\t\t\t'tsb-reminder-sent',\n\t\t\t\trequest.reminderscount,\n\t\t\t\tagoText\n\t\t\t) );\n\t\t}\n\n\t\t$detailsPane.empty().append(\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'tsb-header row' )\n\t\t\t\t.text( request.username ),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'reminder-email row' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.attr( { dir: 'ltr' } )\n\t\t\t\t\t\t.text( request.email ),\n\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t.prop( 'href', '#' )\n\t\t\t\t\t\t.addClass( 'send-reminder link' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-reminder-link-text' ) )\n\t\t\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t\t\te.preventDefault();\n\n\t\t\t\t\t\t\t$reminderStatus\n\t\t\t\t\t\t\t\t.text( mw.msg( 'tsb-reminder-sending' ) );\n\n\t\t\t\t\t\t\tdoApiAction( {\n\t\t\t\t\t\t\t\tdo: 'remind',\n\t\t\t\t\t\t\t\tuserid: request.userid\n\t\t\t\t\t\t\t} ).done( function () {\n\t\t\t\t\t\t\t\trequest.lastreminder = moment();\n\t\t\t\t\t\t\t\trequest.reminderscount++;\n\t\t\t\t\t\t\t\t$reminderStatus.text( mw.msg( 'tsb-reminder-sent-new' ) );\n\t\t\t\t\t\t\t} ).fail( function () {\n\t\t\t\t\t\t\t\t$reminderStatus.text( mw.msg( 'tsb-reminder-failed' ) );\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} ),\n\t\t\t\t\t$reminderStatus\n\t\t\t\t),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'languages row autonym' ),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'signup-comment row' ),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'actions row' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<button>' )\n\t\t\t\t\t\t.addClass( 'accept mw-ui-button mw-ui-progressive' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-accept-button-label' ) )\n\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\tmw.notify( mw.msg( 'tsb-accept-confirmation', 1 ) );\n\n\t\t\t\t\t\t\twindow.tsbUpdatingUsers = true;\n\n\t\t\t\t\t\t\tdoApiAction( {\n\t\t\t\t\t\t\t\tuserid: request.userid,\n\t\t\t\t\t\t\t\tdo: 'promote'\n\t\t\t\t\t\t\t} ).done( function () {\n\t\t\t\t\t\t\t\tremoveSelectedRequests();\n\n\t\t\t\t\t\t\t\twindow.tsbUpdatingUsers = false;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} ),\n\t\t\t\t\t$( '<button>' )\n\t\t\t\t\t\t.addClass( 'reject mw-ui-button mw-ui-destructive' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-reject-button-label' ) )\n\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\tmw.notify( mw.msg( 'tsb-reject-confirmation', 1 ) );\n\n\t\t\t\t\t\t\twindow.tsbUpdatingUsers = true;\n\n\t\t\t\t\t\t\tdoApiAction( {\n\t\t\t\t\t\t\t\tuserid: request.userid,\n\t\t\t\t\t\t\t\tdo: 'delete'\n\t\t\t\t\t\t\t} ).done( function () {\n\t\t\t\t\t\t\t\tremoveSelectedRequests();\n\n\t\t\t\t\t\t\t\twindow.tsbUpdatingUsers = false;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'translations' )\n\t\t);\n\n\t\tif ( request.languagepreferences ) {\n\t\t\tif ( request.languagepreferences.languages ) {\n\t\t\t\trequest.languagepreferences.languages.forEach( function ( language ) {\n\t\t\t\t\t$detailsPane.find( '.languages' ).append(\n\t\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t\t.prop( {\n\t\t\t\t\t\t\t\tdir: $.uls.data.getDir( language ),\n\t\t\t\t\t\t\t\tlang: language\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.text( $.uls.data.getAutonym( language ) )\n\t\t\t\t\t);\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tif ( request.languagepreferences.comment ) {\n\t\t\t\t$detailsPane.find( '.signup-comment' ).append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'signup-comment-label' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-user-posted-a-comment' ) ),\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'signup-comment-text' )\n\t\t\t\t\t\t.text( request.languagepreferences.comment )\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tgetUserTranslations( request.username ).done( showTranslations );\n\t}\n\n\t/**\n\t * Get the current users translations.\n\t *\n\t * @param {string} user User name\n\t * @return {jQuery.Promise}\n\t */\n\tfunction getUserTranslations( user ) {\n\t\tvar api = new mw.Api();\n\n\t\treturn api.postWithToken( 'csrf', {\n\t\t\taction: 'translationstash',\n\t\t\tsubaction: 'query',\n\t\t\tusername: user\n\t\t} );\n\t}\n\n\tfunction showTranslations( translations ) {\n\t\tvar $target = $( '.translations' );\n\n\t\t$target.empty();\n\n\t\t// Display a message if the user didn't make any translations\n\t\tif ( !translations.translationstash.translations.length ) {\n\t\t\t$target.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'tsb-details-no-translations' )\n\t\t\t\t\t.text( mw.msg( 'tsb-didnt-make-any-translations' ) )\n\t\t\t);\n\n\t\t\treturn;\n\t\t}\n\n\t\tvar gender = $( '.requests-list .request.selected' ).data( 'data' ).gender;\n\t\t$target.append(\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'row title' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-translations-source' ) )\n\t\t\t\t\t\t.addClass( 'four columns' ),\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-translations-user', gender ) )\n\t\t\t\t\t\t.addClass( 'four columns' ),\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-translations-current' ) )\n\t\t\t\t\t\t.addClass( 'four columns' )\n\t\t\t\t)\n\t\t);\n\n\t\ttranslations.translationstash.translations.sort( sortTranslationsByLanguage );\n\t\ttranslations.translationstash.translations.forEach( function ( translation ) {\n\t\t\tshowTranslation( translation );\n\t\t} );\n\t}\n\n\tfunction showTranslation( translation ) {\n\t\tvar $target = $( '.translations' ),\n\t\t\ttranslationLang = translation.title.split( '/' ).pop();\n\n\t\t$target.append( $( '<div>' )\n\t\t\t.addClass( 'row' )\n\t\t\t.append(\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'four columns source' )\n\t\t\t\t\t.text( translation.definition ),\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'four columns translation' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' ).text( translation.translation )\n\t\t\t\t\t\t\t.prop( {\n\t\t\t\t\t\t\t\tdir: $.uls.data.getDir( translationLang ),\n\t\t\t\t\t\t\t\tlang: translationLang\n\t\t\t\t\t\t\t} ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'info autonym' )\n\t\t\t\t\t\t\t.prop( {\n\t\t\t\t\t\t\t\tdir: $.uls.data.getDir( translationLang ),\n\t\t\t\t\t\t\t\tlang: translationLang\n\t\t\t\t\t\t\t} )\n\t\t\t\t\t\t\t.text(\n\t\t\t\t\t\t\t\t$.uls.data.getAutonym( translationLang )\n\t\t\t\t\t\t\t)\n\t\t\t\t\t),\n\t\t\t\t$( '<div>' )\n\t\t\t\t\t.addClass( 'four columns comparison' )\n\t\t\t\t\t.append(\n\t\t\t\t\t\t$( '<div>' ).text( translation.comparison || '' ),\n\t\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t\t.addClass( 'info' )\n\t\t\t\t\t\t\t.text( translation.title )\n\t\t\t\t\t)\n\t\t\t)\n\t\t);\n\t}\n\n\t/**\n\t * Display when multiple requests are checked.\n\t */\n\tfunction displayOnMultipleSelection() {\n\t\tvar selectedUserIDs = $( '.request-selector:checked' ).map( function ( i, checkedBox ) {\n\t\t\treturn $( checkedBox ).parents( 'div.request' ).data( 'data' ).userid;\n\t\t} ).toArray();\n\n\t\t$( '.details.pane' ).empty().append(\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'tsb-header row' ),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'actions row' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<button>' )\n\t\t\t\t\t\t.addClass( 'accept-all mw-ui-button mw-ui-progressive' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-accept-all-button-label' ) )\n\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\tmw.notify( mw.msg( 'tsb-accept-confirmation', selectedUserIDs.length ) );\n\n\t\t\t\t\t\t\twindow.tsbUpdatingUsers = true;\n\n\t\t\t\t\t\t\tdoApiAction( {\n\t\t\t\t\t\t\t\tuserid: selectedUserIDs,\n\t\t\t\t\t\t\t\tdo: 'promote'\n\t\t\t\t\t\t\t} ).done( function () {\n\t\t\t\t\t\t\t\tremoveSelectedRequests();\n\n\t\t\t\t\t\t\t\twindow.tsbUpdatingUsers = false;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} ),\n\t\t\t\t\t$( '<button>' )\n\t\t\t\t\t\t.addClass( 'reject-all mw-ui-button mw-ui-destructive' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-reject-all-button-label' ) )\n\t\t\t\t\t\t.on( 'click', function () {\n\t\t\t\t\t\t\tmw.notify( mw.msg( 'tsb-reject-confirmation', selectedUserIDs.length ) );\n\n\t\t\t\t\t\t\twindow.tsbUpdatingUsers = true;\n\n\t\t\t\t\t\t\tdoApiAction( {\n\t\t\t\t\t\t\t\tuserid: selectedUserIDs,\n\t\t\t\t\t\t\t\tdo: 'delete'\n\t\t\t\t\t\t\t} ).done( function () {\n\t\t\t\t\t\t\t\tremoveSelectedRequests();\n\n\t\t\t\t\t\t\t\twindow.tsbUpdatingUsers = false;\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t} )\n\t\t\t\t)\n\t\t);\n\t}\n\n\t/**\n\t * Updates the counter of the selected users.\n\t *\n\t * @param {number} count The number of selected users\n\t */\n\tfunction updateSelectedIndicator( count ) {\n\t\tvar text = mw.msg( 'tsb-selected-count', mw.language.convertNumber( count ) );\n\n\t\t$( '.requests.pane .request-footer .selected-counter' ).text( text );\n\t\tif ( count > 1 ) {\n\t\t\t$( '.details.pane .tsb-header' ).text( text );\n\t\t}\n\t}\n\n\t/**\n\t * Returns older requests with the same number of translations.\n\t *\n\t * @return {jQuery} Older requests\n\t */\n\tfunction getOlderRequests() {\n\t\tvar $lastSelectedRequest = $( '.row.request.selected' ).last(),\n\t\t\tcurrentTranslationCount;\n\n\t\tif ( $lastSelectedRequest.length === 0 ) {\n\t\t\treturn [];\n\t\t}\n\n\t\tcurrentTranslationCount = $lastSelectedRequest.data( 'data' ).translations;\n\t\treturn $lastSelectedRequest.nextAll( ':not(.hide)' ).filter( function () {\n\t\t\treturn ( $( this ).data( 'data' ).translations === currentTranslationCount );\n\t\t} );\n\t}\n\n\t/**\n\t * Updates the number of older requests with the same number\n\t * of translations at the link in the bottom of the requests row\n\t * or hides that link if there are no such requests.\n\t */\n\tfunction indicateOlderRequests() {\n\t\tvar $olderRequests = getOlderRequests(),\n\t\t\t$olderRequestsIndicator = $( '.older-requests-indicator' );\n\n\t\tvar oldRequestsCount = $olderRequests.length;\n\t\tvar oldRequestsCountString = mw.language.convertNumber( oldRequestsCount );\n\n\t\tif ( oldRequestsCount ) {\n\t\t\t$olderRequestsIndicator\n\t\t\t\t.text( mw.msg( 'tsb-older-requests', oldRequestsCountString ) )\n\t\t\t\t.removeClass( 'hide' );\n\t\t} else {\n\t\t\t$olderRequestsIndicator\n\t\t\t\t.addClass( 'hide' );\n\t\t}\n\t}\n\n\t/**\n\t * Updates the number of requests.\n\t */\n\tfunction updateRequestCount() {\n\t\tvar $requests = $( '.requests-list .request' ),\n\t\t\tvisibleRequestsCount = $requests.filter( ':not(.hide)' ).length;\n\n\t\t$( '.request-count' ).text(\n\t\t\tmw.msg( 'tsb-request-count', mw.language.convertNumber( visibleRequestsCount ) )\n\t\t);\n\n\t\tif ( $requests.length === 0 ) {\n\t\t\t$( '.details.pane' )\n\t\t\t\t.empty()\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'tsb-header row' )\n\t\t\t\t\t\t.text( mw.msg( 'tsb-no-requests-from-new-users' ) )\n\t\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Sets the height of the panes to the window height.\n\t */\n\tfunction setPanesHeight() {\n\t\tvar $detailsPane = $( '.details.pane' ),\n\t\t\t$requestsPane = $( '.requests.pane' ),\n\t\t\tdetailsHeight = $( window ).height() - $detailsPane.offset().top,\n\t\t\trequestsHeight = detailsHeight -\n\t\t\t\t$requestsPane.find( '.request-footer' ).height() -\n\t\t\t\t$requestsPane.find( '.request-header' ).height();\n\n\t\t$detailsPane.css( 'max-height', detailsHeight );\n\t\t$requestsPane.find( '.requests-list' ).css( 'max-height', requestsHeight );\n\t}\n\n\tfunction selectAllRequests() {\n\t\tvar $requestCheckboxes = $( '.request-selector' ),\n\t\t\t$detailsPane = $( '.details.pane' ),\n\t\t\t$selectAll = $( '.request-selector-all' ),\n\t\t\t$requestRows = $( '.requests .request' ),\n\t\t\tselectAllChecked = $selectAll.prop( 'checked' ),\n\t\t\t$visibleRows = $requestRows.not( '.hide' );\n\n\t\t$visibleRows.each( function ( index, row ) {\n\t\t\t$( row ).find( '.request-selector' ).prop( {\n\t\t\t\tchecked: selectAllChecked,\n\t\t\t\tdisabled: false\n\t\t\t} );\n\t\t} );\n\n\t\tvar selectedCount;\n\t\tif ( selectAllChecked ) {\n\t\t\tdisplayOnMultipleSelection();\n\t\t\t$visibleRows.addClass( 'selected' );\n\t\t\tselectedCount = $requestCheckboxes.filter( ':checked' ).length;\n\t\t} else {\n\t\t\t$detailsPane.empty();\n\t\t\t$requestRows.removeClass( 'selected' );\n\t\t\tselectedCount = 0;\n\t\t}\n\n\t\tupdateSelectedIndicator( selectedCount );\n\t\tindicateOlderRequests();\n\t}\n\n\t/**\n\t * Handle click on request row\n\t *\n\t * @param {jQuery.Event} e\n\t */\n\tfunction onSelectRequest( e ) {\n\t\tvar $requestRow = $( e.target ).closest( '.request' ),\n\t\t\t$requestRows = $( '.requests .request' ),\n\t\t\t$selectAll = $( '.request-selector-all' );\n\n\t\tdisplayRequestDetails( $requestRow.data( 'data' ) );\n\n\t\t// Clicking a row makes only that row selected and unselects all other rows\n\t\t$requestRows.each( function ( i, row ) {\n\t\t\tvar $row = $( row );\n\n\t\t\tif ( row === $requestRow[ 0 ] ) {\n\t\t\t\t$row.addClass( 'selected' )\n\t\t\t\t\t.find( '.request-selector' ).prop( {\n\t\t\t\t\t\tchecked: true,\n\t\t\t\t\t\tdisabled: true\n\t\t\t\t\t} );\n\t\t\t} else {\n\t\t\t\t$row.removeClass( 'selected' )\n\t\t\t\t\t.find( '.request-selector' ).prop( {\n\t\t\t\t\t\tchecked: false,\n\t\t\t\t\t\tdisabled: false\n\t\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\n\t\t$selectAll.prop( 'indeterminate', true );\n\n\t\tupdateSelectedIndicator( 1 );\n\t\tindicateOlderRequests();\n\t}\n\n\t/**\n\t * Event handler for request checkbox selection.\n\t *\n\t * @param {jQuery.Event} e\n\t */\n\tfunction requestSelectHandler( e ) {\n\t\tvar request = e.target,\n\t\t\t$detailsPane = $( '.details.pane' ),\n\t\t\t$requestCheckboxes = $( '.request-selector' ),\n\t\t\t$selectAll = $( '.request-selector-all' ),\n\t\t\t$thisRequestRow = $( request ).parents( 'div.request' );\n\n\t\t// Uncheck the rows that were selected by clicking the row\n\t\t$requestCheckboxes.filter( ':disabled' ).prop( 'disabled', false );\n\n\t\t$thisRequestRow.toggleClass( 'selected', request.checked );\n\n\t\tvar $checkedBoxes = $requestCheckboxes.filter( ':checked' );\n\t\tvar checkedCount = $checkedBoxes.length;\n\n\t\tif ( checkedCount === $requestCheckboxes.length ) {\n\t\t\t// All boxes are selected\n\t\t\t$selectAll.prop( {\n\t\t\t\tchecked: true,\n\t\t\t\tindeterminate: false\n\t\t\t} );\n\n\t\t\tdisplayOnMultipleSelection();\n\t\t} else if ( checkedCount === 0 ) {\n\t\t\t// No boxes are selected\n\t\t\t$selectAll.prop( {\n\t\t\t\tchecked: false,\n\t\t\t\tindeterminate: false\n\t\t\t} );\n\n\t\t\t$detailsPane.empty();\n\t\t} else if ( checkedCount === 1 ) {\n\t\t\t$selectAll.prop( {\n\t\t\t\tchecked: false,\n\t\t\t\tindeterminate: true\n\t\t\t} );\n\n\t\t\t$checkedBoxes.prop( 'disabled', true );\n\n\t\t\t// Here we know that only one checkbox is selected,\n\t\t\t// so it's OK to query the data from it\n\t\t\tdisplayRequestDetails( $checkedBoxes.parents( 'div.request' ).data( 'data' ) );\n\t\t} else {\n\t\t\t$selectAll.prop( {\n\t\t\t\tchecked: false,\n\t\t\t\tindeterminate: true\n\t\t\t} );\n\n\t\t\tdisplayOnMultipleSelection();\n\t\t}\n\n\t\tupdateSelectedIndicator( checkedCount );\n\t\tindicateOlderRequests();\n\n\t\te.stopPropagation();\n\t}\n\n\t/**\n\t * Old request click handler.\n\t *\n\t * @param {jQuery.Event} e\n\t */\n\tfunction oldRequestSelector( e ) {\n\t\te.preventDefault();\n\n\t\tgetOlderRequests().each( function ( index, request ) {\n\t\t\t$( request ).find( '.request-selector' )\n\t\t\t\t.prop( 'checked', true ) // Otherwise the state doesn't actually change\n\t\t\t\t.trigger( 'change' );\n\t\t} );\n\t}\n\n\t// ======================================\n\t// LanguageFilter plugin\n\t// ======================================\n\tfunction LanguageFilter( element ) {\n\t\tthis.$selector = $( element );\n\t\tthis.init();\n\t}\n\n\tLanguageFilter.prototype.init = function () {\n\t\tvar languageFilter = this;\n\n\t\tvar $clearButton = $( '<button>' )\n\t\t\t.addClass( 'clear-language-selector hide' )\n\t\t\t.text( '×' );\n\n\t\tlanguageFilter.$selector.after( $clearButton );\n\t\t// Activate language selector\n\t\tlanguageFilter.$selector.uls( {\n\t\t\tonSelect: function ( language ) {\n\t\t\t\tlanguageFilter.$selector\n\t\t\t\t\t.removeClass( 'unselected' )\n\t\t\t\t\t.addClass( 'selected autonym' )\n\t\t\t\t\t.prop( {\n\t\t\t\t\t\tdir: $.uls.data.getDir( language ),\n\t\t\t\t\t\tlang: language\n\t\t\t\t\t} )\n\t\t\t\t\t.text( $.uls.data.getAutonym( language ) );\n\n\t\t\t\tlanguageFilter.filter( language );\n\t\t\t\t$clearButton.removeClass( 'hide' );\n\t\t\t\tindicateOlderRequests();\n\t\t\t},\n\t\t\tulsPurpose: 'translate-special-managetranslatorsandbox',\n\t\t\tquickList: mw.uls.getFrequentLanguageList\n\t\t} );\n\n\t\t$clearButton.on( 'click', function () {\n\t\t\tvar userLang = mw.config.get( 'wgUserLanguage' );\n\n\t\t\tlanguageFilter.$selector\n\t\t\t\t.removeClass( 'selected autonym' )\n\t\t\t\t.prop( {\n\t\t\t\t\tdir: $.uls.data.getDir( userLang ),\n\t\t\t\t\tlang: userLang\n\t\t\t\t} )\n\t\t\t\t.addClass( 'unselected' )\n\t\t\t\t.text( mw.msg( 'tsb-all-languages-button-label' ) );\n\n\t\t\tlanguageFilter.filter();\n\t\t\t$clearButton.addClass( 'hide' );\n\t\t} );\n\t};\n\n\t/**\n\t * Filter the requests by language.\n\t *\n\t * @param {string} [language] Language code\n\t */\n\tLanguageFilter.prototype.filter = function ( language ) {\n\t\tvar $requests = $( '.request' );\n\n\t\t$requests.each( function ( index, request ) {\n\t\t\tvar $request = $( request ),\n\t\t\t\trequestData = $request.data( 'data' );\n\n\t\t\tif ( !language ||\n\t\t\t\t( requestData.languagepreferences &&\n\t\t\t\t\trequestData.languagepreferences.languages &&\n\t\t\t\t\trequestData.languagepreferences.languages.includes( language ) )\n\t\t\t) {\n\t\t\t\t// Found language\n\t\t\t\t$request.removeClass( 'hide' );\n\t\t\t} else {\n\t\t\t\t$request.addClass( 'hide' );\n\t\t\t}\n\t\t} );\n\n\t\tupdateAfterFiltering();\n\t};\n\n\t$.fn.languageFilter = function () {\n\t\treturn this.each( function () {\n\t\t\tif ( !$.data( this, 'LanguageFilter' ) ) {\n\t\t\t\t$.data( this, 'LanguageFilter', new LanguageFilter( this ) );\n\t\t\t}\n\t\t} );\n\t};\n\n\t// ======================================\n\t// TranslatorSearch plugin\n\t// ======================================\n\tfunction TranslatorSearch( element ) {\n\t\tthis.$search = $( element );\n\t\tthis.init();\n\t}\n\n\tTranslatorSearch.prototype.init = function () {\n\t\tthis.$search.on( 'search keyup', this.keyup.bind( this ) );\n\t};\n\n\tTranslatorSearch.prototype.keyup = function () {\n\t\tvar translatorSearch = this;\n\n\t\t// Respond to the keypress events after a small timeout to avoid freeze when typed fast\n\t\tdelay( function () {\n\t\t\tvar query = translatorSearch.$search.val().trim().toLowerCase();\n\t\t\ttranslatorSearch.filter( query );\n\t\t}, 300 );\n\t};\n\n\tTranslatorSearch.prototype.filter = function ( query ) {\n\t\tvar $requests = $( '.request' );\n\n\t\t$requests.each( function ( index, request ) {\n\t\t\tvar $request = $( request ),\n\t\t\t\trequestData = $request.data( 'data' );\n\n\t\t\tif ( query.length === 0 ||\n\t\t\t\trequestData.username.toLowerCase().indexOf( query ) === 0 ||\n\t\t\t\trequestData.email.toLowerCase().indexOf( query ) === 0\n\t\t\t) {\n\t\t\t\t$request.removeClass( 'hide' );\n\t\t\t} else {\n\t\t\t\t$request.addClass( 'hide' );\n\t\t\t}\n\t\t} );\n\n\t\tupdateAfterFiltering();\n\t};\n\n\tfunction updateAfterFiltering() {\n\t\tvar $firstVisibleUser = $( '.request:not(.hide)' ).first();\n\n\t\tif ( $firstVisibleUser.length ) {\n\t\t\t$firstVisibleUser.trigger( 'click' );\n\t\t} else {\n\t\t\t$( '.details.pane' ).empty();\n\t\t\tvar $selectedRequests = $( '.request-selector:checked' );\n\t\t\t$selectedRequests.closest( '.request' ).removeClass( 'selected' );\n\t\t\t$selectedRequests.prop( {\n\t\t\t\tchecked: false,\n\t\t\t\tdisabled: false\n\t\t\t} );\n\n\t\t\tupdateSelectedIndicator( 0 );\n\t\t}\n\n\t\tupdateRequestCount();\n\t}\n\n\t$.fn.translatorSearch = function () {\n\t\treturn this.each( function () {\n\t\t\tif ( !$.data( this, 'TranslatorSearch' ) ) {\n\t\t\t\t$.data( this, 'TranslatorSearch', new TranslatorSearch( this ) );\n\t\t\t}\n\t\t} );\n\t};\n\n\tdelay = ( function () {\n\t\tvar timer = 0;\n\n\t\treturn function ( callback, milliseconds ) {\n\t\t\tclearTimeout( timer );\n\t\t\ttimer = setTimeout( callback, milliseconds );\n\t\t};\n\t}() );\n\n\t$( function () {\n\t\tvar $requestCheckboxes = $( '.request-selector' ),\n\t\t\t$selectAll = $( '.request-selector-all' ),\n\t\t\t$requestRows = $( '.requests .request' );\n\n\t\t// Delay so we get the correct height on page load\n\t\twindow.setTimeout( setPanesHeight, 0 );\n\t\t$( window ).on( 'resize', setPanesHeight );\n\n\t\t$( '.request-filter-box' ).translatorSearch();\n\t\t$( '.language-selector' ).languageFilter();\n\n\t\t// Handle clicks for the 'Select all' checkbox\n\t\t$selectAll.on( 'click', selectAllRequests );\n\n\t\t// Handle clicks on request checkboxes.\n\t\t$requestCheckboxes.on( 'click change', requestSelectHandler );\n\n\t\t// Handle clicks on request rows.\n\t\t$requestRows.on( 'click', onSelectRequest );\n\n\t\t$( '.older-requests-indicator' ).on( 'click', oldRequestSelector );\n\n\t\tif ( $requestRows.length ) {\n\t\t\t$requestRows.first().trigger( 'click' );\n\t\t}\n\n\t\tupdateRequestCount();\n\t} );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.pagemigration.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":134,"column":10,"nodeType":"CallExpression","endLine":166,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":388,"column":4,"nodeType":"CallExpression","endLine":394,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":388,"column":4,"nodeType":"CallExpression","endLine":398,"endColumn":7},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":562,"column":17,"nodeType":"CallExpression","endLine":568,"endColumn":5}],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":2,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":397,"column":44,"nodeType":"CallExpression","endLine":397,"endColumn":60,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":3,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\tvar noOfSourceUnits, noOfTranslationUnits,\n\t\tpageName = '',\n\t\tlangCode = '',\n\t\tsourceUnits = [];\n\n\t/**\n\t * Create translation pages using content of right hand side blocks\n\t * and identifiers from left hand side blocks. Create pages only if\n\t * content is not empty.\n\t *\n\t * @param {number} i Array index to sourceUnits.\n\t * @param {string} content\n\t * @return {Function} Returns a function which returns a jQuery.Promise\n\t */\n\tfunction createTranslationPage( i, content ) {\n\n\t\treturn function () {\n\t\t\tvar api = new mw.Api();\n\n\t\t\tvar identifier = sourceUnits[ i ].identifier;\n\t\t\tvar title = 'Translations:' + pageName + '/' + identifier + '/' + langCode;\n\t\t\tvar summary = $( '#pm-summary' ).val();\n\n\t\t\treturn api.postWithToken( 'csrf', {\n\t\t\t\taction: 'edit',\n\t\t\t\twatchlist: 'nochange',\n\t\t\t\ttitle: title,\n\t\t\t\ttext: content,\n\t\t\t\tsummary: summary\n\t\t\t} );\n\t\t};\n\t}\n\n\t/**\n\t * Get the old translations of a given page at given time.\n\t *\n\t * @internal\n\t * @param {string} fuzzyTimestamp Timestamp in MediaWiki format\n\t * @param {string} pageTitle\n\t * @return {jQuery.Promise<Array>} Old translations\n\t */\n\tfunction splitTranslationPage( fuzzyTimestamp, pageTitle ) {\n\t\tvar api = new mw.Api();\n\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tprop: 'revisions',\n\t\t\trvprop: 'content',\n\t\t\trvstart: fuzzyTimestamp,\n\t\t\trvlimit: 1,\n\t\t\tformatversion: '2',\n\t\t\ttitles: pageTitle\n\t\t} ).then( function ( data ) {\n\t\t\tvar $errorBox = $( '.mw-tpm-sp-error__message' );\n\t\t\tvar obj = data.query.pages[ 0 ];\n\t\t\t// TODO: Handle other cases such as invalid page titles ie: obj.invalid\n\t\t\tif ( obj === undefined || obj.missing ) {\n\t\t\t\t$errorBox.text( mw.msg( 'pm-page-does-not-exist', pageTitle ) ).removeClass( 'hide' );\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t}\n\t\t\tif ( obj.revisions === undefined ) {\n\t\t\t\t// the case of /en subpage where first edit is by FuzzyBot\n\t\t\t\t$errorBox.text( mw.msg( 'pm-old-translations-missing', pageTitle ) ).removeClass( 'hide' );\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t}\n\t\t\treturn obj.revisions[ 0 ].content.split( '\\n\\n' );\n\t\t} );\n\t}\n\n\t/**\n\t * Get the timestamp before FuzzyBot's first edit on page.\n\t *\n\t * @internal\n\t * @param {string} pageTitle\n\t * @return {jQuery.Promise<string>} Timestamp\n\t */\n\tfunction getFuzzyTimestamp( pageTitle ) {\n\t\tvar api = new mw.Api();\n\n\t\t// This api call returns the timestamp of FuzzyBot's edit\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tprop: 'revisions',\n\t\t\trvprop: 'timestamp',\n\t\t\trvuser: 'FuzzyBot',\n\t\t\trvdir: 'newer',\n\t\t\trvlimit: 1,\n\t\t\tformatversion: '2',\n\t\t\ttitles: pageTitle\n\t\t} ).then( function ( data ) {\n\t\t\tvar $errorBox = $( '.mw-tpm-sp-error__message' );\n\t\t\tvar obj = data.query.pages[ 0 ];\n\n\t\t\t// Page does not exist if missing field is present\n\t\t\tif ( obj === undefined || obj.missing === '' ) {\n\t\t\t\t$errorBox.text( mw.msg( 'pm-page-does-not-exist', pageTitle ) ).removeClass( 'hide' );\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t}\n\n\t\t\t// Page exists, but no edit by FuzzyBot\n\t\t\tif ( obj.revisions === undefined ) {\n\t\t\t\t$errorBox.text( mw.msg( 'pm-old-translations-missing', pageTitle ) ).removeClass( 'hide' );\n\t\t\t\treturn $.Deferred().reject();\n\t\t\t} else {\n\t\t\t\t// FB over here refers to FuzzyBot\n\t\t\t\tvar timestampFB = obj.revisions[ 0 ].timestamp;\n\t\t\t\tvar dateFB = new Date( timestampFB );\n\t\t\t\tdateFB.setSeconds( dateFB.getSeconds() - 1 );\n\t\t\t\tvar timestampOld = dateFB.toISOString();\n\t\t\t\tmw.log( 'New Timestamp: ' + timestampOld );\n\t\t\t\treturn timestampOld;\n\t\t\t}\n\t\t} );\n\t}\n\n\t/**\n\t * @typedef {Object} SourceUnit\n\t * @param {string} identifier\n\t * @param {string} definition\n\t */\n\n\t/**\n\t * Get the translation units created by Translate extension.\n\t *\n\t * @internal\n\t * @param {string} page Page name\n\t * @return {jQuery.Promise<SourceUnit[]>}\n\t */\n\tfunction getSourceUnits( page ) {\n\t\tvar api = new mw.Api();\n\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tlist: 'messagecollection',\n\t\t\tmcgroup: 'page-' + page,\n\t\t\tmclanguage: 'en',\n\t\t\tmcprop: 'definition'\n\t\t} ).then( function ( data ) {\n\t\t\tsourceUnits = [];\n\t\t\tvar result = data.query.messagecollection;\n\t\t\tfor ( var i = 0; i < result.length; i++ ) {\n\t\t\t\tvar sUnit = {};\n\t\t\t\tvar key = result[ i ].key;\n\t\t\t\tsUnit.identifier = key.slice( key.lastIndexOf( '/' ) + 1 );\n\t\t\t\tsUnit.definition = result[ i ].definition;\n\t\t\t\tsourceUnits.push( sUnit );\n\t\t\t}\n\t\t\treturn sourceUnits;\n\t\t} ).fail( function ( code, result ) {\n\t\t\t// Incase the group does not exist, just return an empty array.\n\t\t\tvar $errorContainer = $( '.mw-tpm-sp-error__message' );\n\t\t\tvar errorMessage = mw.msg( 'pm-translation-unit-fetch-failed' );\n\t\t\tif (\n\t\t\t\tcode === 'badparameter' &&\n\t\t\t\tresult.error && result.error.info.includes( 'mcgroup' )\n\t\t\t) {\n\t\t\t\terrorMessage = mw.msg( 'pm-pagetitle-not-translatable', page );\n\t\t\t}\n\n\t\t\t$errorContainer\n\t\t\t\t.text( errorMessage )\n\t\t\t\t.removeClass( 'hide' );\n\t\t\t$.Deferred().reject();\n\t\t} );\n\t}\n\n\t/**\n\t * Shift rows up by one unit. This is called after a unit is deleted.\n\t *\n\t * @param {jQuery} $start The starting node\n\t */\n\tfunction shiftRowsUp( $start ) {\n\t\tvar $current = $start,\n\t\t\t$next = $start.next();\n\n\t\twhile ( $next.length ) {\n\t\t\tvar nextVal = $next.find( '.mw-tpm-sp-unit__target' ).val();\n\t\t\t$current.find( '.mw-tpm-sp-unit__target' ).val( nextVal );\n\t\t\t$current = $next;\n\t\t\t$next = $current.next();\n\t\t}\n\t\tif ( $current.find( '.mw-tpm-sp-unit__source' ).val() ) {\n\t\t\t$current.find( '.mw-tpm-sp-unit__target' ).val( '' );\n\t\t} else {\n\t\t\t$current.remove();\n\t\t}\n\t}\n\n\t/**\n\t * Shift rows down by one unit. This is called after a new empty unit is\n\t * added.\n\t *\n\t * @param {jQuery} $nextRow The next row to start with\n\t * @param {string} text The text of the next row\n\t * @return {string} text The text of the last row\n\t */\n\tfunction shiftRowsDown( $nextRow, text ) {\n\t\twhile ( $nextRow.length ) {\n\t\t\tvar oldText = $nextRow.find( '.mw-tpm-sp-unit__target' ).val();\n\t\t\t$nextRow.find( '.mw-tpm-sp-unit__target' ).val( text );\n\t\t\t$nextRow = $nextRow.next();\n\t\t\ttext = oldText;\n\t\t}\n\t\treturn text;\n\t}\n\n\t/**\n\t * Create a new row of source text and target text with action icons.\n\t *\n\t * @param {string} sourceText\n\t * @param {string} targetText\n\t * @return {jQuery} newUnit The new row unit object\n\t */\n\n\tfunction createNewUnit( sourceText, targetText ) {\n\t\tvar $newUnit = $( '<div>' ).addClass( 'mw-tpm-sp-unit row' );\n\t\tvar $sourceUnit = $( '<textarea>' ).addClass( 'mw-tpm-sp-unit__source five columns' )\n\t\t\t.prop( 'readonly', true ).attr( 'tabindex', '-1' ).val( sourceText );\n\t\tvar $target = $( '<div>' ).addClass( 'five columns' );\n\t\tvar $targetUnit = $( '<textarea>' ).addClass( 'mw-tpm-sp-unit__target' )\n\t\t\t.val( targetText ).prop( 'dir', $.uls.data.getDir( langCode ) );\n\t\tvar $clearButton = $( '<button>' ).addClass( 'mw-tpm-sp-action--clear' )\n\t\t\t.attr( 'title', mw.msg( 'pm-clear-icon-hover-text' ) );\n\n\t\t$targetUnit.on( 'input', function () {\n\t\t\tvar $input = $( this );\n\t\t\tif ( $input.val().length === 0 ) {\n\t\t\t\t$clearButton.addClass( 'hide' );\n\t\t\t} else {\n\t\t\t\t$clearButton.removeClass( 'hide' );\n\t\t\t}\n\t\t} ).trigger( 'input' );\n\t\t$target.append( $targetUnit, $clearButton );\n\n\t\tvar $actionUnit = $( '<div>' ).addClass( 'mw-tpm-sp-unit__actions two columns' );\n\t\t$actionUnit.append(\n\t\t\t$( '<span>' ).addClass( 'mw-tpm-sp-action mw-tpm-sp-action--add' )\n\t\t\t\t.attr( 'title', mw.msg( 'pm-add-icon-hover-text' ) ),\n\t\t\t$( '<span>' ).addClass( 'mw-tpm-sp-action mw-tpm-sp-action--swap' )\n\t\t\t\t.attr( 'title', mw.msg( 'pm-swap-icon-hover-text' ) ),\n\t\t\t$( '<span>' ).addClass( 'mw-tpm-sp-action mw-tpm-sp-action--delete' )\n\t\t\t\t.attr( 'title', mw.msg( 'pm-delete-icon-hover-text' ) )\n\t\t);\n\t\t$newUnit.append( $sourceUnit, $target, $actionUnit );\n\t\treturn $newUnit;\n\t}\n\n\t/**\n\t * Display the source and target units alongwith the action icons.\n\t *\n\t * @param {Array} units\n\t * @param {Array} translations\n\t */\n\tfunction displayUnits( units, translations ) {\n\t\tnoOfSourceUnits = units.length;\n\t\tnoOfTranslationUnits = translations.length;\n\t\tvar totalUnits = noOfSourceUnits > noOfTranslationUnits ? noOfSourceUnits : noOfTranslationUnits;\n\t\tvar $unitListing = $( '.mw-tpm-sp-unit-listing' );\n\t\t$unitListing.html( '' );\n\t\tfor ( var i = 0; i < totalUnits; i++ ) {\n\t\t\tvar sourceText = '', targetText = '';\n\t\t\tif ( units[ i ] !== undefined ) {\n\t\t\t\tsourceText = units[ i ].definition;\n\t\t\t}\n\t\t\tif ( translations[ i ] !== undefined ) {\n\t\t\t\ttargetText = translations[ i ];\n\t\t\t}\n\t\t\tvar $newUnit = createNewUnit( sourceText, targetText );\n\t\t\t$unitListing.append( $newUnit );\n\t\t}\n\t}\n\n\t/**\n\t * Split headers from remaining text in each translation unit if present.\n\t *\n\t * @internal\n\t * @param {Array} translations Array of initial units obtained on splitting\n\t * @return {string[]} Array having the headers split into new unit\n\t */\n\tfunction splitHeaders( translations ) {\n\t\treturn translations.map( function ( elem ) {\n\t\t\t// Check https://regex101.com/r/oT7fZ2 for details\n\t\t\treturn elem.match( /(^==.+$|(?:(?!^==).+\\n?)+)/gm );\n\t\t} ).reduce( function ( acc, val ) {\n\t\t\t// This should be an Array.prototype.flatMap when ES2019 is supported\n\t\t\treturn acc.concat( val );\n\t\t}, [] );\n\t}\n\n\t/**\n\t * Get the index of next translation unit containing h2 header.\n\t *\n\t * @param {number} startIndex Index to start the scan from\n\t * @param {string[]} translationUnits Segmented units.\n\t * @return {number} Index of the next unit found, -1 if not.\n\t */\n\tfunction getHeaderUnit( startIndex, translationUnits ) {\n\t\tvar regex = new RegExp( /^==[^=]+==$/m );\n\t\tfor ( var i = startIndex; i < translationUnits.length; i++ ) {\n\t\t\tif ( regex.test( translationUnits[ i ] ) ) {\n\t\t\t\treturn i;\n\t\t\t}\n\t\t}\n\t\treturn -1;\n\t}\n\n\t/**\n\t * Align h2 headers in the order they appear.\n\t * Assumption: The source headers and translation headers appear in\n\t * the same order.\n\t *\n\t * @internal\n\t * @param {Object[]} units\n\t * @param {string[]} translationUnits\n\t * @return {string[]}\n\t */\n\tfunction alignHeaders( units, translationUnits ) {\n\t\t// The content does not have information about the page title. Add an empty string\n\t\t// at the beginning of the translationUnits array to match the length of units and\n\t\t// translationUnits.\n\t\tif ( units.length && units[ 0 ].identifier === 'Page_display_title' ) {\n\t\t\ttranslationUnits.unshift( '' );\n\t\t}\n\t\tvar tIndex = 0;\n\t\tvar regex = new RegExp( /^==[^=]+==$/m );\n\t\tfor ( var i = 0; i < units.length; i++ ) {\n\t\t\tif ( regex.test( units[ i ].definition ) ) {\n\t\t\t\ttIndex = getHeaderUnit( tIndex, translationUnits );\n\t\t\t\tvar mergeText = '';\n\t\t\t\t// search is over\n\t\t\t\tif ( tIndex === -1 ) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t// remove the unit\n\t\t\t\tvar matchText = translationUnits.splice( tIndex, 1 ).toString();\n\t\t\t\tvar emptyCount = i - tIndex;\n\t\t\t\tif ( emptyCount > 0 ) {\n\t\t\t\t\t// add empty units\n\t\t\t\t\twhile ( emptyCount !== 0 ) {\n\t\t\t\t\t\ttranslationUnits.splice( tIndex, 0, '' );\n\t\t\t\t\t\temptyCount -= 1;\n\t\t\t\t\t}\n\t\t\t\t} else if ( emptyCount < 0 ) {\n\t\t\t\t\t// merge units until there is room for tIndex translation unit to\n\t\t\t\t\t// align with ith source unit\n\t\t\t\t\twhile ( emptyCount !== 0 ) {\n\t\t\t\t\t\tmergeText += translationUnits.splice( i, 1 ).toString() + '\\n';\n\t\t\t\t\t\temptyCount += 1;\n\t\t\t\t\t}\n\t\t\t\t\tif ( i !== 0 ) {\n\t\t\t\t\t\ttranslationUnits[ i - 1 ] += '\\n' + mergeText;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmatchText = mergeText + matchText;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t// add the unit back\n\t\t\t\ttranslationUnits.splice( i, 0, matchText );\n\t\t\t\ttIndex = i + 1;\n\t\t\t}\n\t\t}\n\t\treturn translationUnits;\n\t}\n\n\t/**\n\t * Handler for 'Save' button click event.\n\t */\n\tfunction saveHandler() {\n\t\tvar list = [];\n\n\t\t$( '.mw-tpm-sp-error__message' ).addClass( 'hide' );\n\t\tif ( noOfSourceUnits < noOfTranslationUnits ) {\n\t\t\t$( '.mw-tpm-sp-error__message' ).text( mw.msg( 'pm-extra-units-warning' ) )\n\t\t\t\t.removeClass( 'hide' );\n\t\t\treturn;\n\t\t} else {\n\t\t\t$( 'input' ).prop( 'disabled', true );\n\t\t\t$( '.mw-tpm-sp-instructions' ).addClass( 'hide' );\n\t\t\tfor ( var i = 0; i < noOfSourceUnits; i++ ) {\n\t\t\t\tvar content = $( '.mw-tpm-sp-unit__target' ).eq( i ).val();\n\t\t\t\tcontent = content.trim();\n\t\t\t\tif ( content !== '' ) {\n\t\t\t\t\tlist.push( createTranslationPage( i, content ) );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$.ajaxDispatcher( list, 1 ).done( function () {\n\t\t\t\t$( '#action-import' ).removeClass( 'hide' );\n\t\t\t\t$( 'input' ).prop( 'disabled', false );\n\t\t\t\t$( '.mw-tpm-sp-instructions' )\n\t\t\t\t\t.text( mw.msg( 'pm-on-save-message-text' ) )\n\t\t\t\t\t.removeClass( 'hide' );\n\t\t\t} ).fail( function ( errmsg ) {\n\t\t\t\t$( 'input' ).prop( 'disabled', false );\n\t\t\t\t// eslint-disable-next-line mediawiki/msg-doc\n\t\t\t\t$( '.mw-tpm-sp-error__message' ).text( mw.msg( errmsg ) ).removeClass( 'hide' );\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Handler for 'Cancel' button click event.\n\t */\n\tfunction cancelHandler() {\n\t\t$( '.mw-tpm-sp-error__message' ).addClass( 'hide' );\n\t\t$( '.mw-tpm-sp-instructions' ).addClass( 'hide' );\n\t\t$( '#action-save, #action-cancel' ).addClass( 'hide' );\n\t\t$( '#action-import' ).removeClass( 'hide' );\n\t\t$( '.mw-tpm-sp-unit-listing' ).html( '' );\n\t}\n\n\t/**\n\t * Handler for add new unit icon ('+') click event. Adds a translation unit\n\t * below the current unit.\n\t *\n\t * @param {jQuery.Event} event\n\t */\n\tfunction addHandler( event ) {\n\t\tvar $nextRow = $( event.target ).closest( '.mw-tpm-sp-unit' ).next();\n\t\tvar $targetUnit = $nextRow.find( '.mw-tpm-sp-unit__target' );\n\t\tvar text = $targetUnit.val();\n\t\t$targetUnit.val( '' );\n\t\t$nextRow = $nextRow.next();\n\t\ttext = shiftRowsDown( $nextRow, text );\n\t\tif ( text ) {\n\t\t\tvar $newUnit = createNewUnit( '', text );\n\t\t\t$( '.mw-tpm-sp-unit-listing' ).append( $newUnit );\n\t\t}\n\t\tnoOfTranslationUnits += 1;\n\t}\n\n\t/**\n\t * Handler for delete icon ('-') click event. Deletes the unit and shifts\n\t * the units up by one.\n\t *\n\t * @param {jQuery.Event} event\n\t */\n\tfunction deleteHandler( event ) {\n\t\tvar $rowUnit = $( event.target ).closest( '.mw-tpm-sp-unit' );\n\t\tvar sourceText = $rowUnit.find( '.mw-tpm-sp-unit__source' ).val();\n\t\tif ( !sourceText ) {\n\t\t\t$rowUnit.remove();\n\t\t} else {\n\t\t\t$rowUnit.find( '.mw-tpm-sp-unit__target' ).val( '' );\n\t\t\tshiftRowsUp( $rowUnit );\n\t\t}\n\t\tnoOfTranslationUnits -= 1;\n\t}\n\n\t/**\n\t * Handler for clear icon click event. Clear the unit and maintains\n\t * the position of other units.\n\t *\n\t * @param {jQuery.Event} event\n\t */\n\tfunction clearContents( event ) {\n\t\tvar $rowUnit = $( event.target ).closest( '.mw-tpm-sp-unit' );\n\t\t$rowUnit.find( '.mw-tpm-sp-unit__target' ).val( '' );\n\t\t$( event.target ).addClass( 'hide' );\n\t}\n\n\t/**\n\t * Handler for swap icon click event. Swaps the text in the current unit\n\t * with the text in the unit below.\n\t *\n\t * @param {jQuery.Event} event\n\t */\n\tfunction swapHandler( event ) {\n\t\tvar $rowUnit = $( event.target ).closest( '.mw-tpm-sp-unit' );\n\t\tvar tempText = $rowUnit.find( '.mw-tpm-sp-unit__target' ).val();\n\t\tvar nextVal = $rowUnit.next().find( '.mw-tpm-sp-unit__target' ).val();\n\t\t$rowUnit.find( '.mw-tpm-sp-unit__target' ).val( nextVal );\n\t\t$rowUnit.next().find( '.mw-tpm-sp-unit__target' ).val( tempText );\n\t}\n\n\t/**\n\t * Handler for 'Import' button click event. Imports source and translation\n\t * units and displays them.\n\t *\n\t * @param {jQuery.Event} e\n\t */\n\tfunction importHandler( e ) {\n\t\tvar $errorBox = $( '.mw-tpm-sp-error__message' ),\n\t\t\t$messageBox = $( '.mw-tpm-sp-instructions' );\n\n\t\te.preventDefault();\n\n\t\tvar pageTitle = $( '#title' ).val().trim();\n\t\tif ( pageTitle === '' ) {\n\t\t\t$errorBox.text( mw.msg( 'pm-pagetitle-missing' ) ).removeClass( 'hide' );\n\t\t\treturn;\n\t\t}\n\n\t\tvar titleObj = mw.Title.newFromText( pageTitle );\n\t\t$messageBox.addClass( 'hide' );\n\t\tif ( titleObj === null ) {\n\t\t\t$errorBox.text( mw.msg( 'pm-pagetitle-invalid' ) ).removeClass( 'hide' );\n\t\t\treturn;\n\t\t}\n\n\t\tpageTitle = titleObj.getPrefixedDb();\n\t\tvar slashPos = pageTitle.lastIndexOf( '/' );\n\n\t\tif ( slashPos === -1 ) {\n\t\t\t$errorBox.text( mw.msg( 'pm-langcode-missing' ) ).removeClass( 'hide' );\n\t\t\treturn;\n\t\t}\n\n\t\tpageName = pageTitle.slice( 0, slashPos );\n\t\tlangCode = pageTitle.slice( slashPos + 1 );\n\n\t\tif ( pageName === '' ) {\n\t\t\t$errorBox.text( mw.msg( 'pm-pagetitle-invalid' ) ).removeClass( 'hide' );\n\t\t\treturn;\n\t\t}\n\n\t\t$errorBox.addClass( 'hide' );\n\n\t\tvar fuzzyTimestamp = null;\n\t\tvar units = null;\n\t\tgetFuzzyTimestamp( pageTitle )\n\t\t\t.then( function ( response ) {\n\t\t\t\tfuzzyTimestamp = response;\n\t\t\t\treturn getSourceUnits( pageName );\n\t\t\t} )\n\t\t\t.then( function ( response ) {\n\t\t\t\tunits = response;\n\t\t\t\treturn splitTranslationPage( fuzzyTimestamp, pageTitle );\n\t\t\t} )\n\t\t\t.then( function ( translations ) {\n\t\t\t\tnoOfSourceUnits = units.length;\n\t\t\t\tvar translationUnits = splitHeaders( translations );\n\t\t\t\ttranslationUnits = alignHeaders( units, translationUnits );\n\t\t\t\tnoOfTranslationUnits = translationUnits.length;\n\t\t\t\tdisplayUnits( units, translationUnits );\n\t\t\t\t$( '#action-save, #action-cancel' ).removeClass( 'hide' );\n\t\t\t\t$( '#action-import' ).addClass( 'hide' );\n\t\t\t\t$messageBox.text( mw.msg( 'pm-on-import-message-text' ) ).removeClass( 'hide' );\n\t\t\t} );\n\t}\n\n\t/**\n\t * Listens to various click events\n\t */\n\tfunction listen() {\n\t\tvar $listing = $( '.mw-tpm-sp-unit-listing' );\n\n\t\t$( '#mw-tpm-sp-primary-form' ).on( 'submit', importHandler );\n\t\t$( '#action-import' ).on( 'click', importHandler );\n\t\t$( '#action-save' ).on( 'click', saveHandler );\n\t\t$( '#action-cancel' ).on( 'click', cancelHandler );\n\t\t$listing.on( 'click', '.mw-tpm-sp-action--swap', swapHandler );\n\t\t$listing.on( 'click', '.mw-tpm-sp-action--delete', deleteHandler );\n\t\t$listing.on( 'click', '.mw-tpm-sp-action--add', addHandler );\n\t\t$listing.on( 'click', '.mw-tpm-sp-action--clear', clearContents );\n\t}\n\n\t$( listen );\n\n\tmw.translate = mw.translate || {};\n\tmw.translate = $.extend( mw.translate, {\n\t\tgetSourceUnits: getSourceUnits,\n\t\tgetFuzzyTimestamp: getFuzzyTimestamp,\n\t\tsplitTranslationPage: splitTranslationPage,\n\t\tsplitHeaders: splitHeaders,\n\t\talignHeaders: alignHeaders\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.pagepreparation.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":327,"column":4,"nodeType":"CallExpression","endLine":339,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":327,"column":4,"nodeType":"CallExpression","endLine":341,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":354,"column":4,"nodeType":"CallExpression","endLine":396,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":354,"column":4,"nodeType":"CallExpression","endLine":398,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":372,"column":5,"nodeType":"CallExpression","endLine":393,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":372,"column":5,"nodeType":"CallExpression","endLine":395,"endColumn":8}],"suppressedMessages":[{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":349,"column":5,"nodeType":"CallExpression","messageId":"unexpected","endLine":349,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":6,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\n\t/**\n\t * Get a regex snippet matching any aliases (including the canonical\n\t * name) of the given namespace, or of “other” namespaces if the\n\t * namespace is not given.\n\t *\n\t * @param {number|null} filter The namespace ID to filter for, or\n\t *  `null` to filter for “other” namespaces\n\t * @return {string} The aliases of the specified namespace(s),\n\t *  regex-escaped and joined with `|`\n\t */\n\tfunction getNamespaceRegex( filter ) {\n\t\tvar aliases = [];\n\t\tvar namespacesObject = mw.config.get( 'wgNamespaceIds' );\n\t\tfor ( var key in namespacesObject ) {\n\t\t\tif ( filter !== null ) {\n\t\t\t\tif ( namespacesObject[ key ] === filter ) {\n\t\t\t\t\taliases.push( mw.util.escapeRegExp( key ) );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tswitch ( namespacesObject[ key ] ) {\n\t\t\t\t\tcase -1:\n\t\t\t\t\tcase 0:\n\t\t\t\t\tcase 6:\n\t\t\t\t\tcase 7:\n\t\t\t\t\tcase 14:\n\t\t\t\t\tcase 15:\n\t\t\t\t\t\t// not needed or handled somewhere else\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault:\n\t\t\t\t\t\taliases.push( mw.util.escapeRegExp( key ) );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn aliases.join( '|' );\n\t}\n\n\t/**\n\t * Remove all the <translate> tags and {{translation}} templates before\n\t * preparing the page. The tool will add them back wherever needed.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction cleanupTags( pageContent ) {\n\t\treturn pageContent.replace( /<\\/?translate>\\n?/gi, '' );\n\t}\n\n\t/**\n\t * Add the <languages/> bar at the top of the page, if not present.\n\t * Remove the old {{languages}} template if it is present.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction addLanguageBar( pageContent ) {\n\t\tif ( !/<languages ?\\/>/gi.test( pageContent ) ) {\n\t\t\tpageContent = '<languages/>\\n' + pageContent;\n\t\t}\n\t\treturn pageContent.replace( /\\{\\{languages.*?}}/gi, '' );\n\t}\n\n\t/**\n\t * Add <translate> tags around Categories to make them a part of the page template\n\t * and tag them with the {{translation}} template.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction doCategories( pageContent ) {\n\t\tvar aliasList = getNamespaceRegex( 14 );\n\t\t// Regex: https://regex101.com/r/sJ3gZ4/2\n\t\tvar categoryRegex = new RegExp( '\\\\[\\\\[((' + aliasList + ')' +\n\t\t\t':[^\\\\|]+)(\\\\|[^\\\\|]*?)?\\\\]\\\\]', 'gi' );\n\t\treturn pageContent.replace( categoryRegex, '\\n</translate>\\n' +\n\t\t\t'[[$1{{#translation:}}$3]]\\n<translate>\\n' );\n\t}\n\n\t/**\n\t * Add the <translate> and </translate> tags at the start and end of the page.\n\t * The opening tag is added immediately after the <languages/> tag.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction addTranslateTags( pageContent ) {\n\t\t// Check for a <languages/> tag with a newline after.\n\t\t// If there is no newline, there is some text/syntax after, so we don't want to add any <translate> tags now.\n\t\tif ( /<languages ?\\/>\\n/gi.test( pageContent ) ) {\n\t\t\tpageContent = pageContent.replace( /(<languages ?\\/>\\n)/gi, '$1<translate>\\n' ) +\n\t\t\t\t'\\n</translate>';\n\t\t}\n\n\t\treturn pageContent;\n\t}\n\n\t/**\n\t * Add newlines before and after section headers. Extra newlines resulting after\n\t * this operation are cleaned up in postPreparationCleanup() function.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction addNewLines( pageContent ) {\n\t\treturn pageContent.replace( /^(==.*==)\\n*/gm, '\\n$1\\n\\n' );\n\t}\n\n\t/**\n\t * Add an anchor to a section header with the given headerText.\n\t *\n\t * @param {string} headerText\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction addAnchor( headerText, pageContent ) {\n\t\tvar anchorID = headerText.replace( ' ', '-' ).toLowerCase();\n\n\t\theaderText = mw.util.escapeRegExp( headerText );\n\t\t// Search for the header having text as headerText\n\t\t// Regex: https://regex101.com/r/fD6iL1\n\t\tvar headerSearchRegex = new RegExp( '(==+[ ]*' + headerText + '[ ]*==+)', 'gi' );\n\t\t// This is to ensure that the tags and the anchor are added only once\n\n\t\tif ( !pageContent.includes( '<span id=\"' + mw.html.escape( anchorID ) + '\"' ) ) {\n\t\t\tpageContent = pageContent.replace( headerSearchRegex, '</translate>\\n' +\n\t\t\t\t'<span id=\"' + mw.html.escape( anchorID ) + '\"></span>\\n<translate>\\n$1' );\n\t\t}\n\n\t\t// This is to add back the tags which were removed in cleanupTags()\n\t\tif ( !pageContent.includes( '</translate>\\n<span id=\"' + anchorID + '\"' ) ) {\n\t\t\tvar spanSearchRegex = new RegExp( '(<span id=\"' + mw.util.escapeRegExp( anchorID ) + '\"></span>)', 'gi' );\n\t\t\tpageContent = pageContent.replace( spanSearchRegex, '\\n</translate>\\n$1\\n</translate>\\n' );\n\t\t}\n\n\t\t// Replace the link text with the anchorID defined above\n\t\t// Regex: https://regex101.com/r/kB5bK3\n\t\tvar replaceAnchorRegex = new RegExp( '(\\\\[\\\\[#)' + headerText + '(.*\\\\]\\\\])', 'gi' );\n\t\treturn pageContent.replace( replaceAnchorRegex, '$1' +\n\t\t\tanchorID.replace( '$', '$$$' ) + '$2' );\n\t}\n\n\t/**\n\t * Convert all the links into the two-party form and add the 'Special:MyLanguage/' prefix\n\t * to links in valid namespaces for the wiki. For example, [[Example]] would be converted\n\t * to [[Special:MyLanguage/Example|Example]].\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction fixInternalLinks( pageContent ) {\n\t\tvar searchText = pageContent;\n\n\t\tvar categoryNsString = getNamespaceRegex( 14 );\n\t\tvar normalizeRegex = new RegExp( '\\\\[\\\\[(?!' + categoryNsString + ')([^|]*?)\\\\]\\\\]', 'gi' );\n\t\t// First, convert all links into the two-party form.\n\t\t// If a link is not having a pipe,\n\t\t// add a pipe and duplicate the link text\n\t\t// Regex: https://regex101.com/r/pO9nN2\n\t\tpageContent = pageContent.replace( normalizeRegex, '[[$1|$1]]' );\n\n\t\tvar nsString = getNamespaceRegex( null );\n\t\t// Finds all the links to sections on the same page.\n\t\t// Regex: https://regex101.com/r/cX6jT3\n\t\tvar sectionLinksRegex = new RegExp( /\\[\\[#(.*?)(\\|(.*?))?]]/gi );\n\t\tvar match = sectionLinksRegex.exec( searchText );\n\t\twhile ( match !== null ) {\n\t\t\tpageContent = addAnchor( match[ 1 ], pageContent );\n\t\t\tmatch = sectionLinksRegex.exec( searchText );\n\t\t}\n\n\t\tvar linkPrefixRegex = new RegExp( '\\\\[\\\\[((?:(?:special(?!:MyLanguage\\\\b)|' + nsString +\n\t\t\t'):)?[^:]*?)\\\\]\\\\]', 'gi' );\n\t\t// Add the 'Special:MyLanguage/' prefix for all internal links of valid namespaces and\n\t\t// main namespace.\n\t\t// Regex: https://regex101.com/r/zZ9jH9\n\t\treturn pageContent.replace( linkPrefixRegex, '[[Special:MyLanguage/$1]]' );\n\t}\n\n\t/**\n\t * Add translate tags around only translatable content for files and keep everything else\n\t * as a part of the page template.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction doFiles( pageContent ) {\n\t\tvar aliasList = getNamespaceRegex( 6 );\n\n\t\t// Add translate tags for files with captions\n\t\tvar captionFilesRegex = new RegExp( '\\\\[\\\\[(' + aliasList + ')(.*\\\\|)(.*?)\\\\]\\\\]', 'gi' );\n\t\tpageContent = pageContent.replace( captionFilesRegex,\n\t\t\t'</translate>\\n[[$1$2<translate>$3</translate>]]\\n<translate>' );\n\n\t\t// Add translate tags for files without captions\n\t\tvar fileRegex = new RegExp( '/\\\\[\\\\[((' + aliasList + ')[^\\\\|]*?)\\\\]\\\\]', 'gi' );\n\t\treturn pageContent.replace( fileRegex, '\\n</translate>[[$1]]\\n<translate>' );\n\t}\n\n\t/**\n\t * Keep templates outside <translate>....</translate> tags.\n\t * Does not deal with nested templates, needs manual changes.\n\t *\n\t * @param {string} pageContent\n\t * @return {string} pageContent\n\t */\n\tfunction doTemplates( pageContent ) {\n\t\t// Regex: https://regex101.com/r/wA3iX0\n\t\tvar templateRegex = new RegExp( /^({{[\\s\\S]*?}})/gm );\n\n\t\treturn pageContent.replace( templateRegex, '</translate>\\n$1\\n<translate>' );\n\t}\n\n\t/**\n\t * Cleanup done after the page is prepared for translation by the tool.\n\t *\n\t * @param {string} pageContent\n\t * @return {string}\n\t */\n\tfunction postPreparationCleanup( pageContent ) {\n\t\t// Removes any extra newlines introduced by the tool\n\t\tpageContent = pageContent.replace( /\\n\\n+/gi, '\\n\\n' );\n\t\t// Removes redundant <translate> tags\n\t\tpageContent = pageContent.replace( /\\n<translate>(\\n*?)<\\/translate>/gi, '' );\n\t\t// Removes the Special:MyLanguage/ prefix for section links\n\t\treturn pageContent.replace( /Special:MyLanguage\\/#/gi, '#' );\n\t}\n\n\t/**\n\t * Get the current revision for the given page.\n\t *\n\t * @param {string} pageName\n\t * @return {jQuery.Promise}\n\t */\n\tfunction getPageContent( pageName ) {\n\t\tvar api = new mw.Api();\n\n\t\treturn api.get( {\n\t\t\taction: 'query',\n\t\t\tprop: 'revisions',\n\t\t\trvprop: 'content',\n\t\t\trvlimit: '1',\n\t\t\tformatversion: '2',\n\t\t\ttitles: pageName\n\t\t} ).promise();\n\t}\n\n\t/**\n\t * Get the diff between the current revision and the prepared page content.\n\t *\n\t * @param {string} pageName Page title\n\t * @param {string} pageContent New content of the page\n\t * @return {jQuery.Promise}\n\t */\n\tfunction getDiff( pageName, pageContent ) {\n\t\tvar api = new mw.Api();\n\n\t\treturn api.post( {\n\t\t\taction: 'compare',\n\t\t\tprop: 'diff',\n\t\t\tformatversion: '2',\n\t\t\tfromtitle: pageName,\n\t\t\ttoslots: 'main',\n\t\t\t'totext-main': pageContent\n\t\t} ).promise();\n\t}\n\n\t/**\n\t * Save the page with a given page name and given content to the wiki.\n\t *\n\t * @param {string} pageName Page title\n\t * @param {string} pageContent Content of the page to be saved\n\t * @param {string} summary Edit summary for the change\n\t * @return {jQuery.Promise}\n\t */\n\tfunction savePage( pageName, pageContent, summary ) {\n\t\tvar api = new mw.Api();\n\n\t\treturn api.postWithToken( 'csrf', {\n\t\t\taction: 'edit',\n\t\t\ttitle: pageName,\n\t\t\ttext: pageContent,\n\t\t\tsummary: summary\n\t\t} ).promise();\n\t}\n\n\t/**\n\t * Display error message to the user\n\t *\n\t * @param {string} errorMessage Error message to display to the user\n\t */\n\tfunction displayError( errorMessage ) {\n\t\tif ( errorMessage === undefined ) {\n\t\t\terrorMessage = mw.msg( 'pp-unexpected-error' );\n\t\t}\n\n\t\t$( '.messageDiv' )\n\t\t\t.text( errorMessage )\n\t\t\t.removeClass( 'hide' )\n\t\t\t.addClass( 'mw-message-box-error' );\n\t}\n\n\t/**\n\t * Failure callback method for the prepare step\n\t *\n\t * @param {string} errorMessage Error message to display to the user\n\t */\n\tfunction onPrepareFailure( errorMessage ) {\n\t\tdisplayError( errorMessage );\n\t\t$( '#action-prepare' ).prop( 'disabled', false );\n\t}\n\n\t$( function () {\n\t\tvar $input = $( '#page' );\n\t\tvar $messageDiv = $( '.messageDiv' );\n\n\t\t$( '#action-cancel' ).on( 'click', function () {\n\t\t\tdocument.location.reload( true );\n\t\t} );\n\n\t\tvar pageContent;\n\t\t$( '#action-save' ).on( 'click', function () {\n\t\t\tvar pageName = $input.val().trim();\n\t\t\t$messageDiv.removeClass( 'mw-message-box-error mw-message-box-success' );\n\t\t\tsavePage( pageName, pageContent, $( '#pp-summary' ).val() ).done( function () {\n\t\t\t\tvar pageUrl = mw.Title.newFromText( pageName ).getUrl( { action: 'edit' } );\n\t\t\t\t$messageDiv\n\t\t\t\t\t.empty()\n\t\t\t\t\t.append( mw.message( 'pp-save-message', pageUrl ).parseDom() )\n\t\t\t\t\t.addClass( 'mw-message-box-success' )\n\t\t\t\t\t.removeClass( 'hide' );\n\t\t\t\t$( '.divDiff' ).addClass( 'hide' );\n\t\t\t\t$( '#action-prepare' ).removeClass( 'hide' );\n\t\t\t\t$input.val( '' );\n\t\t\t\t$( '#action-save' ).addClass( 'hide' );\n\t\t\t\t$( '#action-cancel' ).addClass( 'hide' );\n\t\t\t} ).fail( function ( _code, data ) {\n\t\t\t\tdisplayError( data.error.info );\n\t\t\t} );\n\t\t} );\n\n\t\t$( '#action-prepare' ).on( 'click', function () {\n\t\t\tvar pageName = $input.val().trim();\n\t\t\t$messageDiv.addClass( 'hide' ).removeClass( 'mw-message-box-error mw-message-box-success' );\n\t\t\tif ( pageName === '' ) {\n\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\talert( mw.msg( 'pp-pagename-missing' ) );\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t$( this ).prop( 'disabled', true );\n\n\t\t\tgetPageContent( pageName ).done( function ( contentData ) {\n\t\t\t\t// Check if the page actually exists\n\t\t\t\tif ( contentData.query.pages[ 0 ].revisions === undefined ) {\n\t\t\t\t\tonPrepareFailure( mw.msg( 'pp-page-does-not-exist', pageName ) );\n\t\t\t\t\treturn $.Deferred().reject();\n\t\t\t\t}\n\n\t\t\t\tpageContent = contentData.query.pages[ 0 ].revisions[ 0 ].content.trim();\n\t\t\t\tpageContent = cleanupTags( pageContent );\n\t\t\t\tpageContent = addLanguageBar( pageContent );\n\t\t\t\tpageContent = addTranslateTags( pageContent );\n\t\t\t\tpageContent = addNewLines( pageContent );\n\t\t\t\tpageContent = fixInternalLinks( pageContent );\n\t\t\t\tpageContent = doTemplates( pageContent );\n\t\t\t\tpageContent = doFiles( pageContent );\n\t\t\t\tpageContent = doCategories( pageContent );\n\t\t\t\tpageContent = postPreparationCleanup( pageContent );\n\t\t\t\tpageContent = pageContent.trim();\n\t\t\t\tgetDiff( pageName, pageContent ).done( function ( diffData ) {\n\t\t\t\t\tvar diff = diffData.compare.body;\n\t\t\t\t\tvar $prepare = $( '#action-prepare' );\n\t\t\t\t\t// Enable prepare button whether the diff failed or not, so it can be clicked again...\n\t\t\t\t\t$prepare.prop( 'disabled', false );\n\t\t\t\t\t$messageDiv.removeClass( 'hide' );\n\t\t\t\t\tif ( diff === undefined ) {\n\t\t\t\t\t\tonPrepareFailure( mw.msg( 'pp-diff-error' ) );\n\t\t\t\t\t\treturn $.Deferred().reject();\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( diff !== '' ) {\n\t\t\t\t\t\t$( '.diff tbody' ).html( diff );\n\t\t\t\t\t\t$( '.divDiff' ).removeClass( 'hide' );\n\t\t\t\t\t\t$messageDiv.text( mw.msg( 'pp-prepare-message' ) );\n\t\t\t\t\t\t$prepare.addClass( 'hide' );\n\t\t\t\t\t\t$( '#action-save' ).removeClass( 'hide' );\n\t\t\t\t\t\t$( '#action-cancel' ).removeClass( 'hide' );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdisplayError( mw.msg( 'pp-already-prepared-message' ) );\n\t\t\t\t\t}\n\t\t\t\t} ).fail( function ( _code, errorData ) {\n\t\t\t\t\tonPrepareFailure( errorData.error && errorData.error.info );\n\t\t\t\t} );\n\t\t\t} ).fail( function ( _code, errorData ) {\n\t\t\t\tonPrepareFailure( errorData.error && errorData.error.info );\n\t\t\t} );\n\t\t} );\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.pagetranslation.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":36,"column":3,"nodeType":"CallExpression","endLine":38,"endColumn":6}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"'use strict';\n\n/*!\n * @author Santhosh Thottingal\n * @author Niklas Laxström\n * @license GPL-2.0-or-later\n */\n\nvar LanguagesMultiselectWidget = require( './LanguagesMultiselectWidget.js' );\n\n// Needed for OOUI :(\nwindow.LanguagesMultiselectWidget = LanguagesMultiselectWidget;\n\nfunction configureLanguageInput( $form, $widget ) {\n\t/** @type {LanguagesMultiselectWidget} */\n\tvar widget = OO.ui.infuse( $widget, { api: new mw.Api() } );\n\n\tvar $input = $( '<input>' ).prop( {\n\t\ttype: 'hidden',\n\t\tname: 'prioritylangs',\n\t\tvalue: widget.getValue()\n\t} );\n\n\t$form.prepend( $input );\n\twidget.on( 'change', function () {\n\t\t$input.val( widget.getValue() );\n\t} );\n}\n\nfunction configurePostLinks( $container ) {\n\t$container.on( 'click', '.mw-translate-jspost', function ( e ) {\n\t\tvar uri = new mw.Uri( e.target.href );\n\n\t\tvar params = uri.query;\n\t\tparams.token = mw.user.tokens.get( 'csrfToken' );\n\t\t$.post( uri.path, params ).done( function () {\n\t\t\tlocation.reload();\n\t\t} );\n\n\t\te.preventDefault();\n\t} );\n}\n\nfunction configureDropdownForFuzzySelector( $container ) {\n\tvar $form = $container.find( '.mw-tpt-sp-markform' );\n\tvar $dropdown = $form.find( 'select[name=\"unit-fuzzy-selector\"]' );\n\t$dropdown.on( 'change', function () {\n\t\t// hide the dropdown when it is \"all\" or \"none\"\n\t\t$form.toggleClass( 'mw-tpt-hide-custom-fuzzy', $( this ).val() !== 'custom' );\n\t} );\n}\n\nfunction configureHideUnchangedTranslationUnits( $container ) {\n\tvar $form = $container.find( '.mw-tpt-sp-markform' );\n\t$form.find( 'input[name=\"unchanged-translation-units\"]' ).on( 'change', function () {\n\t\t$form.toggleClass( 'mw-tpt-hide-unchanged', $( this ).prop( 'checked' ) );\n\t} );\n}\n\n// Init\n$( function () {\n\tvar $widgets = $( '#mw-translate-SpecialPageTranslation-prioritylangs' );\n\n\tvar $container = $( '#mw-content-text' );\n\tconfigurePostLinks( $container );\n\tconfigureDropdownForFuzzySelector( $container );\n\tconfigureHideUnchangedTranslationUnits( $container );\n\tif ( $widgets.length ) {\n\t\tconfigureLanguageInput( $( '.mw-tpt-sp-markform' ), $widgets );\n\t}\n} );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.searchtranslations.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.translate.js","messages":[{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":19,"column":17,"nodeType":"CallExpression","endLine":169,"endColumn":5},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":59,"column":4,"nodeType":"CallExpression","endLine":74,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":96,"column":4,"nodeType":"CallExpression","endLine":109,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":236,"column":3,"nodeType":"CallExpression","endLine":240,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":269,"column":3,"nodeType":"CallExpression","endLine":273,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":269,"column":3,"nodeType":"CallExpression","endLine":276,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":664,"column":4,"nodeType":"CallExpression","endLine":667,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":736,"column":3,"nodeType":"CallExpression","endLine":756,"endColumn":6}],"suppressedMessages":[{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":65,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":65,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_type' is not in camel case.","line":67,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":67,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'translatable_count' is not in camel case.","line":69,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":69,"endColumn":25,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'translated_count' is not in camel case.","line":71,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":71,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'target_language' is not in camel case.","line":102,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":102,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'translatable_count' is not in camel case.","line":104,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":104,"endColumn":25,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'translated_count' is not in camel case.","line":106,"column":7,"nodeType":"Identifier","messageId":"notCamelCase","endLine":106,"endColumn":23,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-alert","severity":2,"message":"Unexpected confirm.","line":210,"column":11,"nodeType":"CallExpression","messageId":"unexpected","endLine":210,"endColumn":70,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_language' is not in camel case.","line":743,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":743,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'target_language' is not in camel case.","line":745,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":745,"endColumn":21,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_title' is not in camel case.","line":747,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":747,"endColumn":18,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'source_type' is not in camel case.","line":749,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":749,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'translatable_count' is not in camel case.","line":751,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":751,"endColumn":24,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'translated_count' is not in camel case.","line":753,"column":6,"nodeType":"Identifier","messageId":"notCamelCase","endLine":753,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":7,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\n\tvar state, hideOptionalMessages = '!optional';\n\n\tstate = {\n\t\tgroup: null,\n\t\tlanguage: null,\n\t\tmessageList: null\n\t};\n\n\tmw.translate = mw.translate || {};\n\n\tvar logger = require( 'ext.translate.eventlogginghelpers' );\n\tif ( logger.isEventLoggingEnabled() ) {\n\t\ttrackUserExit();\n\t}\n\n\tmw.translate = $.extend( mw.translate, {\n\n\t\t/**\n\t\t * Change the group that is currently displayed\n\t\t * in the TUX translation editor.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} group a message group object.\n\t\t */\n\t\tchangeGroup: function ( group ) {\n\t\t\tif ( !checkDirty() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar sourceType;\n\t\t\tif ( group.id.indexOf( 'agg-' ) === 0 ) {\n\t\t\t\tsourceType = 'aggregate-group';\n\t\t\t} else if ( group.id.indexOf( 'page-' ) === 0 ) {\n\t\t\t\tsourceType = 'translatable-page';\n\t\t\t} else if ( group.id.indexOf( 'messagebundle-' ) === 0 ) {\n\t\t\t\tsourceType = 'message-bundle';\n\t\t\t} else {\n\t\t\t\tsourceType = 'normal-message-group';\n\t\t\t}\n\n\t\t\tshowAggregateSubgroupCount();\n\n\t\t\tstate.group = group.id;\n\n\t\t\tvar changes = {\n\t\t\t\tgroup: group.id,\n\t\t\t\tshowMessage: null\n\n\t\t\t};\n\n\t\t\tmw.translate.changeUrl( changes );\n\t\t\tmw.translate.updateTabLinks( changes );\n\t\t\tremoveGroupWarnings();\n\t\t\tstate.messageList.changeSettings( changes );\n\t\t\tupdateGroupInformation( state );\n\t\t\tgetTranslationStats( state.language ).done( function ( stats ) {\n\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t'switch_translate_content',\n\t\t\t\t\t'message_group_menu',\n\t\t\t\t\t{\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tsource_title: group.id,\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\tsource_type: sourceType,\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\ttranslatable_count: stats.total,\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\ttranslated_count: stats.translated\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * @private\n\t\t * @param {string} language\n\t\t */\n\t\tchangeLanguage: function ( language ) {\n\t\t\tvar changes = {\n\t\t\t\tlanguage: language,\n\t\t\t\tshowMessage: null\n\t\t\t};\n\n\t\t\tstate.language = language;\n\n\t\t\tmw.translate.changeUrl( changes );\n\t\t\tmw.translate.updateTabLinks( changes );\n\t\t\tremoveGroupWarnings();\n\t\t\tstate.messageList.changeSettings( changes );\n\t\t\tstate.groupSelector.updateTargetLanguage( language );\n\t\t\tupdateGroupInformation( state );\n\n\t\t\tgetTranslationStats( language ).done( function ( stats ) {\n\t\t\t\tlogger.logClickEvent(\n\t\t\t\t\t'change_target_lang',\n\t\t\t\t\t'language_selector',\n\t\t\t\t\t{\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\ttarget_language: language,\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\ttranslatable_count: stats.total,\n\t\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\t\ttranslated_count: stats.translated\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * @internal\n\t\t * @param {string} filter\n\t\t */\n\t\tchangeFilter: function ( filter ) {\n\t\t\tif ( !checkDirty() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tmw.translate.changeUrl( { filter: filter, showMessage: null } );\n\t\t\tstate.messageList.changeSettings( { filter: getActualFilter( filter ) } );\n\t\t},\n\n\t\t/**\n\t\t * @internal\n\t\t * @param {Object} params\n\t\t */\n\t\tchangeUrl: function ( params ) {\n\t\t\tvar uri = new mw.Uri( window.location.href );\n\n\t\t\turi.extend( params );\n\n\t\t\t// Support removing keys from the query\n\t\t\tObject.keys( params ).forEach( function ( key ) {\n\t\t\t\tif ( params[ key ] === null || params[ key ] === undefined ) {\n\t\t\t\t\tdelete uri.query[ key ];\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tmw.hook( 'mw.translate.translationView.stateChange' ).fire( state );\n\n\t\t\tif ( uri.toString() === window.location.href ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( $( '.tux-messagelist' ).length ) {\n\t\t\t\thistory.replaceState( uri, null, uri.toString() );\n\t\t\t} else {\n\t\t\t\twindow.location.href = uri.toString();\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Updates the navigation tabs.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} params Url parameters to update.\n\t\t * @since 2013.05\n\t\t */\n\t\tupdateTabLinks: function ( params ) {\n\t\t\t$( '.tux-tab a' ).each( function () {\n\t\t\t\tvar $a = $( this );\n\t\t\t\tvar uri = new mw.Uri( $a.prop( 'href' ) );\n\t\t\t\turi.extend( params );\n\t\t\t\t$a.prop( 'href', uri.toString() );\n\t\t\t} );\n\t\t}\n\t} );\n\n\tfunction getTranslationStats( language ) {\n\t\treturn mw.translate.loadMessageGroupStatsForItem( state.language, state.group ).then(\n\t\t\tfunction () {\n\t\t\t\tvar statsData = mw.translate.languagestats[ language ] || [];\n\t\t\t\tfor ( var i = 0; i < statsData.length; i++ ) {\n\t\t\t\t\tif ( statsData[ i ].group === state.group ) {\n\t\t\t\t\t\treturn statsData[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn {\n\t\t\t\t\ttotal: 0,\n\t\t\t\t\ttranslated: 0\n\t\t\t\t};\n\t\t\t}\n\t\t);\n\t}\n\n\tfunction getActionSource() {\n\t\tvar uri = new mw.Uri( window.location.href );\n\t\treturn uri.query.action_source || 'direct_open';\n\t}\n\n\tfunction getActualFilter( filter ) {\n\t\tvar realFilters = [ '!ignored' ];\n\t\tvar uri = new mw.Uri( window.location.href );\n\t\tif ( uri.query.optional !== '1' ) {\n\t\t\trealFilters.push( hideOptionalMessages );\n\t\t}\n\t\tif ( filter ) {\n\t\t\trealFilters.push( filter );\n\t\t}\n\n\t\treturn realFilters.join( '|' );\n\t}\n\n\tfunction checkDirty() {\n\t\tif ( mw.translate.isDirty() ) {\n\t\t\t// eslint-disable-next-line no-alert\n\t\t\treturn confirm( mw.msg( 'translate-js-support-unsaved-warning' ) );\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Returns an array of jQuery objects of rows of translated\n\t// and proofread messages in the TUX editors.\n\t// Used several times.\n\tfunction getTranslatedMessages( $translateContainer ) {\n\t\t$translateContainer = $translateContainer || $( '.ext-translate-container' );\n\t\treturn $translateContainer.find( '.tux-message-item' )\n\t\t\t.filter( '.translated, .proofread' );\n\t}\n\n\t/**\n\t * Updates all group specific stuff on the page.\n\t *\n\t * @param {Object} stateInfo Information about current group and language.\n\t * @param {string} stateInfo.group Message group id.\n\t * @param {string} stateInfo.language Language.\n\t */\n\tfunction updateGroupInformation( stateInfo ) {\n\t\tvar props = 'id|priority|prioritylangs|priorityforce|description|label|sourcelanguage|class|subscription';\n\n\t\tmw.translate.recentGroups.append( stateInfo.group );\n\n\t\tmw.translate.getMessageGroup( stateInfo.group, props ).done( function ( group ) {\n\t\t\tupdateDescription( group );\n\t\t\tupdateGroupPriorityWarnings( group, stateInfo.language );\n\t\t\tupdateGroupSubscription( group );\n\t\t} );\n\t}\n\n\tfunction updateDescription( group ) {\n\t\tvar\n\t\t\tapi = new mw.Api(),\n\t\t\t$description = $( '.tux-editor-header .description' );\n\n\t\tif ( group.description === null ) {\n\t\t\t$description.empty();\n\t\t\treturn;\n\t\t}\n\t\tvar description = group.description;\n\t\tif (\n\t\t\tgroup.class === 'WikiPageMessageGroup' &&\n\t\t\tgroup.sourcelanguage !== state.language &&\n\t\t\t// Message documentation does not have a translation page\n\t\t\tstate.language !== mw.config.get( 'wgTranslateDocumentationLanguageCode' )\n\t\t) {\n\t\t\tdescription = mw.msg(\n\t\t\t\t'translate-tag-page-wikipage-desc',\n\t\t\t\t':' + group.label + '/' + state.language,\n\t\t\t\t':' + group.label,\n\t\t\t\t$.uls.data.getAutonym( group.sourcelanguage ),\n\t\t\t\tgroup.sourcelanguage,\n\t\t\t\t$.uls.data.getAutonym( state.language ),\n\t\t\t\tstate.language );\n\t\t}\n\n\t\tapi.parse( description ).done( function ( parsedDescription ) {\n\t\t\t// The parsed text is returned in a <p> tag,\n\t\t\t// so it's removed here.\n\t\t\t$description.html( parsedDescription );\n\t\t} ).fail( function () {\n\t\t\t$description.empty();\n\t\t\tmw.log( 'Error parsing description for group ' + group.id );\n\t\t} );\n\t}\n\n\tfunction updateGroupPriorityWarnings( group, language ) {\n\t\tvar $groupWarning = $( '.tux-editor-header .tux-group-warning' );\n\n\t\tif ( group.priority === 'discouraged' ) {\n\t\t\t$groupWarning.append(\n\t\t\t\t$( '<p>' ).append( $( '<strong>' )\n\t\t\t\t\t.text( mw.message( 'tpt-discouraged-translation-header' ).text() )\n\t\t\t\t),\n\t\t\t\t$( '<p>' ).append( mw.message( 'tpt-discouraged-translation-content' ).parseDom() )\n\t\t\t);\n\t\t}\n\n\t\tvar headerMessage, languagesMessage;\n\t\tif ( !group.prioritylangs && group.priorityforce ) {\n\t\t\theaderMessage = mw.message(\n\t\t\t\t'tpt-discouraged-language-force-header',\n\t\t\t\t$.uls.data.getAutonym( language )\n\t\t\t);\n\t\t\tlanguagesMessage = mw.message( 'tpt-translation-restricted-no-priority-languages-no-reason' );\n\t\t\t$groupWarning.append(\n\t\t\t\t$( '<p>' ).append( $( '<strong>' ).text( headerMessage.text() ) ),\n\t\t\t\t$( '<p>' ).text( languagesMessage.text() )\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !group.prioritylangs || isPriorityLanguage( language, group.prioritylangs ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make a comma-separated list of preferred languages\n\t\tvar $preferredLanguages = $( '<span>' );\n\t\tgroup.prioritylangs.forEach( function ( languageCode, index ) {\n\t\t\t// bidi isolation for language names\n\t\t\t$preferredLanguages.append(\n\t\t\t\t$( '<bdi>' ).text( $.uls.data.getAutonym( languageCode ) )\n\t\t\t);\n\n\t\t\t// Add comma between languages\n\t\t\tif ( index + 1 !== group.prioritylangs.length ) {\n\t\t\t\t$preferredLanguages.append( ', ' );\n\t\t\t}\n\t\t} );\n\n\t\tif ( group.priorityforce ) {\n\t\t\theaderMessage = mw.message(\n\t\t\t\t'tpt-discouraged-language-force-header',\n\t\t\t\t$.uls.data.getAutonym( language )\n\t\t\t);\n\t\t\tlanguagesMessage = mw.message(\n\t\t\t\t'tpt-discouraged-language-force-content',\n\t\t\t\t$preferredLanguages\n\t\t\t);\n\t\t} else {\n\t\t\theaderMessage = mw.message(\n\t\t\t\t'tpt-discouraged-language-header',\n\t\t\t\t$.uls.data.getAutonym( language )\n\t\t\t);\n\t\t\tlanguagesMessage = mw.message(\n\t\t\t\t'tpt-discouraged-language-content',\n\t\t\t\t$preferredLanguages\n\t\t\t);\n\t\t}\n\n\t\t$groupWarning.append(\n\t\t\t$( '<p>' ).append( $( '<strong>' ).text( headerMessage.text() ) ),\n\t\t\t$( '<p>' ).append( languagesMessage.parseDom() )\n\t\t);\n\t}\n\n\tfunction updateGroupSubscription( group ) {\n\t\tif ( mw.config.get( 'wgTranslateEnableMessageGroupSubscription' ) !== true ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar $tuxBreadcrumb = $( '.tux-breadcrumb' );\n\t\tif ( group.subscription === undefined ) {\n\t\t\t$tuxBreadcrumb.find( '.tux-watch-button' ).remove();\n\t\t\treturn;\n\t\t}\n\n\t\tvar buttonMessage = group.subscription ? 'tux-unwatch-group' : 'tux-watch-group';\n\t\tvar watchClass = group.subscription ? 'tux-watch-group--watch' : 'tux-watch-group--unwatch';\n\t\tvar $subscribeButton = $( '<button>' )\n\t\t\t// CSS Classes:\n\t\t\t// * tux-watch-group--watch\n\t\t\t// * tux-watch-group--unwatch\n\t\t\t.addClass( 'mw-ui-button tux-watch-button ' + watchClass )\n\t\t\t.data( 'subscribed', group.subscription )\n\t\t\t.on( 'click', toggleSubscription );\n\n\t\t$subscribeButton.append(\n\t\t\t$( '<span>' ).addClass( 'tux-watch-icon' ),\n\t\t\t$( '<span>' )\n\t\t\t\t.addClass( 'tux-watch-label' )\n\t\t\t\t// * tux-watch-group\n\t\t\t\t// * tux-unwatch-group\n\t\t\t\t.text( mw.msg( buttonMessage ) )\n\t\t);\n\n\t\t$tuxBreadcrumb.find( '.tux-watch-button' ).remove();\n\t\t$tuxBreadcrumb.append( $subscribeButton );\n\t}\n\n\tfunction removeGroupWarnings() {\n\t\tvar $tuxHeader = $( '.tux-editor-header' );\n\t\t$tuxHeader.find( '.tux-group-warning' ).empty();\n\t}\n\n\tfunction isPriorityLanguage( language, priorityLanguages ) {\n\t\t// Don't show priority notice if the language is message documentation.\n\t\tif ( language === mw.config.get( 'wgTranslateDocumentationLanguageCode' ) ) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// If no priority language is set, return early.\n\t\tif ( !priorityLanguages ) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn priorityLanguages.includes( language );\n\t}\n\n\tfunction setupLanguageSelector( $element ) {\n\t\tvar ulsOptions = {\n\t\t\tlanguages: mw.config.get( 'wgTranslateLanguages' ),\n\t\t\tshowRegions: [ 'SP' ].concat( $.fn.lcd.defaults.showRegions ),\n\t\t\tonSelect: function ( languageCode ) {\n\t\t\t\tvar languageDetails = mw.translate.getLanguageDetailsForHtml( languageCode );\n\t\t\t\tmw.translate.changeLanguage( languageCode );\n\t\t\t\t$element\n\t\t\t\t\t.find( '.ext-translate-target-language' )\n\t\t\t\t\t.text( languageDetails.autonym )\n\t\t\t\t\t.prop( {\n\t\t\t\t\t\tlang: languageDetails.code,\n\t\t\t\t\t\tdir: languageDetails.direction\n\t\t\t\t\t} );\n\t\t\t},\n\t\t\tulsPurpose: 'translate-special-translate',\n\t\t\tquickList: function () {\n\t\t\t\treturn mw.uls.getFrequentLanguageList();\n\t\t\t}\n\t\t};\n\n\t\tmw.translate.addExtraLanguagesToLanguageData( ulsOptions.languages, [ 'SP' ] );\n\t\t$element.uls( ulsOptions );\n\t}\n\n\tfunction addTuxGroupWarningContainer() {\n\t\tvar $tuxEditorHeader = $( '.tux-editor-header' );\n\t\tvar $tuxWarning = $tuxEditorHeader.find( 'tux-group-warning' );\n\t\tif ( !$tuxWarning.length ) {\n\t\t\t$tuxWarning = $( '<div>' )\n\t\t\t\t.addClass( 'mw-message-box-warning mw-message-box tux-group-warning twelve column' );\n\t\t\t$tuxEditorHeader.append( $tuxWarning );\n\t\t}\n\t}\n\n\tfunction toggleSubscription() {\n\t\tvar api = new mw.Api();\n\t\tvar $button = $( this );\n\t\t$button.prop( 'disabled', true );\n\n\t\tvar subscriptionStatus = $button.data( 'subscribed' );\n\n\t\tvar params = {\n\t\t\taction: 'messagegroupsubscription',\n\t\t\tgroupId: state.group,\n\t\t\toperation: subscriptionStatus ? 'unsubscribe' : 'subscribe',\n\t\t\tassert: 'user',\n\t\t\tformatversion: 2\n\t\t};\n\n\t\treturn api.postWithToken( 'csrf', params ).then(\n\t\t\tfunction ( response ) {\n\t\t\t\tvar oldSubscriptionStatus = subscriptionStatus;\n\t\t\t\tif ( response.messagegroupsubscription && response.messagegroupsubscription.success === 1 ) {\n\t\t\t\t\tvar buttonMessage = oldSubscriptionStatus ? 'tux-watch-group' : 'tux-unwatch-group';\n\t\t\t\t\tvar watchClass = oldSubscriptionStatus ?\n\t\t\t\t\t\t'tux-watch-group--unwatch' : 'tux-watch-group--watch';\n\t\t\t\t\t$button\n\t\t\t\t\t\t.removeClass( [ 'tux-watch-group--watch', 'tux-watch-group--unwatch' ] )\n\t\t\t\t\t\t// CSS Classes:\n\t\t\t\t\t\t// * tux-watch-group--watch\n\t\t\t\t\t\t// * tux-watch-group--unwatch\n\t\t\t\t\t\t.addClass( watchClass )\n\t\t\t\t\t\t.data( 'subscribed', !oldSubscriptionStatus );\n\n\t\t\t\t\t$button.find( '.tux-watch-label' )\n\t\t\t\t\t\t// * tux-watch-group\n\t\t\t\t\t\t// * tux-unwatch-group\n\t\t\t\t\t\t.text( mw.msg( buttonMessage ) );\n\n\t\t\t\t\tloadWatchedMessageGroups();\n\t\t\t\t} else {\n\t\t\t\t\tmw.notify( mw.msg( 'tux-subscription-error' ) );\n\t\t\t\t}\n\t\t\t},\n\t\t\tfunction ( error ) {\n\t\t\t\tmw.notify( mw.msg( 'tux-subscription-error' ) );\n\t\t\t\tmw.log.error( 'messagegroupsubscription: Failed', error, params );\n\t\t\t}\n\t\t).always( function () {\n\t\t\t$button.prop( 'disabled', false );\n\t\t} );\n\t}\n\n\tfunction loadWatchedMessageGroups() {\n\t\tif ( mw.config.get( 'wgTranslateEnableMessageGroupSubscription' ) !== true ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar api = new mw.Api();\n\t\tvar params = {\n\t\t\taction: 'query',\n\t\t\tlist: 'messagegroupsubscription',\n\t\t\tformatversion: 2\n\t\t};\n\n\t\treturn api.get( params ).then(\n\t\t\tfunction ( response ) {\n\t\t\t\tstate.groupSelector.setWatchedGroups( response.query.messagegroupsubscription );\n\t\t\t},\n\t\t\tfunction ( error ) {\n\t\t\t\tmw.log.error( 'messagegroupsubscription: Failed to fetch user subscriptions', error, params );\n\t\t\t}\n\t\t);\n\t}\n\n\tfunction showAggregateSubgroupCount() {\n\t\tvar $groupBreadcrumbs = $( '.tux-breadcrumb .grouptitle' );\n\t\tvar $selectedGroup = $groupBreadcrumbs.last();\n\t\tvar groupCounts = $selectedGroup.data( 'msggroup-subgroup-count' );\n\t\tif ( groupCounts === undefined ) {\n\t\t\t$groupBreadcrumbs\n\t\t\t\t.find( '.tux-breadcrumb__item--aggregate-count' )\n\t\t\t\t.remove();\n\t\t} else {\n\t\t\tvar subGroups = mw.msg( 'translate-msggroupselector-view-subprojects', groupCounts );\n\t\t\t$selectedGroup.append(\n\t\t\t\t$( '<span>' ).append( mw.message( 'parentheses', $( '<span>' ).text( subGroups ) ).parse() )\n\t\t\t\t\t.addClass( 'tux-breadcrumb__item--aggregate-count' )\n\t\t\t);\n\t\t}\n\t}\n\n\tfunction trackUserExit() {\n\t\tvar timeout;\n\t\tvar timeoutDuration = 30 * 60 * 1000; // 30 minutes in milliseconds\n\n\t\tfunction resetTimer() {\n\t\t\t// Clear the existing timeout\n\t\t\tclearTimeout( timeout );\n\t\t\ttimeout = setTimeout( logInactivity, timeoutDuration );\n\t\t}\n\n\t\tfunction logInactivity() {\n\t\t\tlogger.logEvent( 'exit', 'inactivity' );\n\t\t}\n\n\t\tfunction throttle( func, delay ) {\n\t\t\tvar lastCall = 0;\n\n\t\t\treturn function () {\n\t\t\t\tvar now = Date.now();\n\t\t\t\tif ( now - lastCall >= delay ) {\n\t\t\t\t\tlastCall = now;\n\t\t\t\t\tfunc();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t// Create a throttled version of resetTimer\n\t\tvar throttledResetTimer = throttle( resetTimer, 3000 ); // 3 seconds between resets\n\t\t// Add event listeners with throttled reset\n\t\tvar events = [\n\t\t\t'mousemove',\n\t\t\t'mousedown',\n\t\t\t'touchstart',\n\t\t\t'touchmove',\n\t\t\t'click',\n\t\t\t'keydown',\n\t\t\t'scroll',\n\t\t\t'wheel'\n\t\t];\n\n\t\tevents.forEach( function ( eventName ) {\n\t\t\twindow.addEventListener( eventName, throttledResetTimer, true );\n\t\t} );\n\n\t\tresetTimer(); // Initial timer setup\n\n\t\twindow.addEventListener( 'unload', function () {\n\t\t\tlogger.logEvent( 'exit', 'browser_tab_close' );\n\t\t} );\n\t}\n\n\t$( function () {\n\t\tvar $messageList = $( '.tux-messagelist' );\n\t\tstate.group = $( '.tux-messagetable-loader' ).data( 'messagegroup' );\n\t\tstate.language = $messageList.data( 'targetlangcode' );\n\t\tvar uri = new mw.Uri( window.location.href );\n\n\t\tif ( $messageList.length ) {\n\t\t\t$messageList.messagetable();\n\t\t\tstate.messageList = $messageList.data( 'messagetable' );\n\n\t\t\tvar filter = uri.query.filter;\n\t\t\tvar offset = uri.query.showMessage;\n\t\t\tvar limit;\n\t\t\tif ( offset ) {\n\t\t\t\tlimit = uri.query.limit || 1;\n\t\t\t\t// Default to no filters\n\t\t\t\tfilter = filter || '';\n\t\t\t}\n\n\t\t\tif ( filter === undefined ) {\n\t\t\t\tfilter = '!translated';\n\t\t\t}\n\n\t\t\t$( '.tux-message-selector li' ).each( function () {\n\t\t\t\tvar $this = $( this );\n\n\t\t\t\tif ( $this.data( 'filter' ) === filter ) {\n\t\t\t\t\t$this.addClass( 'selected' );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tvar newUrlParams = {\n\t\t\t\tgroup: state.group,\n\t\t\t\tlanguage: state.language,\n\t\t\t\tfilter: filter,\n\t\t\t\tshowMessage: offset\n\t\t\t};\n\t\t\tif ( offset ) {\n\t\t\t\tnewUrlParams.optional = 1;\n\t\t\t}\n\t\t\tmw.translate.changeUrl( newUrlParams );\n\n\t\t\t// Start loading messages\n\t\t\tvar actualFilter = getActualFilter( filter );\n\t\t\tstate.messageList.changeSettings( {\n\t\t\t\tgroup: state.group,\n\t\t\t\tlanguage: state.language,\n\t\t\t\toffset: offset,\n\t\t\t\tlimit: limit,\n\t\t\t\tfilter: actualFilter\n\t\t\t} );\n\n\t\t\tif ( !actualFilter.includes( hideOptionalMessages ) ) {\n\t\t\t\t$( '#tux-option-optional' ).prop( 'checked', true );\n\t\t\t}\n\t\t}\n\n\t\taddTuxGroupWarningContainer();\n\n\t\tvar position = {\n\t\t\tmy: 'left top',\n\t\t\tat: 'left-10 bottom+5'\n\t\t};\n\t\tif ( $( document.body ).hasClass( 'rtl' ) ) {\n\t\t\tposition = {\n\t\t\t\tmy: 'right top',\n\t\t\t\tat: 'right+10 bottom+5'\n\t\t\t};\n\t\t}\n\n\t\t$( '.tux-breadcrumb__item--aggregate' ).msggroupselector( {\n\t\t\tonSelect: mw.translate.changeGroup,\n\t\t\tlanguage: state.language,\n\t\t\tposition: position,\n\t\t\trecent: mw.translate.recentGroups.get(),\n\t\t\tshowWatched: mw.config.get( 'wgTranslateEnableMessageGroupSubscription' ) || false,\n\t\t\tmenuClass: 'tux-groupselector-tpt'\n\t\t} );\n\n\t\tstate.groupSelector = $( '.tux-breadcrumb__item--aggregate' ).data( 'msggroupselector' );\n\t\tloadWatchedMessageGroups();\n\n\t\tupdateGroupInformation( state );\n\n\t\tshowAggregateSubgroupCount();\n\n\t\t$( '.ext-translate-language-selector .uls' ).one( 'click', function () {\n\t\t\tvar $target = $( this );\n\t\t\tmw.loader.using( 'ext.uls.mediawiki' ).done( function () {\n\t\t\t\tsetupLanguageSelector( $target );\n\t\t\t\t$target.trigger( 'click' );\n\t\t\t} );\n\t\t} ).on( 'keypress', function () {\n\t\t\t$( this ).trigger( 'click' );\n\t\t} );\n\n\t\tif ( $.fn.translateeditor ) {\n\t\t\t// New translation editor\n\t\t\t$( '.tux-message' ).translateeditor();\n\t\t}\n\n\t\tvar $translateContainer = $( '.ext-translate-container' );\n\n\t\tif ( mw.translate.canProofread() ) {\n\t\t\t$translateContainer.find( '.proofread-mode-button' ).removeClass( 'hide' );\n\t\t}\n\n\t\tvar $hideTranslatedButton = $translateContainer.find( '.tux-editor-clear-translated' );\n\t\t$hideTranslatedButton\n\t\t\t.prop( 'disabled', !getTranslatedMessages( $translateContainer ).length )\n\t\t\t.on( 'click', function () {\n\t\t\t\tgetTranslatedMessages( $translateContainer ).remove();\n\t\t\t\t$( this ).prop( 'disabled', true );\n\t\t\t} );\n\n\t\t// Message filter click handler\n\t\t$translateContainer.find( '.row.tux-message-selector > li' ).on( 'click', function () {\n\t\t\tvar $this = $( this );\n\n\t\t\tif ( $this.hasClass( 'more' ) ) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tvar newFilter = $this.data( 'filter' );\n\n\t\t\t// Remove the 'selected' class from all the items.\n\t\t\t// Some of them could have been moved to under the \"more\" menu,\n\t\t\t// so everything under .row.tux-message-selector is searched.\n\t\t\t$translateContainer.find( '.row.tux-message-selector .selected' )\n\t\t\t\t.removeClass( 'selected' );\n\t\t\tmw.translate.changeFilter( newFilter );\n\t\t\t$this.addClass( 'selected' );\n\n\t\t\tvar translated = newFilter !== '!translated';\n\t\t\t// TODO: this could should be in messagetable\n\t\t\t$hideTranslatedButton.toggleClass( 'hide', translated )\n\t\t\t\t.prop( 'disabled', !translated && !getTranslatedMessages( $translateContainer ).length );\n\n\t\t\treturn false;\n\t\t} );\n\n\t\t// TODO: this could should be in messagetable\n\t\t$hideTranslatedButton\n\t\t\t.toggleClass( 'hide', $( '.tux-messagetable-loader' ).data( 'filter' ) !== '!translated' );\n\n\t\t// Don't let clicking the items in the \"more\" menu\n\t\t// affect the rest of it.\n\t\t$( '.row.tux-message-selector .more ul' )\n\t\t\t.on( 'click', function ( e ) {\n\t\t\t\te.stopPropagation();\n\t\t\t} );\n\n\t\t$( '#tux-option-optional' ).on( 'change', function () {\n\t\t\tvar currentUri = new mw.Uri( window.location.href ),\n\t\t\t\tchecked = $( this ).prop( 'checked' );\n\n\t\t\tmw.translate.changeUrl( { optional: checked ? 1 : 0 } );\n\t\t\tmw.translate.changeFilter( currentUri.query.filter );\n\t\t} );\n\n\t\tgetTranslationStats( state.language ).done( function ( stats ) {\n\t\t\tlogger.logEvent(\n\t\t\t\t'interface_open',\n\t\t\t\tnull,\n\t\t\t\tgetActionSource(),\n\t\t\t\t{\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tsource_language: $messageList.data( 'sourcelangcode' ),\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\ttarget_language: state.language,\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tsource_title: uri.query.group,\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\tsource_type: 'page',\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\ttranslatable_count: stats.total,\n\t\t\t\t\t// eslint-disable-next-line camelcase\n\t\t\t\t\ttranslated_count: stats.translated\n\t\t\t\t}\n\t\t\t);\n\t\t} );\n\t} );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.special.translationstats.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.statsbar.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":33,"column":4,"nodeType":"CallExpression","endLine":33,"endColumn":53}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * Translate language statistics bar - jQuery plugin.\n *\n * @author Niklas Laxström\n * @author Santhosh Thottingal\n * @license GPL-2.0-or-later\n * @since 2012-11-30\n */\n\n/*\n * Usage:\n *     $( '<div>' ).languagestatsbar( {\n *         language: 'fi',\n *         group: 'core'\n *     } );\n * The status bar will be rendered to the newly created div. Or use any container.\n */\n( function () {\n\t'use strict';\n\n\tvar LanguageStatsBar = function ( container, options ) {\n\t\tthis.$container = $( container );\n\t\tthis.group = options.group;\n\t\tthis.language = options.language;\n\t\tthis.onlyLoadCurrentGroupData = options.onlyLoadCurrentGroupData;\n\t\tthis.$statsBar = null;\n\t\tthis.elements = null;\n\t\tthis.init();\n\t};\n\n\tLanguageStatsBar.prototype = {\n\t\tinit: function () {\n\t\t\tthis.loadStats().done( this.render.bind( this ) );\n\t\t},\n\n\t\t/**\n\t\t * Listen for the change events and update the statsbar\n\t\t */\n\t\tlisten: function () {\n\t\t\tvar statsbar = this;\n\t\t\tstatsbar.$statsBar.on( 'change', function ( event, to, from ) {\n\t\t\t\t// This updates the value in mw.translate.languagestats as a reference to\n\t\t\t\t// the object is returned here.\n\t\t\t\tvar groupLanguageStats = statsbar.getGroupStatsWithFallback();\n\t\t\t\t// Changing a proofread message does not create a new translation\n\t\t\t\tif ( to === 'translated' && from !== 'proofread' ) {\n\t\t\t\t\tgroupLanguageStats.translated++;\n\t\t\t\t}\n\t\t\t\tif ( to === 'proofread' ) {\n\t\t\t\t\tgroupLanguageStats.proofread++;\n\t\t\t\t}\n\t\t\t\tif ( to === 'fuzzy' ) {\n\t\t\t\t\tgroupLanguageStats.fuzzy++;\n\t\t\t\t}\n\n\t\t\t\tif ( from === 'fuzzy' ) {\n\t\t\t\t\tgroupLanguageStats.fuzzy--;\n\t\t\t\t}\n\t\t\t\tif ( from === 'proofread' ) {\n\t\t\t\t\tgroupLanguageStats.proofread--;\n\t\t\t\t}\n\t\t\t\t// Proofreading a message does not remove translation\n\t\t\t\tif ( from === 'translated' && to !== 'proofread' ) {\n\t\t\t\t\tgroupLanguageStats.translated--;\n\t\t\t\t}\n\n\t\t\t\t// Update the stats bar\n\t\t\t\tstatsbar.update();\n\t\t\t} );\n\n\t\t\tstatsbar.$container.on( {\n\t\t\t\tmouseenter: function () {\n\t\t\t\t\tstatsbar.elements.$info.removeClass( 'hide' );\n\t\t\t\t},\n\t\t\t\tmouseleave: function () {\n\t\t\t\t\tstatsbar.elements.$info.addClass( 'hide' );\n\t\t\t\t}\n\t\t\t} );\n\t\t},\n\n\t\trender: function () {\n\t\t\tthis.$statsBar = $( '<div>' )\n\t\t\t\t.addClass( 'tux-statsbar' )\n\t\t\t\t.data( 'group', this.group );\n\n\t\t\tthis.elements = {\n\t\t\t\t$proofread: $( '<span>' ).addClass( 'tux-proofread' ),\n\t\t\t\t$translated: $( '<span>' ).addClass( 'tux-translated' ),\n\t\t\t\t$fuzzy: $( '<span>' ).addClass( 'tux-fuzzy' ),\n\t\t\t\t$untranslated: $( '<span>' ).addClass( 'tux-untranslated' ),\n\t\t\t\t$info: $( '<div>' ).addClass( 'tux-statsbar-info hide' )\n\t\t\t};\n\n\t\t\tthis.update();\n\t\t\tthis.$statsBar.append( [\n\t\t\t\t// Append needs an array instead of an object\n\t\t\t\tthis.elements.$proofread,\n\t\t\t\tthis.elements.$translated,\n\t\t\t\tthis.elements.$fuzzy,\n\t\t\t\tthis.elements.$untranslated,\n\t\t\t\tthis.elements.$info\n\t\t\t] );\n\t\t\tthis.$container.append( this.$statsBar );\n\n\t\t\tthis.listen();\n\t\t},\n\n\t\tupdate: function () {\n\t\t\tvar stats = this.getGroupStatsWithFallback();\n\n\t\t\tvar proofread = 100 * stats.proofread / stats.total;\n\t\t\t// Proofread messages are also translated, so remove those for\n\t\t\t// the bar showing only translated count.\n\t\t\tvar translated = stats.translated - stats.proofread;\n\t\t\ttranslated = 100 * translated / stats.total;\n\t\t\tvar fuzzy = 100 * stats.fuzzy / stats.total;\n\t\t\tvar untranslated = 100 - proofread - translated - fuzzy;\n\n\t\t\tthis.elements.$proofread[ 0 ].style.width = proofread + '%';\n\t\t\tthis.elements.$translated[ 0 ].style.width = translated + '%';\n\t\t\tthis.elements.$fuzzy[ 0 ].style.width = fuzzy + '%';\n\t\t\tthis.elements.$untranslated[ 0 ].style.width = untranslated + '%';\n\n\t\t\ttranslated = !translated ? 0 : translated + proofread;\n\t\t\tproofread = !proofread ? 0 : proofread;\n\n\t\t\tif ( fuzzy ) {\n\t\t\t\tthis.elements.$info\n\t\t\t\t\t.text( mw.msg( 'translate-statsbar-tooltip-with-fuzzy',\n\t\t\t\t\t\ttranslated.toFixed(), proofread.toFixed(),\n\t\t\t\t\t\tfuzzy.toFixed() ) );\n\t\t\t} else {\n\t\t\t\tthis.elements.$info\n\t\t\t\t\t.text( mw.msg( 'translate-statsbar-tooltip',\n\t\t\t\t\t\ttranslated.toFixed(), proofread.toFixed() ) );\n\t\t\t}\n\t\t},\n\n\t\tgetGroupStatsWithFallback: function () {\n\t\t\tvar statsData = mw.translate.languagestats[ this.language ] || [];\n\t\t\tfor ( var i = 0; i < statsData.length; i++ ) {\n\t\t\t\tif ( statsData[ i ].group === this.group ) {\n\t\t\t\t\treturn statsData[ i ];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn this.getEmptyStats();\n\t\t},\n\n\t\tloadStats: function () {\n\t\t\tif ( this.onlyLoadCurrentGroupData ) {\n\t\t\t\treturn mw.translate.loadMessageGroupStatsForItem( this.language, this.group );\n\t\t\t} else {\n\t\t\t\treturn mw.translate.loadMessageGroupStatsForLanguage( this.language );\n\t\t\t}\n\t\t},\n\n\t\tgetEmptyStats: function () {\n\t\t\treturn {\n\t\t\t\tproofread: 0,\n\t\t\t\ttotal: 0,\n\t\t\t\tfuzzy: 0,\n\t\t\t\ttranslated: 0\n\t\t\t};\n\t\t}\n\t};\n\n\t/*\n\t * languagestatsbar PLUGIN DEFINITION\n\t */\n\n\t$.fn.languagestatsbar = function ( options ) {\n\t\treturn this.each( function () {\n\t\t\tvar $this = $( this ),\n\t\t\t\tdata = $this.data( 'languagestatsbar' );\n\n\t\t\tif ( !data ) {\n\t\t\t\t$this.data( 'languagestatsbar', new LanguageStatsBar( this, options ) );\n\t\t\t}\n\t\t} );\n\t};\n\n\t$.fn.languagestatsbar.Constructor = LanguageStatsBar;\n\n\tmw.translate = mw.translate || {};\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.storage.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.translationstats.embedded.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.translationstats.graphbuilder.js","messages":[{"ruleId":"jsdoc/require-returns","severity":1,"message":"Missing JSDoc @return declaration.","line":69,"column":3,"nodeType":"Block","endLine":72,"endColumn":6},{"ruleId":"jsdoc/require-param-type","severity":1,"message":"Missing JSDoc @param \"options\" type.","line":70,"column":1,"nodeType":"Block","endLine":70,"endColumn":1},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":85,"column":11,"nodeType":"CallExpression","endLine":92,"endColumn":7}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * Graph component to display translation stats using ChartJS\n * @license GPL-2.0-or-later\n */\n\n( function () {\n\t'use strict';\n\tvar graphInfo = {\n\t\t\tedits: mw.msg( 'translate-statsf-count-edits' ),\n\t\t\tusers: mw.msg( 'translate-statsf-count-users' ),\n\t\t\tregistrations: mw.msg( 'translate-statsf-count-registrations' ),\n\t\t\treviews: mw.msg( 'translate-statsf-count-reviews' ),\n\t\t\treviewers: mw.msg( 'translate-statsf-count-reviewers' )\n\t\t}, granularityInfo = {\n\t\t\tyears: mw.msg( 'translate-statsf-scale-years' ),\n\t\t\tmonths: mw.msg( 'translate-statsf-scale-months' ),\n\t\t\tweeks: mw.msg( 'translate-statsf-scale-weeks' ),\n\t\t\tdays: mw.msg( 'translate-statsf-scale-days' ),\n\t\t\thours: mw.msg( 'translate-statsf-scale-hours' )\n\t\t}, graphColors = [\n\t\t\t'skyblue', 'green', 'orange', 'blue', 'red', 'darkgreen', 'purple', 'peru',\n\t\t\t'cyan', 'salmon', 'slateblue', 'yellowgreen', 'magenta', 'aquamarine', 'gold', 'violet'\n\t\t],\n\t\tGraphBuilder;\n\n\t/**\n\t * Used to display translation stats graph. Each instance of this class manages one\n\t * instance of the graph.\n\t *\n\t * @internal\n\t * @param {Object} $graphContainer The title of the page including language code\n\t *   to store the translation.\n\t * @param {Object} graphOptions Graph options, current only processes the width and height.\n\t * @return {Object} Instance of the graph builder\n\t */\n\tGraphBuilder = function ( $graphContainer, graphOptions ) {\n\t\tvar $graphElement = $( '<canvas>' )\n\t\t\t\t.attr( 'class', 'mw-translate-translationstats-graph' )\n\t\t\t\t.attr( 'role', 'img' )\n\t\t\t\t.attr( 'tabindex', 0 )\n\t\t\t\t.text( mw.msg( 'translate-statsf-graph-alt-text-info' ) ),\n\t\t\t$graphWrapper = $( '<div>' )\n\t\t\t\t.attr( 'class', 'mw-translationstats-graph-container' ),\n\t\t\t$loadingElement = $( '<div>' )\n\t\t\t\t.attr( 'class', 'tux-loading-indicator tux-loading-indicator--centered' ),\n\t\t\t$errorElement = $( '<div>' )\n\t\t\t\t.attr( 'class', 'mw-translate-error-container' ),\n\t\t\t$tableElement = $( '<table>' )\n\t\t\t\t.addClass( 'wikitable mw-translate-translationstats-table' )\n\t\t\t\t.attr( 'tabindex', 0 )\n\t\t\t\t.attr(\n\t\t\t\t\t'summary', mw.msg( 'translate-statsf-alt-text' )\n\t\t\t\t),\n\t\t\tlineChart;\n\n\t\t$graphWrapper\n\t\t\t.width( graphOptions && graphOptions.width )\n\t\t\t.height( graphOptions && graphOptions.height );\n\n\t\t// Set the container height and width if passed.\n\t\t$graphContainer.append( [\n\t\t\t$graphWrapper,\n\t\t\t$loadingElement,\n\t\t\t$errorElement\n\t\t] );\n\n\t\t$graphWrapper.append( $graphElement );\n\n\t\t/**\n\t\t * @param options\n\t\t * @internal\n\t\t */\n\t\tfunction display( options ) {\n\t\t\tif ( lineChart ) {\n\t\t\t\tcleanup();\n\t\t\t}\n\n\t\t\t// Set the appropriate height and width and display the loader.\n\t\t\t$graphWrapper\n\t\t\t\t.width( options.width )\n\t\t\t\t.height( options.height );\n\n\t\t\tshowLoading();\n\n\t\t\treturn getData( options ).then( function ( graphData ) {\n\t\t\t\t// Hide the loader before displaying the data.\n\t\t\t\tshowData( graphData, options );\n\t\t\t} ).fail( function ( errorCode, results ) {\n\t\t\t\tvar errorInfo = results && results.error ? results.error.info :\n\t\t\t\t\tmw.msg( 'translate-statsf-unknown-error' );\n\t\t\t\tdisplayError( mw.msg( 'translate-statsf-error-message', errorInfo ) );\n\t\t\t} ).always( function () {\n\t\t\t\thideLoading();\n\t\t\t} );\n\t\t}\n\n\t\tfunction showData( apiResponse, options ) {\n\t\t\tvar graphData = getAxesLabelsAndData( apiResponse.data ),\n\t\t\t\tgraphDatasets = [],\n\t\t\t\tdatasetLabels = apiResponse.labels;\n\n\t\t\tif ( graphData.data.length ) {\n\t\t\t\tgraphData.data.forEach( function ( dataset, datasetIndex ) {\n\t\t\t\t\tvar graphDataset = {\n\t\t\t\t\t\tdata: dataset,\n\t\t\t\t\t\tfill: false,\n\t\t\t\t\t\tborderColor: getLineColor( datasetIndex )\n\t\t\t\t\t};\n\n\t\t\t\t\tif ( datasetLabels[ datasetIndex ] ) {\n\t\t\t\t\t\tgraphDataset.label = datasetLabels[ datasetIndex ];\n\t\t\t\t\t}\n\n\t\t\t\t\tgraphDatasets.push( graphDataset );\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\tlineChart = new Chart( $graphElement, {\n\t\t\t\ttype: 'line',\n\t\t\t\tdata: {\n\t\t\t\t\tlabels: graphData.axesLabels,\n\t\t\t\t\tdatasets: graphDatasets\n\t\t\t\t},\n\t\t\t\toptions: {\n\t\t\t\t\tmaintainAspectRatio: false,\n\t\t\t\t\tlegend: {\n\t\t\t\t\t\tdisplay: datasetLabels.length !== 0\n\t\t\t\t\t},\n\t\t\t\t\tscales: {\n\t\t\t\t\t\tyAxes: [ {\n\t\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\tlabelString: getXAxesLabel( options.measure )\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\t\tbeginAtZero: true,\n\t\t\t\t\t\t\t\tprecision: 0,\n\t\t\t\t\t\t\t\tcallback: function ( value ) {\n\t\t\t\t\t\t\t\t\treturn mw.language.convertNumber( Number( value ) );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} ],\n\t\t\t\t\t\txAxes: [ {\n\t\t\t\t\t\t\tscaleLabel: {\n\t\t\t\t\t\t\t\tdisplay: true,\n\t\t\t\t\t\t\t\tlabelString: getYAxesLabel( options.granularity )\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tticks: {\n\t\t\t\t\t\t\t\tmaxTicksLimit: 15\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tgridLines: {\n\t\t\t\t\t\t\t\tdisplay: false\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} ]\n\t\t\t\t\t},\n\t\t\t\t\ttooltips: {\n\t\t\t\t\t\tcallbacks: {\n\t\t\t\t\t\t\tlabel: function ( tooltipItem, data ) {\n\t\t\t\t\t\t\t\tvar convertedValue = mw.language.convertNumber( Number( tooltipItem.yLabel ) ),\n\t\t\t\t\t\t\t\t\tlabel = data.datasets[ tooltipItem.datasetIndex ].label;\n\n\t\t\t\t\t\t\t\tif ( label ) {\n\t\t\t\t\t\t\t\t\treturn label + ': ' + convertedValue;\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn convertedValue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t// Generate table inside the canvas element to improve accessibility.\n\t\t\tshowTable( graphData, datasetLabels, options );\n\t\t}\n\n\t\tfunction getAxesLabelsAndData( jsonGraphData ) {\n\t\t\tvar labels = [], graphData = [],\n\t\t\t\tlabelIndex = 0,\n\t\t\t\tmaxValue = 0, minValue = 0;\n\n\t\t\tfor ( var labelProp in jsonGraphData ) {\n\t\t\t\tif ( !labels.includes( labelProp ) ) {\n\t\t\t\t\tlabels.push( labelProp );\n\t\t\t\t}\n\n\t\t\t\tvar labelData = jsonGraphData[ labelProp ];\n\n\t\t\t\tfor ( var i = 0; i < labelData.length; ++i ) {\n\t\t\t\t\tif ( !graphData[ i ] ) {\n\t\t\t\t\t\tgraphData[ i ] = [];\n\t\t\t\t\t}\n\n\t\t\t\t\tvar currentValue = labelData[ i ];\n\t\t\t\t\tgraphData[ i ][ labelIndex ] = currentValue;\n\t\t\t\t\tif ( currentValue < minValue ) {\n\t\t\t\t\t\tminValue = currentValue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( currentValue > maxValue ) {\n\t\t\t\t\t\tmaxValue = currentValue;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t++labelIndex;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\taxesLabels: labels,\n\t\t\t\tdata: graphData,\n\t\t\t\tmax: maxValue,\n\t\t\t\tmin: minValue\n\t\t\t};\n\t\t}\n\n\t\tfunction getXAxesLabel( measure ) {\n\t\t\treturn graphInfo[ measure ];\n\t\t}\n\n\t\tfunction getYAxesLabel( granularity ) {\n\t\t\treturn granularityInfo[ granularity ];\n\t\t}\n\n\t\tfunction getData( filterOptions ) {\n\t\t\tvar api = new mw.Api(),\n\t\t\t\tapiParams = {\n\t\t\t\t\taction: 'translationstats',\n\t\t\t\t\tcount: filterOptions.measure,\n\t\t\t\t\tdays: filterOptions.days,\n\t\t\t\t\tstart: filterOptions.start || null,\n\t\t\t\t\tscale: filterOptions.granularity,\n\t\t\t\t\tgroup: filterOptions.group,\n\t\t\t\t\tlanguage: filterOptions.language,\n\t\t\t\t\tformatversion: 2\n\t\t\t\t};\n\n\t\t\t// Remove null or empty array from request object\n\t\t\tObject.keys( apiParams ).forEach( function ( apiParamKey ) {\n\t\t\t\tvar apiParamValue = apiParams[ apiParamKey ];\n\t\t\t\tif (\n\t\t\t\t\tapiParamValue === null ||\n\t\t\t\t\t\t( Array.isArray( apiParamValue ) && apiParamValue.length === 0 )\n\t\t\t\t) {\n\t\t\t\t\tdelete apiParams[ apiParamKey ];\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\treturn api.get( apiParams ).then( function ( result ) {\n\t\t\t\treturn result.translationstats;\n\t\t\t} );\n\t\t}\n\n\t\tfunction getLineColor( index ) {\n\t\t\tvar colorIndex = index % graphColors.length,\n\t\t\t\tcolorName = graphColors[ colorIndex ];\n\t\t\treturn colorName;\n\t\t}\n\n\t\tfunction displayError( errorMessage ) {\n\t\t\t$errorElement.text( errorMessage );\n\t\t\t$graphContainer.addClass( 'mw-translate-has-error' )\n\t\t\t\t.height( 'auto' );\n\t\t}\n\n\t\t/** @internal */\n\t\tfunction showLoading() {\n\t\t\t// show loading, and hide error messages.\n\t\t\t$graphContainer.addClass( 'mw-translate-loading' )\n\t\t\t\t.removeClass( 'mw-translate-has-error' );\n\t\t}\n\n\t\tfunction hideLoading() {\n\t\t\t$graphContainer.removeClass( 'mw-translate-loading' );\n\t\t}\n\n\t\tfunction showTable( graphData, datasetLabels, options ) {\n\t\t\t$tableElement\n\t\t\t\t.append(\n\t\t\t\t\t$( '<caption>' ).text( getGraphSummary( options ) )\n\t\t\t\t)\n\t\t\t\t.append( getTableHead( datasetLabels, options ) )\n\t\t\t\t.append( getTableBody( graphData ) );\n\n\t\t\t$graphContainer.append( $tableElement );\n\t\t}\n\n\t\tfunction getTableHead( datasetLabels, options ) {\n\t\t\tvar $tableHead = $( '<thead>' ),\n\t\t\t\t$tableHeadRow = $( '<tr>' ),\n\t\t\t\ti = 0;\n\n\t\t\t$tableHeadRow.append( $( '<th>' ).text( getYAxesLabel( options.granularity ) ) );\n\n\t\t\tif ( datasetLabels && datasetLabels.length ) {\n\t\t\t\tfor ( ; i < datasetLabels.length; ++i ) {\n\t\t\t\t\t$tableHeadRow.append( $( '<th>' ).text( datasetLabels[ i ] ) );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$tableHeadRow.append( $( '<th>' ).text( getXAxesLabel( options.measure ) ) );\n\t\t\t}\n\n\t\t\treturn $tableHead.append( $tableHeadRow );\n\t\t}\n\n\t\tfunction getTableBody( graphData ) {\n\t\t\tvar $tbody = $( '<tbody>' );\n\n\t\t\tfor ( var scaleIndex = 0; scaleIndex < graphData.axesLabels.length; scaleIndex++ ) {\n\t\t\t\tvar $tBodyRow = $( '<tr>' )\n\t\t\t\t\t.append( $( '<td>' ).text( graphData.axesLabels[ scaleIndex ] ) );\n\n\t\t\t\tfor ( var datasetIndex = 0; datasetIndex < graphData.data.length; datasetIndex++ ) {\n\t\t\t\t\tvar columnValue = '';\n\t\t\t\t\tif (\n\t\t\t\t\t\tgraphData.data[ datasetIndex ] &&\n\t\t\t\t\t\tgraphData.data[ datasetIndex ][ scaleIndex ] !== undefined\n\t\t\t\t\t) {\n\t\t\t\t\t\tcolumnValue =\n\t\t\t\t\t\t\tmw.language.convertNumber(\n\t\t\t\t\t\t\t\tNumber( graphData.data[ datasetIndex ][ scaleIndex ] )\n\t\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\t$tBodyRow.append( $( '<td>' ).text( columnValue ) );\n\t\t\t\t}\n\n\t\t\t\t$tbody.append( $tBodyRow );\n\t\t\t}\n\n\t\t\treturn $tbody;\n\t\t}\n\n\t\tfunction cleanup() {\n\t\t\tlineChart.destroy();\n\t\t\t$tableElement.remove();\n\t\t}\n\n\t\tfunction getGraphSummary( options ) {\n\t\t\treturn getXAxesLabel( options.measure ) + ' / ' +\n\t\t\t\tgetYAxesLabel( options.granularity );\n\t\t}\n\n\t\treturn {\n\t\t\tdisplay: display,\n\t\t\tshowLoading: showLoading\n\t\t};\n\t};\n\n\tmw.translate = mw.translate || {};\n\tmw.translate.TranslationStatsGraphBuilder = mw.translate.TranslationStatsGraphBuilder || GraphBuilder;\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/ext.translate.workflowselector.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":52,"column":4,"nodeType":"CallExpression","endLine":56,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":146,"column":5,"nodeType":"CallExpression","endLine":149,"endColumn":9},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":146,"column":5,"nodeType":"CallExpression","endLine":153,"endColumn":9}],"suppressedMessages":[{"ruleId":"no-alert","severity":2,"message":"Unexpected alert.","line":152,"column":7,"nodeType":"CallExpression","messageId":"unexpected","endLine":152,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * A jQuery plugin which handles the display and change of message group\n * workflow states.\n *\n * @author Niklas Laxström\n * @license GPL-2.0-or-later\n */\n\n( function () {\n\t'use strict';\n\n\t/**\n\t * @private\n\t * @param {jQuery} container\n\t */\n\tfunction WorkflowSelector( container ) {\n\t\tthis.$container = $( container );\n\n\t\t// Hide the workflow selector when clicking outside of it\n\t\t$( document.documentElement ).on( 'click', function ( e ) {\n\t\t\tif ( !e.isDefaultPrevented() ) {\n\t\t\t\t$( container )\n\t\t\t\t\t.find( '.tux-workflow-status-selector' )\n\t\t\t\t\t.addClass( 'hide' );\n\t\t\t}\n\t\t} );\n\t}\n\n\tWorkflowSelector.prototype = {\n\t\t/**\n\t\t * Displays the current state and selector if relevant.\n\t\t *\n\t\t * @private\n\t\t * @param {string} groupId\n\t\t * @param {string} language\n\t\t * @param {string} state\n\t\t */\n\t\treceiveState: function ( groupId, language, state ) {\n\t\t\tvar instance = this;\n\n\t\t\tinstance.currentState = state;\n\t\t\tinstance.language = language;\n\n\t\t\t// Only if groupId changes, fetch the new states\n\t\t\tif ( instance.groupId === groupId ) {\n\t\t\t\t// But update the display\n\t\t\t\tinstance.display();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tinstance.groupId = groupId;\n\t\t\tmw.translate.getMessageGroup( groupId, 'workflowstates' )\n\t\t\t\t.done( function ( group ) {\n\t\t\t\t\tinstance.states = group.workflowstates;\n\t\t\t\t\tinstance.display();\n\t\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Calls the WebApi to change the state to a new value.\n\t\t *\n\t\t * @private\n\t\t * @param {string} state\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tchangeState: function ( state ) {\n\t\t\tvar api = new mw.Api();\n\n\t\t\tvar params = {\n\t\t\t\taction: 'groupreview',\n\t\t\t\tgroup: this.groupId,\n\t\t\t\tlanguage: this.language,\n\t\t\t\tstate: state\n\t\t\t};\n\n\t\t\treturn api.postWithToken( 'csrf', params );\n\t\t},\n\n\t\t/**\n\t\t * Get the text which says that the current state is X.\n\t\t *\n\t\t * @private\n\t\t * @param {string} stateName\n\t\t * @return {string} Text which should be escaped.\n\t\t */\n\t\tgetStateDisplay: function ( stateName ) {\n\t\t\treturn mw.msg( 'translate-workflowstatus', stateName );\n\t\t},\n\n\t\t/**\n\t\t * Actually constructs the DOM and displays the selector.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tdisplay: function () {\n\t\t\tvar instance = this;\n\n\t\t\tinstance.$container.empty();\n\t\t\tif ( !instance.states ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar $list = $( '<ul>' )\n\t\t\t\t.addClass( 'tux-dropdown-menu tux-workflow-status-selector hide' );\n\n\t\t\tvar $display = $( '<div>' )\n\t\t\t\t.addClass( 'tux-workflow-status' )\n\t\t\t\t.text( mw.msg( 'translate-workflow-state-' ) )\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\t$list.toggleClass( 'hide' );\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t} );\n\n\t\t\tObject.keys( instance.states ).forEach( function ( key ) {\n\t\t\t\tvar data = instance.states[ key ], $state;\n\n\t\t\t\t// Store the id also\n\t\t\t\tdata.id = key;\n\n\t\t\t\t$state = $( '<li>' )\n\t\t\t\t\t.data( 'state', data )\n\t\t\t\t\t.text( data.name );\n\n\t\t\t\tif ( data.canchange && data.id !== instance.currentState ) {\n\t\t\t\t\t$state.addClass( 'changeable' );\n\t\t\t\t} else {\n\t\t\t\t\t$state.addClass( 'unchangeable' );\n\t\t\t\t}\n\n\t\t\t\tif ( data.id === instance.currentState ) {\n\t\t\t\t\t$display.text( instance.getStateDisplay( data.name ) )\n\t\t\t\t\t\t.append( $( '<span>' ).addClass( 'tux-workflow-status-triangle' ) );\n\t\t\t\t\t$state.addClass( 'selected' );\n\t\t\t\t}\n\n\t\t\t\t$state.appendTo( $list );\n\t\t\t} );\n\n\t\t\t$list.find( '.changeable' ).on( 'click', function () {\n\t\t\t\tvar $this = $( this );\n\n\t\t\t\tvar state = $this.data( 'state' ).id;\n\n\t\t\t\t$display.text( mw.msg( 'translate-workflow-set-doing' ) )\n\t\t\t\t\t.append( $( '<span>' ).addClass( 'tux-workflow-status-triangle' ) );\n\t\t\t\tinstance.changeState( state )\n\t\t\t\t\t.done( function () {\n\t\t\t\t\t\tinstance.receiveState( instance.groupId, instance.language, state );\n\t\t\t\t\t} )\n\t\t\t\t\t.fail( function () {\n\t\t\t\t\t\t// eslint-disable-next-line no-alert\n\t\t\t\t\t\talert( 'Change of state failed' );\n\t\t\t\t\t} );\n\t\t\t} );\n\t\t\tinstance.$container.append( $display, $list );\n\t\t}\n\t};\n\n\t/**\n\t * workflowselector jQuery definitions\n\t *\n\t * @internal\n\t * @param {string} groupId\n\t * @param {string} language\n\t * @param {string} state\n\t * @return {jQuery}\n\t */\n\t$.fn.workflowselector = function ( groupId, language, state ) {\n\t\treturn this.each( function () {\n\t\t\tvar $this = $( this ),\n\t\t\t\tdata = $this.data( 'workflowselector' );\n\n\t\t\tif ( !data ) {\n\t\t\t\t$this.data( 'workflowselector', new WorkflowSelector( this ) );\n\t\t\t}\n\t\t\t$this.data( 'workflowselector' ).receiveState( groupId, language, state );\n\t\t} );\n\t};\n\t$.fn.workflowselector.Constructor = WorkflowSelector;\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/js/jquery.ajaxdispatcher.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":19,"column":10,"nodeType":"CallExpression","endLine":24,"endColumn":7},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":65,"column":2,"nodeType":"CallExpression","endLine":65,"endColumn":51}],"suppressedMessages":[],"errorCount":1,"fatalErrorCount":0,"warningCount":1,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\n\t/**\n\t * Call list of callbacks returning promises in serial order and returns a list of promises.\n\t *\n\t * @internal\n\t * @author Niklas Laxström\n\t *\n\t * @param {Function[]} list List of callbacks returning promises.\n\t * @param {number} maxRetries Maximum number of times a failed promise is retried.\n\t * @return {jQuery.Promise}\n\t */\n\tfunction ajaxDispatcher( list, maxRetries ) {\n\t\tvar deferred = $.Deferred();\n\n\t\tmaxRetries = maxRetries || 0;\n\n\t\treturn $.when( helper( list, maxRetries ) )\n\t\t\t.then( function ( promises ) {\n\t\t\t\treturn deferred.resolve( promises );\n\t\t\t} ).fail( function ( errmsg ) {\n\t\t\t\treturn deferred.reject( errmsg );\n\t\t\t} );\n\t}\n\n\tfunction helper( list, maxRetries ) {\n\t\tvar deferred = $.Deferred();\n\n\t\tif ( list.length === 0 ) {\n\t\t\tdeferred.resolve( [] );\n\t\t\treturn deferred;\n\t\t}\n\n\t\tvar first = list.slice( 0, 1 )[ 0 ];\n\t\tvar rest = list.slice( 1 );\n\n\t\tvar retries = 0;\n\t\tvar retrier = function ( result, promise ) {\n\t\t\tif ( !promise.state ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( promise.state() === 'rejected' ) {\n\t\t\t\tif ( retries < maxRetries ) {\n\t\t\t\t\tretries += 1;\n\t\t\t\t\treturn first.call().always( retrier );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( promise.state() !== 'pending' ) {\n\t\t\t\thelper( rest, maxRetries ).always( function ( promises ) {\n\t\t\t\t\tdeferred.resolve( [].concat( promise, promises ) );\n\t\t\t\t} );\n\t\t\t}\n\t\t};\n\n\t\tfirst.call().always( retrier ).catch( function ( errmsg ) {\n\t\t\treturn deferred.reject( errmsg );\n\t\t} );\n\n\t\treturn deferred;\n\t}\n\n\t$.extend( $, { ajaxDispatcher: ajaxDispatcher } );\n\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupAssociation.vue","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"vue/component-tags-order","replacedBy":["block-order"]},{"ruleId":"vue/no-invalid-model-keys","replacedBy":["valid-model-definition"]},{"ruleId":"vue/v-on-function-call","replacedBy":["v-on-handler-style"]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupDeleteDialog.vue","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"vue/component-tags-order","replacedBy":["block-order"]},{"ruleId":"vue/no-invalid-model-keys","replacedBy":["valid-model-definition"]},{"ruleId":"vue/v-on-function-call","replacedBy":["v-on-handler-style"]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupDialog.vue","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":143,"column":4,"nodeType":"CallExpression","endLine":153,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":143,"column":4,"nodeType":"CallExpression","endLine":157,"endColumn":8}],"suppressedMessages":[],"errorCount":2,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"<template>\n\t<cdx-dialog\n\t\t:open=\"visible\"\n\t\t:title=\"dialogTitle\"\n\t\t:default-action=\"defaultAction\"\n\t\t:primary-action=\"primaryAction\"\n\t\t@primary=\"onPrimaryAction\"\n\t\t@default=\"$emit( 'close' )\"\n\t\t@update:open=\"$emit( 'close' )\"\n\t>\n\t\t<cdx-message\n\t\t\tv-if=\"apiLoadError\"\n\t\t\ttype=\"error\"\n\t\t\tallow-user-dismiss\n\t\t>\n\t\t\t{{ apiLoadError }}\n\t\t</cdx-message>\n\t\t<cdx-message\n\t\t\tv-if=\"apiSaveError\"\n\t\t\ttype=\"error\"\n\t\t\tallow-user-dismiss\n\t\t>\n\t\t\t{{ apiSaveError }}\n\t\t</cdx-message>\n\t\t<cdx-field :status=\"inputNameStatus\" :messages=\"inputNameMessages\">\n\t\t\t<template #label>\n\t\t\t\t{{ $i18n( \"tpt-aggregategroup-edit-name\" ) }}\n\t\t\t</template>\n\t\t\t<cdx-text-input\n\t\t\t\tv-model=\"formData.name\"\n\t\t\t\tmaxlength=\"200\"\n\t\t\t\trequired\n\t\t\t\t@input=\"onInputName\"\n\t\t\t></cdx-text-input>\n\t\t</cdx-field>\n\t\t<cdx-field :optional=\"true\">\n\t\t\t<template #label>\n\t\t\t\t{{ $i18n( \"tpt-aggregategroup-edit-description\" ) }}\n\t\t\t</template>\n\t\t\t<cdx-text-area v-model=\"formData.description\"></cdx-text-area>\n\t\t</cdx-field>\n\t\t<!-- FIXME: Remove the double (optional) suffix that appears by updating the English string -->\n\t\t<cdx-field :optional=\"true\">\n\t\t\t<template #label>\n\t\t\t\t{{ $i18n( \"tpt-aggregategroup-select-source-language\" ) }}\n\t\t\t</template>\n\t\t\t<!-- TODO: Maybe better to use a Codex Lookup here? -->\n\t\t\t<cdx-select v-model:selected=\"formData.languageCode\" :menu-items=\"languageMenuItems\">\n\t\t\t</cdx-select>\n\t\t</cdx-field>\n\t</cdx-dialog>\n</template>\n\n<script>\nconst {\n\tCdxDialog,\n\tCdxField,\n\tCdxTextArea,\n\tCdxTextInput,\n\tCdxSelect,\n\tCdxMessage\n} = require( '../../../../codex.js' );\nconst { supportedLanguages, undeterminedLanguageCode } = require( '../../language-map.json' );\n\n// @vue/component\nmodule.exports = {\n\tname: 'AggregateGroupDialog',\n\tcomponents: {\n\t\tCdxDialog,\n\t\tCdxField,\n\t\tCdxTextArea,\n\t\tCdxTextInput,\n\t\tCdxSelect,\n\t\tCdxMessage\n\t},\n\tinject: [ 'aggregateGroupApi' ],\n\tprops: {\n\t\tvisible: {\n\t\t\ttype: Boolean,\n\t\t\trequired: true\n\t\t},\n\t\taggregateGroupId: {\n\t\t\ttype: [ String, null ],\n\t\t\tdefault: null\n\t\t}\n\t},\n\temits: [ 'close', 'saved' ],\n\tdata() {\n\t\tconst defaultAction = {\n\t\t\tlabel: this.$i18n( 'tpt-aggregategroup-close' )\n\t\t};\n\n\t\tconst languageMenuItems = [ {\n\t\t\tlabel: this.$i18n( 'tpt-aggregategroup-language-none' ).text(),\n\t\t\tvalue: undeterminedLanguageCode\n\t\t} ];\n\t\tObject.keys( supportedLanguages ).forEach( ( languageCode ) => {\n\t\t\tlanguageMenuItems.push( {\n\t\t\t\tlabel: supportedLanguages[ languageCode ],\n\t\t\t\tvalue: languageCode\n\t\t\t} );\n\t\t} );\n\n\t\treturn {\n\t\t\tdefaultAction,\n\t\t\tlanguageMenuItems,\n\t\t\tformData: {\n\t\t\t\tname: '',\n\t\t\t\tdescription: '',\n\t\t\t\tlanguageCode: undeterminedLanguageCode\n\t\t\t},\n\t\t\tinputNameMessages: null,\n\t\t\tinputNameStatus: 'default',\n\t\t\tapiLoadError: null,\n\t\t\tapiSaveError: null\n\t\t};\n\t},\n\tcomputed: {\n\t\tdialogTitle() {\n\t\t\treturn this.aggregateGroupId ?\n\t\t\t\tmw.msg( 'tpt-aggregategroup-edit' ) : mw.msg( 'tpt-aggregategroup-add-new' );\n\t\t},\n\t\tprimaryAction() {\n\t\t\treturn {\n\t\t\t\tlabel: this.$i18n( 'tpt-aggregategroup-save' ),\n\t\t\t\tactionType: 'progressive',\n\t\t\t\tdisabled: !!this.apiLoadError\n\t\t\t};\n\t\t}\n\t},\n\tmethods: {\n\t\tfetchAggregateGroupInfo( aggregateGroupId ) {\n\t\t\tconst params = {\n\t\t\t\tmeta: 'messagegroups',\n\t\t\t\tmgformat: 'flat',\n\t\t\t\tmgprop: 'id|label|description|sourcelanguage',\n\t\t\t\tmgroot: aggregateGroupId,\n\t\t\t\tformatversion: 2,\n\t\t\t\tuselang: mw.config.get( 'wgUserLanguage' )\n\t\t\t};\n\n\t\t\tconst api = new mw.Api();\n\t\t\tapi.get( params )\n\t\t\t\t.done( ( result ) => {\n\t\t\t\t\tconst messageGroup = result.query.messagegroups[ 0 ];\n\t\t\t\t\tif ( !messageGroup ) {\n\t\t\t\t\t\tthis.apiLoadError = mw.msg( 'tpt-aggregategroup-not-found' );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tthis.formData.name = messageGroup.label;\n\t\t\t\t\tthis.formData.languageCode = messageGroup.sourcelanguage;\n\t\t\t\t\tthis.formData.description = messageGroup.description;\n\t\t\t\t} )\n\t\t\t\t.fail( ( code, data ) => {\n\t\t\t\t\tmw.log.error( 'Error while fetching aggregate group', code, data );\n\t\t\t\t\tthis.apiLoadError = mw.msg( 'tpt-aggregategroup-load-error' );\n\t\t\t\t} );\n\t\t},\n\t\tonPrimaryAction() {\n\t\t\tif ( !this.validate() ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.apiSaveError = null;\n\t\t\tlet apiPromise;\n\t\t\tif ( this.aggregateGroupId ) {\n\t\t\t\tapiPromise = this.aggregateGroupApi.update( this.aggregateGroupId, this.formData );\n\t\t\t} else {\n\t\t\t\tapiPromise = this.aggregateGroupApi.add( this.formData );\n\t\t\t}\n\n\t\t\tapiPromise\n\t\t\t\t.then( () => {\n\t\t\t\t\tthis.resetErrors();\n\t\t\t\t\tthis.$emit( 'saved' );\n\t\t\t\t} )\n\t\t\t\t.catch( ( code, data ) => {\n\t\t\t\t\tthis.apiSaveError = data.error && data.error.info;\n\t\t\t\t} );\n\t\t},\n\t\tonInputName( event ) {\n\t\t\tif ( event.target.value !== '' ) {\n\t\t\t\tthis.inputNameStatus = 'default';\n\t\t\t\tthis.inputNameMessages = null;\n\t\t\t}\n\t\t},\n\t\tvalidate() {\n\t\t\tif ( this.formData.name.trim() === '' ) {\n\t\t\t\tthis.inputNameStatus = 'error';\n\t\t\t\tthis.inputNameMessages = {\n\t\t\t\t\terror: this.$i18n( 'tpt-aggregategroup-empty-name' )\n\t\t\t\t};\n\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\treturn true;\n\t\t},\n\t\tresetErrors() {\n\t\t\tthis.inputNameStatus = 'default';\n\t\t\tthis.inputNameMessages = null;\n\t\t\tthis.apiSaveError = null;\n\t\t\tthis.apiLoadError = null;\n\t\t}\n\t},\n\twatch: {\n\t\tvisible( newValue ) {\n\t\t\tif ( newValue ) {\n\t\t\t\t// Dialog is being opened.\n\t\t\t\tthis.resetErrors();\n\t\t\t}\n\t\t},\n\t\taggregateGroupId( newValue ) {\n\t\t\tif ( newValue ) {\n\t\t\t\tthis.fetchAggregateGroupInfo( newValue );\n\t\t\t} else {\n\t\t\t\tthis.formData = {\n\t\t\t\t\tname: '',\n\t\t\t\t\tdescription: '',\n\t\t\t\t\tlanguageCode: undeterminedLanguageCode\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n};\n</script>\n\n<style lang=\"less\">\n// FIXME: These styles should not be needed. Report an issue in Codex\n// See: https://phabricator.wikimedia.org/F58151207\n.cdx-dialog__body .cdx-message:first-child {\n\tpadding-top: inherit;\n}\n</style>\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"vue/component-tags-order","replacedBy":["block-order"]},{"ruleId":"vue/no-invalid-model-keys","replacedBy":["valid-model-definition"]},{"ruleId":"vue/v-on-function-call","replacedBy":["v-on-handler-style"]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupSubGroupItem.vue","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"vue/component-tags-order","replacedBy":["block-order"]},{"ruleId":"vue/no-invalid-model-keys","replacedBy":["valid-model-definition"]},{"ruleId":"vue/v-on-function-call","replacedBy":["v-on-handler-style"]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupsToolboxApp.vue","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"vue/component-tags-order","replacedBy":["block-order"]},{"ruleId":"vue/no-invalid-model-keys","replacedBy":["valid-model-definition"]},{"ruleId":"vue/v-on-function-call","replacedBy":["v-on-handler-style"]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.aggregategroups.refresh/init.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.cleanchanges/index.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.entity.selector/index.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.eventlogginghelpers/index.js","messages":[],"suppressedMessages":[{"ruleId":"camelcase","severity":2,"message":"Identifier 'action_subtype' is not in camel case.","line":29,"column":21,"nodeType":"Identifier","messageId":"notCamelCase","endLine":29,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'action_source' is not in camel case.","line":34,"column":21,"nodeType":"Identifier","messageId":"notCamelCase","endLine":34,"endColumn":34,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'action_subtype' is not in camel case.","line":57,"column":21,"nodeType":"Identifier","messageId":"notCamelCase","endLine":57,"endColumn":35,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"camelcase","severity":2,"message":"Identifier 'action_source' is not in camel case.","line":62,"column":21,"nodeType":"Identifier","messageId":"notCamelCase","endLine":62,"endColumn":34,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.groupselector/index.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":156,"column":5,"nodeType":"CallExpression","endLine":156,"endColumn":57},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":348,"column":4,"nodeType":"CallExpression","endLine":359,"endColumn":7},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":391,"column":4,"nodeType":"CallExpression","endLine":408,"endColumn":8},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":450,"column":4,"nodeType":"CallExpression","endLine":476,"endColumn":7}],"suppressedMessages":[{"ruleId":"mediawiki/class-doc","severity":2,"message":"All possible CSS classes should be documented. See https://w.wiki/PS2 for details.","line":73,"column":5,"nodeType":"CallExpression","endLine":73,"endColumn":56,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/variable-pattern","severity":2,"message":"jQuery collection names must match the variablePattern","line":292,"column":5,"nodeType":"AssignmentExpression","endLine":292,"endColumn":45,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"( function () {\n\t'use strict';\n\n\tvar groupsLoader, delay;\n\n\t/**\n\t * options\n\t *  - position: accepts same values as jquery.ui.position\n\t *  - onSelect:\n\t *  - language:\n\t *  - preventSelector: boolean to not allow selection of subgroups.\n\t *  - recent: list of recent group ids\n\t * groups: list of message group ids\n\t *\n\t * @private\n\t * @param {Element} element\n\t * @param {Object} options\n\t * @param {Object} [options.position] Accepts same values as jquery.ui.position.\n\t * @param {Function} [options.onSelect] Callback with message group id when selected.\n\t * @param {string} options.language Language code for statistics.\n\t * @param {boolean} [options.preventSelector] Do not allow selection of subgroups.\n\t * @param {string[]} [options.recent] List of recent message group ids.\n\t * @param {string[]} [options.showWatched] Whether to show watched message groups\n\t * @param {string} [options.menuClass] A CSS class to add to the menu element\n\t * @param {string[]} [groups] List of message group ids to show.\n\t */\n\tfunction TranslateMessageGroupSelector( element, options, groups ) {\n\t\tthis.$trigger = $( element );\n\t\tthis.$menu = null;\n\t\tthis.$search = null;\n\t\tthis.$list = null;\n\t\tthis.$loader = null;\n\n\t\tthis.parentGroupId = null;\n\t\tthis.options = $.extend( true, {}, $.fn.msggroupselector.defaults, options );\n\t\t// Store the explicitly given options, which can be passed to subgroup\n\t\t// selectors.\n\t\tthis.customOptions = options;\n\t\tthis.flatGroupList = null;\n\t\tthis.groups = groups;\n\t\tthis.firstShow = true;\n\t\tthis.watchedGroups = [];\n\n\t\tthis.init();\n\t}\n\n\tTranslateMessageGroupSelector.prototype = {\n\t\tconstructor: TranslateMessageGroupSelector,\n\n\t\t/**\n\t\t * Initialize the plugin\n\t\t *\n\t\t * @private\n\t\t */\n\t\tinit: function () {\n\t\t\tthis.parentGroupId = this.$trigger.data( 'msggroupid' );\n\t\t\tthis.prepareSelectorMenu();\n\t\t\tthis.listen();\n\t\t},\n\n\t\t/**\n\t\t * Prepare the selector menu rendering\n\t\t *\n\t\t * @private\n\t\t */\n\t\tprepareSelectorMenu: function () {\n\t\t\tthis.$menu = $( '<div>' )\n\t\t\t\t.addClass( 'tux-groupselector' )\n\t\t\t\t.addClass( 'grid hide' );\n\n\t\t\tif ( this.customOptions.menuClass ) {\n\t\t\t\t// eslint-disable-next-line mediawiki/class-doc\n\t\t\t\tthis.$menu.addClass( this.customOptions.menuClass );\n\t\t\t}\n\n\t\t\tvar $searchIcon = $( '<div>' )\n\t\t\t\t.addClass( 'two columns tux-groupselector__filter__search__icon' );\n\n\t\t\tthis.$search = $( '<input>' )\n\t\t\t\t.prop( 'type', 'text' )\n\t\t\t\t.addClass( 'tux-groupselector__filter__search__input' )\n\t\t\t\t.prop( 'placeholder', mw.msg( 'translate-msggroupselector-search-placeholder' ) );\n\n\t\t\tvar $search = $( '<div>' )\n\t\t\t\t.addClass( 'ten columns' )\n\t\t\t\t.append( this.$search );\n\n\t\t\tvar $listFilters = $( '<div>' )\n\t\t\t\t.addClass( 'tux-groupselector__filter__tabs' )\n\t\t\t\t.addClass( 'six columns' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'tux-grouptab tux-grouptab--all tux-grouptab--selected' )\n\t\t\t\t\t\t.text( mw.msg( 'translate-msggroupselector-search-all' ) )\n\t\t\t\t);\n\n\t\t\tif ( this.options.recent && this.options.recent.length ) {\n\t\t\t\t$listFilters.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'tux-grouptab tux-grouptab--recent' )\n\t\t\t\t\t\t.text( mw.msg( 'translate-msggroupselector-search-recent' ) )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( this.options.showWatched ) {\n\t\t\t\t$listFilters.append(\n\t\t\t\t\t$( '<div>' )\n\t\t\t\t\t\t.addClass( 'tux-grouptab tux-grouptab--watched' )\n\t\t\t\t\t\t.text( mw.msg( 'translate-msggroupselector-search-watched' ) )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tvar $searchGroup = $( '<div>' )\n\t\t\t\t.addClass( 'tux-groupselector__filter__search' )\n\t\t\t\t.addClass( 'six columns' )\n\t\t\t\t.append( $searchIcon, $search );\n\n\t\t\tvar $listFiltersGroup = $( '<div>' )\n\t\t\t\t.addClass( 'tux-groupselector__filter' )\n\t\t\t\t.addClass( 'row' )\n\t\t\t\t.append( $listFilters, $searchGroup );\n\n\t\t\tvar manageSubscriptions = require( './data.json' ).pagelink;\n\t\t\tvar $footer = $( '<div>' )\n\t\t\t\t.addClass( 'tux-groupselector__footer hide' )\n\t\t\t\t.append( $( '<a>' )\n\t\t\t\t\t.prop( 'href', mw.util.getUrl( manageSubscriptions ) )\n\t\t\t\t\t.text( mw.msg( 'translate-msggroupselector-special-msgsubscriptions-label' ) )\n\t\t\t\t);\n\n\t\t\tthis.$list = $( '<div>' )\n\t\t\t\t.addClass( 'tux-grouplist' )\n\t\t\t\t.addClass( 'row' );\n\n\t\t\tthis.$loader = $( '<div>' )\n\t\t\t\t.addClass( 'tux-loading-indicator tux-loading-indicator--centered' );\n\n\t\t\tthis.$menu.append( $listFiltersGroup, this.$loader, this.$list, $footer );\n\n\t\t\tthis.$menu.appendTo( document.body );\n\t\t},\n\n\t\t/**\n\t\t * Show the selector\n\t\t *\n\t\t * @private\n\t\t */\n\t\tshow: function () {\n\t\t\tthis.$menu.addClass( 'open' ).removeClass( 'hide' );\n\t\t\tthis.position();\n\t\t\t// Place the focus in the message group search box.\n\t\t\tthis.$search.trigger( 'focus' );\n\t\t\t// Start loading the groups, but assess the situation again after\n\t\t\t// they are loaded, in case user has made further interactions.\n\t\t\tif ( this.firstShow ) {\n\t\t\t\tthis.loadGroups().done( this.showList.bind( this ) );\n\t\t\t\tthis.firstShow = false;\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Hide the selector\n\t\t *\n\t\t * @private\n\t\t * @param {jQuery.Event} e\n\t\t */\n\t\thide: function ( e ) {\n\t\t\t// Do not hide if the trigger is clicked\n\t\t\tif ( e && ( this.$trigger.is( e.target ) || this.$trigger.has( e.target ).length ) ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.$menu.addClass( 'hide' ).removeClass( 'open' );\n\t\t},\n\n\t\t/**\n\t\t * Toggle the menu open/close state\n\t\t *\n\t\t * @private\n\t\t */\n\t\ttoggle: function () {\n\t\t\tif ( this.$menu.hasClass( 'open' ) ) {\n\t\t\t\tthis.hide();\n\t\t\t} else {\n\t\t\t\tthis.show();\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Attach event listeners\n\t\t *\n\t\t * @private\n\t\t */\n\t\tlisten: function () {\n\t\t\tvar groupSelector = this;\n\n\t\t\t// Hide the selector panel when clicking outside of it\n\t\t\t$( document.documentElement ).on( 'click', this.hide.bind( this ) );\n\n\t\t\tgroupSelector.$trigger.on( 'click', function () {\n\t\t\t\tgroupSelector.toggle();\n\t\t\t} );\n\n\t\t\tgroupSelector.$menu.on( 'click', function ( e ) {\n\t\t\t\te.stopPropagation();\n\t\t\t} );\n\n\t\t\t// Handle click on row item. This selects the group, and in case it has\n\t\t\t// subgroups, also opens a new menu to show them.\n\t\t\tgroupSelector.$menu.on( 'click', '.tux-grouplist__item', function () {\n\t\t\t\tvar messageGroup = $( this ).data( 'msggroup' );\n\n\t\t\t\tgroupSelector.hide();\n\n\t\t\t\tgroupSelector.$trigger.nextAll().remove();\n\n\t\t\t\tif ( !groupSelector.options.preventSelector ) {\n\t\t\t\t\tvar $newLink = $( '<span>' )\n\t\t\t\t\t\t.addClass( 'grouptitle grouplink' )\n\t\t\t\t\t\t.text( messageGroup.label )\n\t\t\t\t\t\t.data( 'msggroupid', messageGroup.id );\n\n\t\t\t\t\tgroupSelector.$trigger.after( $newLink );\n\n\t\t\t\t\tif ( messageGroup.groups && messageGroup.groups.length > 0 ) {\n\t\t\t\t\t\t// Show the new menu immediately.\n\t\t\t\t\t\t// Pass options for callbacks, language etc. but ignore the position\n\t\t\t\t\t\t// option unless explicitly given to allow automatic recalculation\n\t\t\t\t\t\t// of the position compared to the new trigger.\n\t\t\t\t\t\t$newLink\n\t\t\t\t\t\t\t.addClass( 'tux-breadcrumb__item--aggregate' )\n\t\t\t\t\t\t\t.msggroupselector( groupSelector.customOptions )\n\t\t\t\t\t\t\t.data( 'msggroupselector' ).show();\n\t\t\t\t\t\t$newLink.data( 'msggroup-subgroup-count', messageGroup.groups.length );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ( groupSelector.options.onSelect ) {\n\t\t\t\t\tgroupSelector.options.onSelect( messageGroup );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t// Handle the tabs All | Recent\n\t\t\tvar $tabs = groupSelector.$menu.find( '.tux-grouptab' );\n\t\t\t$tabs.on( 'click', function () {\n\t\t\t\tvar $this = $( this );\n\n\t\t\t\t/* Do nothing if user clicks the active tab.\n\t\t\t\t * Fixes two things:\n\t\t\t\t * - The blue bottom border highlight doesn't jump around\n\t\t\t\t * - No flash when clicking recent tab again\n\t\t\t\t */\n\t\t\t\tif ( $this.hasClass( 'tux-grouptab--selected' ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t} else {\n\t\t\t\t\t$tabs.removeClass( 'tux-grouptab--selected' );\n\t\t\t\t\t$this.addClass( 'tux-grouptab--selected' );\n\t\t\t\t}\n\n\t\t\t\tgroupSelector.$search.val( '' );\n\t\t\t\tgroupSelector.showList();\n\t\t\t\tgroupSelector.$menu.find( '.tux-groupselector__footer' )\n\t\t\t\t\t.toggleClass( 'hide', !$this.hasClass( 'tux-grouptab--watched' ) );\n\t\t\t} );\n\n\t\t\tthis.$search.on( 'click', this.show.bind( this ) )\n\t\t\t\t.on( 'keypress', this.keyup.bind( this ) )\n\t\t\t\t.on( 'keyup', this.keyup.bind( this ) );\n\n\t\t\tif ( this.eventSupported( 'keydown' ) ) {\n\t\t\t\tthis.$search.on( 'keydown', this.keyup.bind( this ) );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Handle the keypress/keyup events in the message group search box.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tkeyup: function () {\n\t\t\tdelay( this.showList.bind( this ), 300 );\n\t\t},\n\n\t\t/**\n\t\t * Position the menu\n\t\t *\n\t\t * @private\n\t\t */\n\t\tposition: function () {\n\t\t\tif ( this.options.position.of === undefined ) {\n\t\t\t\t// eslint-disable-next-line no-jquery/variable-pattern\n\t\t\t\tthis.options.position.of = this.$trigger;\n\t\t\t}\n\n\t\t\tvar positionElement = require( './ui.position.js' );\n\t\t\tpositionElement( this.$menu, this.options.position );\n\t\t},\n\n\t\t/**\n\t\t * Shows suitable list for current view, taking possible filter into account\n\t\t *\n\t\t * @private\n\t\t */\n\t\tshowList: function () {\n\t\t\tvar query = this.$search.val().trim().toLowerCase();\n\n\t\t\tif ( query ) {\n\t\t\t\tthis.filter( query );\n\t\t\t} else {\n\t\t\t\tthis.showUnfilteredList();\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Shows an unfiltered list of groups depending on the selected tab.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tshowUnfilteredList: function () {\n\t\t\tvar $selected = this.$menu.find( '.tux-grouptab--selected' );\n\n\t\t\tif ( $selected.hasClass( 'tux-grouptab--all' ) ) {\n\t\t\t\tif ( this.groups ) {\n\t\t\t\t\tthis.showSelectedGroups( this.groups );\n\t\t\t\t} else {\n\t\t\t\t\tthis.showDefaultGroups();\n\t\t\t\t}\n\t\t\t} else if ( $selected.hasClass( 'tux-grouptab--recent' ) ) {\n\t\t\t\tthis.showRecentGroups();\n\t\t\t} else if ( $selected.hasClass( 'tux-grouptab--watched' ) ) {\n\t\t\t\tthis.showWatchedGroups();\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Shows the list of message groups excluding subgroups.\n\t\t *\n\t\t * In case a parent message group has been given, only subgroups of that\n\t\t * message group are shown, otherwise all top-level message groups are shown.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tshowDefaultGroups: function () {\n\t\t\tvar groupSelector = this;\n\n\t\t\tthis.$loader.removeClass( 'hide' );\n\n\t\t\tthis.loadGroups().done( function ( groups ) {\n\t\t\t\tvar groupsToShow = mw.translate.findGroup( groupSelector.parentGroupId, groups );\n\n\t\t\t\t// We do not want to display the group itself, only its subgroups\n\t\t\t\tif ( groupSelector.parentGroupId ) {\n\t\t\t\t\tgroupsToShow = groupsToShow.groups;\n\t\t\t\t}\n\n\t\t\t\tgroupSelector.$loader.addClass( 'hide' );\n\t\t\t\tgroupSelector.$list.empty();\n\t\t\t\tgroupSelector.addGroupRows( groupsToShow );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Show recent message groups.\n\t\t *\n\t\t * @private\n\t\t */\n\t\tshowRecentGroups: function () {\n\t\t\tvar recent = this.options.recent || [];\n\n\t\t\tthis.showSelectedGroups( recent );\n\t\t},\n\n\t\t/**\n\t\t * Show watched message groups.\n\t\t */\n\t\tshowWatchedGroups: function () {\n\t\t\tif ( this.options.showWatched ) {\n\t\t\t\tthis.showSelectedGroups( this.watchedGroups || [] );\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Load message groups.\n\t\t *\n\t\t * @private\n\t\t * @param {Array} groups List of the message group ids to show.\n\t\t */\n\t\tshowSelectedGroups: function ( groups ) {\n\t\t\tvar groupSelector = this;\n\t\t\tthis.$loader.removeClass( 'hide' );\n\t\t\tthis.loadGroups()\n\t\t\t\t.then( function ( allGroups ) {\n\t\t\t\t\tvar rows = [];\n\t\t\t\t\tgroups.forEach( function ( id ) {\n\t\t\t\t\t\tvar group = mw.translate.findGroup( id, allGroups );\n\t\t\t\t\t\tif ( group ) {\n\t\t\t\t\t\t\trows.push( groupSelector.prepareMessageGroupRow( group ) );\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t\treturn rows;\n\t\t\t\t} )\n\t\t\t\t.always( function () {\n\t\t\t\t\tgroupSelector.$loader.addClass( 'hide' );\n\t\t\t\t\tgroupSelector.$list.empty();\n\t\t\t\t} )\n\t\t\t\t.done( function ( rows ) {\n\t\t\t\t\tgroupSelector.$list.append( rows );\n\t\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Flattens a message group tree.\n\t\t *\n\t\t * @private\n\t\t * @param {Array} messageGroups An array or data object.\n\t\t * @param {Object} foundIDs The array in which the keys are IDs of message groups that were found already.\n\t\t */\n\t\tflattenGroupList: function ( messageGroups, foundIDs ) {\n\t\t\tvar messageGroupList;\n\t\t\tif ( messageGroups.groups ) {\n\t\t\t\tmessageGroupList = messageGroups.groups;\n\t\t\t} else {\n\t\t\t\tmessageGroupList = messageGroups;\n\t\t\t}\n\n\t\t\tfor ( var i = 0; i < messageGroupList.length; i++ ) {\n\t\t\t\t// Avoid duplicate groups, and add the parent before subgroups\n\t\t\t\tif ( !foundIDs[ messageGroupList[ i ].id ] ) {\n\t\t\t\t\tthis.flatGroupList.push( messageGroupList[ i ] );\n\t\t\t\t\tfoundIDs[ messageGroupList[ i ].id ] = true;\n\t\t\t\t}\n\n\t\t\t\t// In case there are subgroups, add them recursively\n\t\t\t\tif ( messageGroupList[ i ].groups ) {\n\t\t\t\t\tthis.flattenGroupList( messageGroupList[ i ].groups, foundIDs );\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\t/**\n\t\t * Search the message groups based on label or id.\n\t\t * Label match is prefix match, while id match is exact match.\n\t\t *\n\t\t * @private\n\t\t * @param {string} query\n\t\t */\n\t\tfilter: function ( query ) {\n\t\t\tvar self = this;\n\n\t\t\tthis.loadGroups().done( function ( groups ) {\n\t\t\t\tvar foundGroups = [];\n\n\t\t\t\tif ( !self.flatGroupList ) {\n\t\t\t\t\tself.flatGroupList = [];\n\t\t\t\t\tvar currentGroup = mw.translate.findGroup( self.parentGroupId, groups );\n\t\t\t\t\tif ( self.parentGroupId ) {\n\t\t\t\t\t\tcurrentGroup = currentGroup.groups;\n\t\t\t\t\t}\n\t\t\t\t\tself.flattenGroupList( currentGroup, {} );\n\t\t\t\t}\n\n\t\t\t\t// Optimization, assuming that people search the beginning\n\t\t\t\t// of the group name.\n\t\t\t\tvar matcher = new RegExp( '\\\\b' + escapeRegex( query ), 'i' );\n\n\t\t\t\tfor ( var index = 0; index < self.flatGroupList.length; index++ ) {\n\t\t\t\t\tif ( matcher.test( self.flatGroupList[ index ].label ) ||\n\t\t\t\t\t\tquery === self.flatGroupList[ index ].id ) {\n\t\t\t\t\t\tfoundGroups.push( self.flatGroupList[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tself.$loader.addClass( 'hide' );\n\t\t\t\tself.$list.empty();\n\t\t\t\tself.addGroupRows( foundGroups );\n\t\t\t} );\n\t\t},\n\n\t\t/**\n\t\t * Load message groups and relevant properties using the API.\n\t\t *\n\t\t * @private\n\t\t * @return {jQuery.Promise}\n\t\t */\n\t\tloadGroups: function () {\n\t\t\tif ( groupsLoader !== undefined ) {\n\t\t\t\treturn groupsLoader;\n\t\t\t}\n\n\t\t\tvar params = {\n\t\t\t\taction: 'query',\n\t\t\t\tmeta: 'messagegroups',\n\t\t\t\tmgformat: 'tree',\n\t\t\t\tmgprop: 'id|label|icon',\n\t\t\t\tmgiconsize: '32',\n\t\t\t\tmglanguageFilter: this.options.language\n\t\t\t};\n\n\t\t\tgroupsLoader = new mw.Api()\n\t\t\t\t.get( params )\n\t\t\t\t.then( function ( result ) {\n\t\t\t\t\treturn result.query.messagegroups;\n\t\t\t\t} )\n\t\t\t\t.promise();\n\n\t\t\treturn groupsLoader;\n\t\t},\n\n\t\t/**\n\t\t * Add rows with message groups to the selector.\n\t\t *\n\t\t * @private\n\t\t * @param {Array} groups Array of message group objects to add.\n\t\t */\n\t\taddGroupRows: function ( groups ) {\n\t\t\tvar groupSelector = this,\n\t\t\t\t$msgGroupRows = [];\n\n\t\t\tif ( !groups ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tgroups.forEach( function ( group ) {\n\t\t\t\t$msgGroupRows.push( groupSelector.prepareMessageGroupRow( group ) );\n\t\t\t} );\n\n\t\t\tif ( this.parentGroupId ) {\n\t\t\t\tvar $parent = this.$list.find( '.tux-grouplist__item[data-msggroupid=\"' +\n\t\t\t\t\tthis.parentGroupId + '\"]' );\n\n\t\t\t\tif ( $parent.length ) {\n\t\t\t\t\t$parent.after( $msgGroupRows );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.$list.append( $msgGroupRows );\n\t\t},\n\n\t\t/**\n\t\t * Prepare a message group row in the selector.\n\t\t *\n\t\t * @private\n\t\t * @param {Object} messagegroup object.\n\t\t * @return {Object} a jQuery object with the groups selector row (<div>).\n\t\t */\n\t\tprepareMessageGroupRow: function ( messagegroup ) {\n\t\t\tvar $row = $( '<div>' )\n\t\t\t\t.addClass( 'row tux-grouplist__item' )\n\t\t\t\t.attr( 'data-msggroupid', messagegroup.id )\n\t\t\t\t.data( 'msggroup', messagegroup );\n\n\t\t\tvar $icon = $( '<div>' )\n\t\t\t\t.addClass( 'tux-grouplist__item__icon' )\n\t\t\t\t.addClass( 'one column' );\n\n\t\t\tvar $statsbar = $( '<div>' ).languagestatsbar( {\n\t\t\t\tlanguage: this.options.language,\n\t\t\t\tgroup: messagegroup.id\n\t\t\t} );\n\n\t\t\tvar $label = $( '<div>' )\n\t\t\t\t.addClass( 'tux-grouplist__item__label' )\n\t\t\t\t.addClass( 'seven columns' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t// T130390: must be attr for IE/Edge.\n\t\t\t\t\t\t.attr( { dir: 'auto' } )\n\t\t\t\t\t\t.text( messagegroup.label ),\n\t\t\t\t\t$statsbar\n\t\t\t\t);\n\n\t\t\tvar style = '';\n\t\t\tif ( messagegroup.icon && messagegroup.icon.raster ) {\n\t\t\t\tstyle += 'background-image: url(--);';\n\t\t\t\tstyle = style.replace( /--/g, messagegroup.icon.raster );\n\t\t\t}\n\n\t\t\tif ( messagegroup.icon && messagegroup.icon.vector ) {\n\t\t\t\tstyle += 'background-image: url(--);';\n\t\t\t\tstyle = style.replace( /--/g, messagegroup.icon.vector );\n\t\t\t}\n\n\t\t\tif ( style !== '' ) {\n\t\t\t\t$icon.attr( 'style', style );\n\t\t\t}\n\n\t\t\tvar $subGroupsLabel = $( [] );\n\n\t\t\tif ( messagegroup.groups && messagegroup.groups.length > 0 ) {\n\t\t\t\t$subGroupsLabel = $( '<div>' )\n\t\t\t\t\t.addClass( 'tux-grouplist__item__subgroups' )\n\t\t\t\t\t.addClass( 'four columns' )\n\t\t\t\t\t.text( mw.msg( 'translate-msggroupselector-view-subprojects',\n\t\t\t\t\t\tmessagegroup.groups.length ) );\n\t\t\t}\n\n\t\t\treturn $row.append( $icon, $label, $subGroupsLabel );\n\t\t},\n\n\t\t/**\n\t\t * Check that a DOM event is supported by the $menu jQuery object.\n\t\t *\n\t\t * @private\n\t\t * @param {string} eventName\n\t\t * @return {boolean}\n\t\t */\n\t\teventSupported: function ( eventName ) {\n\t\t\tvar $search = this.$menu.find( '.tux-groupselector__filter__search__input' ),\n\t\t\t\tisSupported = eventName in $search;\n\n\t\t\tif ( !isSupported ) {\n\t\t\t\tthis.$element.setAttribute( eventName, 'return;' );\n\t\t\t\tisSupported = typeof this.$element[ eventName ] === 'function';\n\t\t\t}\n\n\t\t\treturn isSupported;\n\t\t},\n\n\t\t/**\n\t\t * Only shows message groups translatable to given target language\n\t\t *\n\t\t * @internal\n\t\t * @param {string} targetLanguage\n\t\t */\n\t\tupdateTargetLanguage: function ( targetLanguage ) {\n\t\t\tthis.options.language = targetLanguage;\n\t\t\tgroupsLoader = undefined;\n\t\t\tthis.firstShow = true;\n\t\t},\n\n\t\t/**\n\t\t * Set the list of watched message group ids\n\t\t *\n\t\t * @param {string[]} groupIds\n\t\t */\n\t\tsetWatchedGroups: function ( groupIds ) {\n\t\t\tthis.watchedGroups = groupIds;\n\t\t\tvar $watchedTab = this.$menu.find( '.tux-grouptab--watched' );\n\t\t\tif ( $watchedTab.hasClass( 'tux-grouptab--selected' ) ) {\n\t\t\t\tthis.showWatchedGroups();\n\t\t\t}\n\t\t}\n\t};\n\n\t/**\n\t * msggroupselector PLUGIN DEFINITION\n\t *\n\t * @internal\n\t * @param {Object} options\n\t * @param {string[]} groups\n\t * @return {jQuery}\n\t */\n\t$.fn.msggroupselector = function ( options, groups ) {\n\t\treturn this.each( function () {\n\t\t\tvar $this = $( this ),\n\t\t\t\tdata = $this.data( 'msggroupselector' );\n\n\t\t\tif ( !data ) {\n\t\t\t\t$this.data( 'msggroupselector',\n\t\t\t\t\t( data = new TranslateMessageGroupSelector( this, options, groups ) )\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif ( typeof options === 'string' ) {\n\t\t\t\tdata[ options ].call( $this );\n\t\t\t}\n\t\t} );\n\t};\n\n\t$.fn.msggroupselector.Constructor = TranslateMessageGroupSelector;\n\n\t/**\n\t * Default options when initializing the message group selector\n\t *\n\t * @private\n\t */\n\t$.fn.msggroupselector.defaults = {\n\t\tlanguage: 'en',\n\t\tposition: {\n\t\t\tmy: 'left top',\n\t\t\tat: 'left-90 bottom+5'\n\t\t}\n\t};\n\n\t/*\n\t * Private functions\n\t */\n\n\t/**\n\t * Escape the search query for regex match\n\t *\n\t * @param {string} value A search string to be escaped.\n\t * @return {string} Escaped string that is safe to use for a search.\n\t */\n\tfunction escapeRegex( value ) {\n\t\treturn value.replace( /[-[\\]{}()*+?.,\\\\^$|#\\s]/g, '\\\\$&' );\n\t}\n\n\tdelay = ( function () {\n\t\tvar timer = 0;\n\n\t\treturn function ( callback, milliseconds ) {\n\t\t\tclearTimeout( timer );\n\t\t\ttimer = setTimeout( callback, milliseconds );\n\t\t};\n\t}() );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.groupselector/ui.position.js","messages":[],"suppressedMessages":[{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\+.","line":19,"column":14,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":19,"endColumn":15,"suggestions":[{"messageId":"removeEscape","fix":{"range":[675,676],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[675,675],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-useless-escape","severity":2,"message":"Unnecessary escape character: \\-.","line":19,"column":16,"nodeType":"Literal","messageId":"unnecessaryEscape","endLine":19,"endColumn":17,"suggestions":[{"messageId":"removeEscape","fix":{"range":[677,678],"text":""},"desc":"Remove the `\\`. This maintains the current functionality."},{"messageId":"escapeBackslash","fix":{"range":[677,677],"text":"\\"},"desc":"Replace the `\\` with `\\\\` to include the actual backslash character."}],"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"eqeqeq","severity":2,"message":"Expected '!==' and instead saw '!='.","line":35,"column":13,"nodeType":"BinaryExpression","messageId":"unexpected","endLine":35,"endColumn":15,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/variable-pattern","severity":2,"message":"jQuery collection names must match the variablePattern","line":73,"column":3,"nodeType":"VariableDeclarator","endLine":75,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":73,"column":9,"nodeType":"CallExpression","endLine":75,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-parse-html-literal","severity":2,"message":"Prefer DOM building to parsing HTML literals","line":73,"column":9,"nodeType":"CallExpression","endLine":75,"endColumn":58,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-return-assign","severity":2,"message":"Return statement should not contain assignment.","line":90,"column":2,"nodeType":"ReturnStatement","messageId":"returnAssignment","endLine":90,"endColumn":40,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/variable-pattern","severity":2,"message":"jQuery collection names must match the variablePattern","line":109,"column":6,"nodeType":"VariableDeclarator","endLine":109,"endColumn":44,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":139,"column":15,"nodeType":"MemberExpression","messageId":"forbidden","endLine":139,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":141,"column":5,"nodeType":"MemberExpression","messageId":"forbidden","endLine":141,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":176,"column":15,"nodeType":"MemberExpression","messageId":"forbidden","endLine":176,"endColumn":22,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":178,"column":5,"nodeType":"MemberExpression","messageId":"forbidden","endLine":178,"endColumn":12,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":202,"column":12,"nodeType":"CallExpression","endLine":202,"endColumn":35,"fix":{"range":[6111,6119],"text":"Object.assign"},"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":219,"column":3,"nodeType":"MemberExpression","messageId":"forbidden","endLine":219,"endColumn":13,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":226,"column":17,"nodeType":"CallExpression","endLine":226,"endColumn":45,"fix":{"range":[6795,6803],"text":"Object.assign"},"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-each-util","severity":2,"message":"Prefer Array#forEach to $.each","line":230,"column":2,"nodeType":"CallExpression","endLine":258,"endColumn":5,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":260,"column":7,"nodeType":"MemberExpression","messageId":"forbidden","endLine":260,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":262,"column":14,"nodeType":"MemberExpression","messageId":"forbidden","endLine":262,"endColumn":24,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":266,"column":7,"nodeType":"MemberExpression","messageId":"forbidden","endLine":266,"endColumn":17,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":268,"column":14,"nodeType":"MemberExpression","messageId":"forbidden","endLine":268,"endColumn":24,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/variable-pattern","severity":2,"message":"jQuery collection names must match the variablePattern","line":278,"column":4,"nodeType":"VariableDeclarator","endLine":278,"endColumn":20,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-extend","severity":1,"message":"Prefer Object.assign or the spread operator to $.extend","line":287,"column":15,"nodeType":"CallExpression","endLine":287,"endColumn":43,"fix":{"range":[8757,8765],"text":"Object.assign"},"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"no-jquery/no-each-util","severity":2,"message":"Prefer Array#forEach to $.each","line":310,"column":3,"nodeType":"CallExpression","endLine":325,"endColumn":6,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"es-x/no-array-string-prototype-at","severity":2,"message":"ES2022 'Array.prototype.at' method is forbidden.","line":321,"column":9,"nodeType":"MemberExpression","messageId":"forbidden","endLine":321,"endColumn":19,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.mtHelpers/index.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.special.exporttranslations/index.js","messages":[{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":22,"column":25,"nodeType":"CallExpression","endLine":22,"endColumn":64},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":37,"column":29,"nodeType":"CallExpression","endLine":37,"endColumn":82}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":2,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * Entity selector for Special:ExportTranslations that allows users to load\n * messages from typing in a group name.\n * @author Eugene Wang'ombe\n * @license GPL-2.0-or-later, CC-BY-SA-3.0\n */\n\n( function () {\n\t'use strict';\n\n\tfunction activateEntitySelector( $group ) {\n\t\t// hide the message group selector\n\t\tconst $groupContainer = $( '.message-group-selector' );\n\n\t\t// Change the label, and update the for attribute, and remove the click handler\n\t\t// which causes the entity selector to become un-responsive when triggered\n\t\t$groupContainer\n\t\t\t.attr( 'for', 'mw-entity-selector-input' )\n\t\t\t.off( 'click' );\n\n\t\t// Determine what value was set, and set it on the entity selector\n\t\tconst selectedGroup = $group.find( 'select option:selected' ).text();\n\n\t\t// load the entity selector and set the value\n\t\tconst entitySelector = getEntitySelector( onEntitySelect );\n\t\tentitySelector.setValue( selectedGroup );\n\n\t\t$group.addClass( 'hidden' );\n\t\t$group.after( entitySelector.$element );\n\t}\n\n\tfunction onEntitySelect( selectedItem ) {\n\t\t$( 'select[name=\"group\"]' ).val( selectedItem.data );\n\t}\n\n\tfunction onSubmit() {\n\t\tconst selectedGroupName = $( 'select[name=\"group\"]' ).find( 'option:selected' ).text();\n\t\tconst currentVal = $( '.tes-entity-selector' ).find( 'input[type=\"text\"]' ).val();\n\n\t\t// Check if the user has selected an invalid entity.\n\t\tif ( currentVal !== selectedGroupName ) {\n\t\t\tmw.notify(\n\t\t\t\tmw.msg( 'translate-mgs-invalid-group', currentVal ),\n\t\t\t\t{\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttag: 'invalid-selection'\n\t\t\t\t}\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction getEntitySelector( onSelect ) {\n\t\tconst EntitySelector = require( 'ext.translate.entity.selector' );\n\t\treturn new EntitySelector( {\n\t\t\tonSelect: onSelect,\n\t\t\tentityType: [ 'groups' ],\n\t\t\tinputId: 'mw-entity-selector-input'\n\t\t} );\n\t}\n\n\t$( () => {\n\t\tactivateEntitySelector( $( '#group' ) );\n\n\t\t$( '#mw-export-message-group-form' ).on( 'submit', onSubmit );\n\t} );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.special.languagestats/index.js","messages":[{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Positional selector extensions are not allowed","line":20,"column":3,"nodeType":"CallExpression","endLine":20,"endColumn":34},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Positional selector extensions are not allowed","line":21,"column":3,"nodeType":"CallExpression","endLine":21,"endColumn":35},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":214,"column":23,"nodeType":"CallExpression","endLine":214,"endColumn":62},{"ruleId":"no-jquery/no-sizzle","severity":1,"message":"Selector extensions are not allowed","line":242,"column":27,"nodeType":"CallExpression","endLine":242,"endColumn":80},{"ruleId":"compat/compat","severity":1,"message":"ResizeObserver.observe() is not supported in Safari 11.1, iOS Safari 11.3-11.4","line":300,"column":3,"nodeType":"MemberExpression","endLine":318,"endColumn":14},{"ruleId":"compat/compat","severity":1,"message":"ResizeObserver is not supported in Safari 11.1","line":300,"column":3,"nodeType":"NewExpression","endLine":318,"endColumn":6}],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":6,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * Collapsing script for Special:LanguageStats in MediaWiki Extension:Translate\n * @author Krinkle <krinklemail (at) gmail (dot) com>\n * @author Niklas Laxström\n * @license GPL-2.0-or-later, CC-BY-SA-3.0\n */\n\n( function () {\n\t'use strict';\n\n\tvar $columns;\n\n\t/**\n\t * Add css class to every other visible row.\n\t * It's not possible to do zebra colors with CSS only if there are hidden rows.\n\t *\n\t * @param {jQuery} $table\n\t */\n\tfunction doZebra( $table ) {\n\t\t$table.find( 'tr:visible:odd' ).toggleClass( 'tux-statstable-even', false );\n\t\t$table.find( 'tr:visible:even' ).toggleClass( 'tux-statstable-even', true );\n\t}\n\n\tfunction addExpanders( $table ) {\n\t\tvar $metaRows = $( 'tr.AggregateMessageGroup', $table );\n\n\t\t// Quick return\n\t\tif ( !$metaRows.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\t$metaRows.each( function () {\n\t\t\tvar $parent = $( this ),\n\t\t\t\tthisGroupId = $parent.attr( 'data-groupid' ),\n\t\t\t\t$children = $( 'tr[data-parentgroup=\"' + thisGroupId + '\"]', $table );\n\n\t\t\t// Only do the collapse stuff if this Meta-group actually has children on this page\n\t\t\tif ( !$children.length ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Build toggle link\n\t\t\tvar $toggler = $( '<span>' ).addClass( 'groupexpander collapsed' )\n\t\t\t\t.append(\n\t\t\t\t\t'[',\n\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t.attr( 'href', '#' )\n\t\t\t\t\t\t.text( mw.msg( 'translate-langstats-expand' ) ),\n\t\t\t\t\t']'\n\t\t\t\t)\n\t\t\t\t.on( 'click', function ( e ) {\n\t\t\t\t\tvar $el = $( this );\n\t\t\t\t\t// Switch the state and toggle the rows\n\t\t\t\t\tif ( $el.hasClass( 'collapsed' ) ) {\n\t\t\t\t\t\t$children.removeClass( 'statstable-hide' ).trigger( 'show' );\n\t\t\t\t\t\tdoZebra( $table );\n\t\t\t\t\t\t$el.removeClass( 'collapsed' ).addClass( 'expanded' );\n\t\t\t\t\t\t$el.find( '> a' ).text( mw.msg( 'translate-langstats-collapse' ) );\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$children.addClass( 'statstable-hide' ).trigger( 'hide' );\n\t\t\t\t\t\tdoZebra( $table );\n\t\t\t\t\t\t$el.addClass( 'collapsed' ).removeClass( 'expanded' );\n\t\t\t\t\t\t$el.find( '> a' ).text( mw.msg( 'translate-langstats-expand' ) );\n\t\t\t\t\t}\n\n\t\t\t\t\te.preventDefault();\n\t\t\t\t} );\n\n\t\t\t// Add the toggle link to the first cell of the meta group table-row\n\t\t\t$parent.find( ' > td' ).first().append( $toggler );\n\n\t\t\t// Handle hide/show recursively, so that collapsing parent group\n\t\t\t// hides all sub groups regardless of nesting level\n\t\t\t$parent.on( 'hide show', function ( event ) {\n\t\t\t\t// Reuse $toggle, $parent and $children from parent scope\n\t\t\t\tif ( $toggler.hasClass( 'expanded' ) ) {\n\t\t\t\t\t$children.trigger( event.type )[ event.type ]();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\n\t\t// Create, bind and append the toggle-all button\n\t\tvar $allChildRows = $( 'tr[data-parentgroup]', $table );\n\t\tvar $allTogglesCache = null;\n\t\tvar $toggleAllButton = $( '<span>' ).addClass( 'collapsed' )\n\t\t\t.append(\n\t\t\t\t'[',\n\t\t\t\t$( '<a>' )\n\t\t\t\t\t.attr( 'href', '#' )\n\t\t\t\t\t.text( mw.msg( 'translate-langstats-expandall' ) ),\n\t\t\t\t']'\n\t\t\t)\n\t\t\t.on( 'click', function ( e ) {\n\t\t\t\tvar $el = $( this ),\n\t\t\t\t\t$allToggles = $allTogglesCache || $( '.groupexpander', $table );\n\n\t\t\t\t// Switch the state and toggle the rows\n\t\t\t\t// and update the local toggles too\n\t\t\t\tif ( $el.hasClass( 'collapsed' ) ) {\n\t\t\t\t\t$allChildRows.removeClass( 'statstable-hide' );\n\t\t\t\t\t$el.add( $allToggles ).removeClass( 'collapsed' ).addClass( 'expanded' );\n\t\t\t\t\t$el.find( '> a' ).text( mw.msg( 'translate-langstats-collapseall' ) );\n\t\t\t\t\t$allToggles.find( '> a' ).text( mw.msg( 'translate-langstats-collapse' ) );\n\t\t\t\t} else {\n\t\t\t\t\t$allChildRows.addClass( 'statstable-hide' );\n\t\t\t\t\t$el.add( $allToggles ).addClass( 'collapsed' ).removeClass( 'expanded' );\n\t\t\t\t\t$el.find( '> a' ).text( mw.msg( 'translate-langstats-expandall' ) );\n\t\t\t\t\t$allToggles.find( '> a' ).text( mw.msg( 'translate-langstats-expand' ) );\n\t\t\t\t}\n\n\t\t\t\tdoZebra( $table );\n\t\t\t\te.preventDefault();\n\t\t\t} );\n\n\t\t// Initially hide them\n\t\t$allChildRows.addClass( 'statstable-hide' );\n\t\tdoZebra( $table );\n\n\t\t// Add the toggle-all button above the table\n\t\t$( '<p>' ).addClass( 'groupexpander-all' ).append( $toggleAllButton ).insertBefore( $table );\n\t}\n\n\tfunction applySorting( $table ) {\n\t\tvar sort = {},\n\t\t\tre = /#sortable:(\\d+)=(asc|desc)/,\n\t\t\tmatch = re.exec( location.hash );\n\n\t\tif ( match ) {\n\t\t\tvar index = parseInt( match[ 1 ], 10 );\n\t\t\tsort[ index ] = match[ 2 ];\n\t\t}\n\t\t$table.tablesorter( { sortList: [ sort ] } );\n\n\t\t$table.on( 'sortEnd.tablesorter', function () {\n\t\t\t$table.find( '.headerSortDown, .headerSortUp' ).each( function () {\n\t\t\t\tvar headerIndex = $table.find( 'th' ).index( $( this ) ),\n\t\t\t\t\tdir = $( this ).hasClass( 'headerSortUp' ) ? 'asc' : 'desc';\n\t\t\t\tlocation.hash = 'sortable:' + headerIndex + '=' + dir;\n\n\t\t\t\tdoZebra( $table );\n\t\t\t} );\n\t\t} );\n\t}\n\n\tfunction narrowTable( $table, enable ) {\n\t\tvar labelColumnCount = 1,\n\t\t\t// 0-indexed\n\t\t\tdefaultValueColumn = 2;\n\n\t\tif ( $columns === undefined ) {\n\t\t\t$columns = $table.find( 'thead > tr > th ' ).map( function ( index, value ) {\n\t\t\t\treturn value.textContent;\n\t\t\t} );\n\t\t}\n\n\t\tvar $select = makeValueColumnSelector( $columns, labelColumnCount, defaultValueColumn );\n\t\t// Prevent table sorter from making the select inaccessible\n\t\t$select.on( 'mousedown click', function ( e ) {\n\t\t\te.stopPropagation();\n\t\t} ).on( 'change', function () {\n\t\t\tshowValueColumn( $table, $select, labelColumnCount );\n\t\t} );\n\n\t\tif ( enable ) {\n\t\t\tshowValueColumn( $table, $select, labelColumnCount );\n\t\t} else {\n\t\t\t// Restore original headings\n\t\t\t$table.find( 'thead > tr > th' ).map( function ( index ) {\n\t\t\t\treturn $( this ).text( $columns[ index ] );\n\t\t\t} );\n\t\t\t$table.find( 'tr > *' ).removeClass( 'statstable-hide' );\n\t\t}\n\n\t}\n\n\tfunction makeValueColumnSelector( headings, skip, def ) {\n\t\tvar $select = $( '<select>' );\n\n\t\tfor ( var i = skip; i < headings.length; i++ ) {\n\t\t\t$( '<option>' )\n\t\t\t\t.text( headings[ i ] )\n\t\t\t\t.val( i )\n\t\t\t\t.prop( 'selected', i === def )\n\t\t\t\t.appendTo( $select );\n\t\t}\n\n\t\treturn $select;\n\t}\n\n\tfunction showValueColumn( $table, $select, skip ) {\n\t\tvar index = parseInt( $select.val(), 10 );\n\t\tvar cssQuery = 'th:nth-child(_)'.replace( '_', index + 1 );\n\t\t$table.find( cssQuery ).html( $select );\n\n\t\tfor ( var i = 0; i < $select.children().length; i++ ) {\n\t\t\tcssQuery = 'tr > *:nth-child(_)'.replace( '_', i + skip + 1 );\n\t\t\t$table.find( cssQuery ).toggleClass( 'statstable-hide', i + skip !== index );\n\t\t}\n\t}\n\n\tfunction activateEntitySelector( $group, $messagePrefix ) {\n\t\t// hide the message group and prefix selector\n\t\tvar $groupContainer = $( '.message-group-selector' );\n\n\t\t// Change the label, and update the for attribute, and remove the click handler\n\t\t// which causes the entity selector to become un-responsive when triggered\n\t\t$groupContainer\n\t\t\t.find( 'label' )\n\t\t\t.text( mw.msg( 'translate-mgs-group-or-prefix' ) )\n\t\t\t.attr( 'for', 'mw-entity-selector-input' )\n\t\t\t.off( 'click' );\n\n\t\t// Determine what value was set, and set it on the entity selector\n\t\tvar selectedGroup = $group.find( 'select option:selected' ).text();\n\n\t\t// load the entity selector and set the value\n\t\tvar entitySelector = getEntitySelector( onEntitySelect );\n\t\tif ( selectedGroup ) {\n\t\t\tentitySelector.setValue( selectedGroup );\n\t\t} else {\n\t\t\tvar selectedMessage = $messagePrefix.val();\n\t\t\tif ( selectedMessage ) {\n\t\t\t\tentitySelector.setValue( selectedMessage );\n\t\t\t}\n\t\t}\n\n\t\t$group.addClass( 'hidden' );\n\t\t$group.after( entitySelector.$element );\n\t}\n\n\tfunction onEntitySelect( selectedItem ) {\n\t\tif ( selectedItem.type === 'group' ) {\n\t\t\t$( 'select[name=\"group\"]' ).val( selectedItem.data );\n\t\t\t$( 'input[name=\"messages\"]' ).val( '' );\n\t\t} else {\n\t\t\t$( 'input[name=\"messages\"]' ).val( selectedItem.data );\n\t\t\t$( 'select[name=\"group\"]' ).val( '' );\n\t\t}\n\t}\n\n\tfunction onSubmit() {\n\t\tvar selectedGroupName = $( 'select[name=\"group\"]' ).find( 'option:selected' ).text();\n\t\tvar selectedMessagePrefix = $( 'input[name=\"messages\"]' ).val();\n\t\tvar currentVal = $( '.tes-entity-selector' ).find( 'input[type=\"text\"]' ).val();\n\n\t\t// Check if the user has selected an invalid entity.\n\t\tif ( currentVal !== selectedGroupName && currentVal !== selectedMessagePrefix ) {\n\t\t\tmw.notify(\n\t\t\t\tmw.msg( 'translate-mgs-invalid-entity' ),\n\t\t\t\t{\n\t\t\t\t\ttype: 'error',\n\t\t\t\t\ttag: 'invalid-selection'\n\t\t\t\t}\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tfunction getEntitySelector( onSelect ) {\n\t\tvar EntitySelector = require( 'ext.translate.entity.selector' );\n\t\treturn new EntitySelector( {\n\t\t\tonSelect: onSelect,\n\t\t\tentityType: [ 'groups', 'messages' ],\n\t\t\tinputId: 'mw-entity-selector-input'\n\t\t} );\n\t}\n\n\t$( function () {\n\t\tvar $table = $( '.statstable' );\n\n\t\tactivateEntitySelector( $( '#group' ), $( 'input[name=\"messages\"]' ) );\n\n\t\t// Sometimes the table is not present on the page\n\t\tif ( !$table.length ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Calculate absolute minimum table width\n\t\tif ( window.ResizeObserver ) {\n\t\t\t$table.css( 'max-width', '1px' );\n\t\t}\n\n\t\tapplySorting( $table );\n\t\taddExpanders( $table );\n\n\t\t$( '#mw-message-group-stats-form' ).on( 'submit', onSubmit );\n\n\t\tif ( !window.ResizeObserver ) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar minimumTableWidth;\n\t\t// Hopefully previous stuff have time to render by now to have accurate picture of the width\n\t\t( window.requestAnimationFrame || setTimeout )( function () {\n\t\t\tminimumTableWidth = $table.outerWidth();\n\t\t\t$table.css( 'max-width', '' );\n\t\t} );\n\n\t\tvar isNarrowMode;\n\t\tnew ResizeObserver( function ( entries ) {\n\t\t\tvar shouldCollapse = entries[ 0 ].contentRect.width < minimumTableWidth;\n\t\t\t// Some fudge to avoid flapping\n\t\t\tvar shouldExpand = entries[ 0 ].contentRect.width - 20 > minimumTableWidth;\n\n\t\t\tvar newMode;\n\t\t\tif ( isNarrowMode && shouldExpand ) {\n\t\t\t\tnewMode = false;\n\t\t\t} else if ( !isNarrowMode && shouldCollapse ) {\n\t\t\t\tnewMode = true;\n\t\t\t} else {\n\t\t\t\tnewMode = isNarrowMode;\n\t\t\t}\n\n\t\t\tif ( newMode !== isNarrowMode ) {\n\t\t\t\tisNarrowMode = newMode;\n\t\t\t\tnarrowTable( $table, isNarrowMode );\n\t\t\t}\n\t\t} ).observe( $table.parent().get( 0 ) );\n\t} );\n}() );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.special.managemessagegroupsubscriptions/index.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.specialTranslationStash/index.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":172,"column":2,"nodeType":"CallExpression","endLine":200,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":172,"column":2,"nodeType":"CallExpression","endLine":205,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":247,"column":2,"nodeType":"CallExpression","endLine":255,"endColumn":6}],"suppressedMessages":[],"errorCount":3,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * TranslationStash front-end logic.\n *\n * @author Santhosh Thottingal\n * @license GPL-2.0-or-later\n * @since 2013.10\n */\n'use strict';\n\nvar userTranslations = {},\n\tTranslationStashStorage = require( './storage.js' ),\n\ttranslationStorage = new TranslationStashStorage();\n\nmw.translate.canTranslate = function () {\n\t// At this page, the new translator can translate\n\treturn true;\n};\n\nfunction getMessages( messageGroup, language, offset, limit ) {\n\tvar deferred = new mw.Api().get( {\n\t\taction: 'query',\n\t\tlist: 'messagecollection',\n\t\tmcgroup: messageGroup,\n\t\tmclanguage: language,\n\t\tmcoffset: offset,\n\t\tmclimit: limit,\n\t\tmcprop: 'definition'\n\t} );\n\n\treturn deferred.promise();\n}\n\nfunction addMessage( message ) {\n\tvar $messageTable = $( '.tux-messagelist' ),\n\t\tsourceLanguage = $messageTable.data( 'sourcelangcode' ),\n\t\tsourceLanguageDir = $.uls.data.getDir( sourceLanguage ),\n\t\ttargetLanguage = $messageTable.data( 'targetlangcode' ),\n\t\ttargetLanguageDir = $.uls.data.getDir( targetLanguage ),\n\t\tstatus = message.properties.status,\n\t\tstatusClass = 'tux-status-' + status;\n\n\tvar statusMsg;\n\tif ( status === 'translated' ) {\n\t\t// tux-status-translated\n\t\tstatusMsg = 'tux-status-' + status;\n\t}\n\n\tvar $messageWrapper = $( '<div>' )\n\t\t.addClass( 'row tux-message' );\n\n\tvar $message = $( '<div>' )\n\t\t.addClass( 'row message tux-message-item ' + status )\n\t\t.append(\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'eight columns tux-list-message' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.addClass( 'tux-list-source' )\n\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\tlang: sourceLanguage,\n\t\t\t\t\t\t\tdir: sourceLanguageDir\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.text( message.definition ),\n\t\t\t\t\t// Bidirectional isolation.\n\t\t\t\t\t// This should be removed some day when proper\n\t\t\t\t\t// unicode-bidi: isolate\n\t\t\t\t\t// is supported everywhere\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.html( $( document.body ).hasClass( 'rtl' ) ? '&rlm;' : '&lrm;' ),\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.addClass( 'tux-list-translation' )\n\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\tlang: targetLanguage,\n\t\t\t\t\t\t\tdir: targetLanguageDir\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.text( message.translation || '' )\n\t\t\t\t),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'two columns tux-list-status text-center' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<span>' )\n\t\t\t\t\t\t.addClass( statusClass )\n\t\t\t\t\t\t// The following messages are used here:\n\t\t\t\t\t\t// * tux-status-optional\n\t\t\t\t\t\t// * tux-status-fuzzy\n\t\t\t\t\t\t// * tux-status-proofread\n\t\t\t\t\t\t// * tux-status-translated\n\t\t\t\t\t\t// * tux-status-saving\n\t\t\t\t\t\t// * tux-status-unsaved\n\t\t\t\t\t\t.text( statusMsg ? mw.msg( statusMsg ) : '' )\n\t\t\t\t),\n\t\t\t$( '<div>' )\n\t\t\t\t.addClass( 'two column tux-list-edit text-right' )\n\t\t\t\t.append(\n\t\t\t\t\t$( '<a>' )\n\t\t\t\t\t\t.attr( {\n\t\t\t\t\t\t\ttitle: mw.msg( 'translate-edit-title', message.key )\n\t\t\t\t\t\t} )\n\t\t\t\t\t\t.text( mw.msg( 'tux-edit' ) )\n\t\t\t\t)\n\t\t);\n\n\t$messageWrapper.append( $message );\n\t$messageTable.append( $messageWrapper );\n\t// Attach translate editor to the message\n\t$messageWrapper.translateeditor( {\n\t\tmessage: message,\n\t\tstorage: translationStorage,\n\t\tonSave: updateStats,\n\t\tonSkip: function () {\n\t\t\tvar $next = this.$editTrigger.next( '.tux-message' );\n\n\t\t\t// If there is text in the skipped message, avoid showing the\n\t\t\t// regular \"you have unsaved messages\" when navigating away,\n\t\t\t// because there is no way to get back to these messages.\n\t\t\tthis.markUnunsaved();\n\n\t\t\t// This can happen when it's\n\t\t\t// the last message in the translation stash\n\t\t\tif ( !$next.length ) {\n\t\t\t\t// Reload the page to get more messages\n\t\t\t\t// when we get to the last one\n\t\t\t\twindow.location.reload();\n\t\t\t}\n\t\t},\n\t\tonReady: function () {\n\t\t\tthis.$editor.find( '.tux-editor-skip-button' )\n\t\t\t\t.text( mw.msg( 'translate-translationstash-skip-button-label' ) );\n\t\t}\n\t} );\n}\n\n/**\n * Updates the translation count at the top of the message list and\n * displays warning when translation limit has been reached.\n * Relies on classes stash-stats and tux-status-translated.\n */\nfunction updateStats() {\n\tvar $target = $( '.stash-stats' );\n\n\tvar count = $( '.tux-status-translated' ).length;\n\tif ( count === 0 ) {\n\t\treturn;\n\t}\n\n\t$target.text( mw.msg(\n\t\t'translate-translationstash-translations',\n\t\tmw.language.convertNumber( count )\n\t) );\n\n\tif ( count >= mw.config.get( 'wgTranslateSandboxLimit' ) ) {\n\t\t// Remove the untranslated message to disallow translation beyond the limit\n\t\t$( '.tux-message' ).has( '.untranslated' ).remove();\n\n\t\t// Show a message telling that the limit was reached\n\t\t$( '.limit-reached' )\n\t\t\t.empty()\n\t\t\t.append( $( '<h1>' ).text( mw.msg( 'tsb-limit-reached-title' ) ) )\n\t\t\t.append( $( '<p>' ).text( mw.msg( 'tsb-limit-reached-body' ) ) )\n\t\t\t.removeClass( 'hide' );\n\t}\n}\n\nfunction loadMessages() {\n\tvar $messageTable = $( '.tux-messagelist' ),\n\t\tmessagegroup = '!sandbox';\n\n\t$( '<div>' )\n\t\t.addClass( 'tux-loading-indicator' )\n\t\t.appendTo( $messageTable );\n\n\tgetMessages( messagegroup, $messageTable.data( 'targetlangcode' ) )\n\t\t.done( function ( result ) {\n\t\t\tvar messages = result.query.messagecollection;\n\n\t\t\t// Remove error class if it was previously added in .fail() below\n\t\t\t$messageTable.empty().removeClass( 'error' );\n\t\t\tmessages.forEach( function ( message ) {\n\t\t\t\tmessage.properties = {};\n\t\t\t\tmessage.properties.status = 'untranslated';\n\n\t\t\t\tmessage.group = messagegroup;\n\t\t\t\tif ( userTranslations[ message.title ] ) {\n\t\t\t\t\tmessage.translation = userTranslations[ message.title ].translation;\n\t\t\t\t\tmessage.properties.status = 'translated';\n\t\t\t\t}\n\n\t\t\t\taddMessage( message );\n\t\t\t} );\n\n\t\t\t// Show the editor for the first untranslated message.\n\t\t\tvar $untranslated = $( '.tux-message' )\n\t\t\t\t.has( '.tux-message-item.untranslated' )\n\t\t\t\t.first();\n\t\t\tif ( $untranslated.length ) {\n\t\t\t\t$untranslated.data( 'translateeditor' ).show();\n\t\t\t}\n\n\t\t\tupdateStats();\n\t\t} ).fail( function ( errorCode, response ) {\n\t\t\t$messageTable.empty().addClass( 'error' )\n\t\t\t\t.text( 'Error: ' + errorCode + ' - ' +\n\t\t\t\t\t( response.error && response.error.info || 'Unknown error' )\n\t\t\t\t);\n\t\t} );\n}\n\n$( function () {\n\tvar $messageTable = $( '.tux-messagelist' ),\n\t\t$ulsTrigger = $( '.ext-translate-language-selector > .uls' );\n\n\t// Some links in helpers will navigate away by default. But since the messages\n\t// will change on this page on every load, we want to avoid that. Force the\n\t// links to open on new window/tab.\n\tmw.hook( 'mw.translate.editor.showTranslationHelpers' ).add( function ( helpers, $editor ) {\n\t\t$editor.find( 'a' ).prop( 'target', '_blank' );\n\t} );\n\n\t$ulsTrigger.uls( {\n\t\tulsPurpose: 'translate-special-translationstash',\n\t\tonSelect: function ( languageCode ) {\n\t\t\tvar languageDetails = mw.translate.getLanguageDetailsForHtml( languageCode );\n\n\t\t\t$ulsTrigger\n\t\t\t\t.find( '.ext-translate-target-language' )\n\t\t\t\t.text( languageDetails.autonym )\n\t\t\t\t.prop( {\n\t\t\t\t\tlang: languageDetails.code,\n\t\t\t\t\tdir: languageDetails.direction\n\t\t\t\t} );\n\n\t\t\t$messageTable\n\t\t\t\t.empty()\n\t\t\t\t.data( {\n\t\t\t\t\ttargetlangcode: languageCode,\n\t\t\t\t\ttargetlangdir: languageDetails.direction\n\t\t\t\t} );\n\n\t\t\tloadMessages();\n\t\t}\n\t} ).on( 'keypress', function () {\n\t\t$( this ).trigger( 'click' );\n\t} );\n\n\t// Get the user translations if any(possibly from an early attempt)\n\t// and new messages to try.\n\ttranslationStorage.getUserTranslations()\n\t\t.done( function ( translations ) {\n\t\t\tif ( translations.translationstash.translations ) {\n\t\t\t\ttranslations.translationstash.translations.forEach( function ( translation ) {\n\t\t\t\t\tuserTranslations[ translation.title ] = translation;\n\t\t\t\t} );\n\t\t\t}\n\t\t\tloadMessages();\n\t\t} );\n} );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ext.translate.specialTranslationStash/storage.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/services/aggregategroup.api.factory.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/services/translationentitysearch.api.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ve-translate/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ve-translate/ve.ce.MWTranslateAnnotationNode.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ve-translate/ve.dm.MWTranslateAnnotationNode.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js","messages":[],"suppressedMessages":[{"ruleId":"mediawiki/msg-doc","severity":2,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":45,"column":12,"nodeType":"CallExpression","endLine":45,"endColumn":37,"suppressions":[{"kind":"directive","justification":""}]},{"ruleId":"mediawiki/msg-doc","severity":2,"message":"All possible message keys should be documented. See https://w.wiki/4r9a for details.","line":60,"column":12,"nodeType":"CallExpression","endLine":60,"endColumn":37,"suppressions":[{"kind":"directive","justification":""}]}],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-revtag-int-to-bigint-unsigned.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-revtag-unique-to-pk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-translate_message_group_subscriptions-composite-primary-key.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-translate_messageindex-unique-to-pk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-translate_reviews-unsigned.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/abstractSchemaChanges/patch-translate_tmt-unique-to-pk.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/sql/tables.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/parser/translateParserTests-knownFailures.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/MediaWikiExtensionTest-conf2.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/MediaWikiExtensionTest-conf3.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/MediaWikiExtensionTest-conf4.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/MessageLoaderGroups.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/MixedSourceLanguageGroups.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/ParentGroups.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/ValidatorGroup.yaml","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-len","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/phpunit/data/jsontest_fi.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/.eslintrc.json","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"indent","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"no-extra-parens","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/ext.translate.parsers.test.js","messages":[],"suppressedMessages":[],"errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]},{"filePath":"/src/repo/tests/qunit/ext.translate.special.pagemigration.test.js","messages":[{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":17,"column":3,"nodeType":"CallExpression","endLine":20,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .fail","line":31,"column":3,"nodeType":"CallExpression","endLine":34,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":46,"column":3,"nodeType":"CallExpression","endLine":49,"endColumn":6},{"ruleId":"no-jquery/no-done-fail","severity":2,"message":"Prefer .then to .done","line":61,"column":3,"nodeType":"CallExpression","endLine":65,"endColumn":7}],"suppressedMessages":[],"errorCount":4,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0,"source":"/*!\n * @license GPL-2.0-or-later\n */\nQUnit.module( 'ext.translate.special.pagemigration', function ( hooks ) {\n\t'use strict';\n\n\thooks.beforeEach( function () {\n\t\tthis.server = this.sandbox.useFakeServer();\n\t} );\n\n\tQUnit.test( 'Source units', function ( assert ) {\n\t\tvar data = '{ \"query\": { \"messagecollection\": [ { \"key\": \"key_\",' +\n\t\t\t' \"definition\": \"definition_\", \"title\": \"title_\" }, { \"key\": \"key_1\",' +\n\t\t\t' \"definition\": \"definition_1\", \"title\": \"title_1\" } ] } }';\n\n\t\tvar done = assert.async();\n\t\tmw.translate.getSourceUnits( 'Help:Special pages' ).done( function ( sourceUnits ) {\n\t\t\tassert.strictEqual( sourceUnits.length, 2, 'Source units retrieved' );\n\t\t\tdone();\n\t\t} );\n\n\t\tthis.server.respond( function ( request ) {\n\t\t\trequest.respond( 200, { 'Content-Type': 'application/json' }, data );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'Page does not exist', function ( assert ) {\n\t\tvar data = '{ \"query\": { \"pages\": { \"-1\": { \"missing\": \"\" } } } }';\n\n\t\tvar done = assert.async();\n\t\tmw.translate.getFuzzyTimestamp( 'ugagagagagaga/uga' ).fail( function ( timestamp ) {\n\t\t\tassert.strictEqual( timestamp, undefined, 'Page does not exist' );\n\t\t\tdone();\n\t\t} );\n\n\t\tthis.server.respond( function ( request ) {\n\t\t\trequest.respond( 200, { 'Content-Type': 'application/json' }, data );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'Fuzzy timestamp', function ( assert ) {\n\t\tvar data = '{ \"query\": { \"pages\": [ { \"pageid\": \"19563\", \"revisions\": ' +\n\t\t\t'[ {\"timestamp\": \"2014-02-18T20:59:58Z\" }, { \"timestamp\": \"t2\" } ] } ] } }';\n\n\t\tvar done = assert.async();\n\t\tmw.translate.getFuzzyTimestamp( 'Help:Special pages/fr' ).done( function ( timestamp ) {\n\t\t\tassert.strictEqual( timestamp, '2014-02-18T20:59:57.000Z', 'Fuzzy timestamp retrieved' );\n\t\t\tdone();\n\t\t} );\n\n\t\tthis.server.respond( function ( request ) {\n\t\t\trequest.respond( 200, { 'Content-Type': 'application/json' }, data );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'Split translation page', function ( assert ) {\n\t\tvar data = '{ \"query\": { \"pages\": [ { \"pageid\": \"19563\", \"revisions\": ' +\n\t\t\t'[ { \"content\": \"unit1\\\\n\\\\nunit2\\\\n\\\\nunit3\" } ] } ] } }';\n\n\t\tvar done = assert.async();\n\t\tmw.translate.splitTranslationPage( '2014-02-18T20:59:57.000Z', 'Help:Special pages/fr' )\n\t\t\t.done( function ( translationUnits ) {\n\t\t\t\tassert.strictEqual( translationUnits.length, 3, 'Translation page split into units' );\n\t\t\t\tdone();\n\t\t\t} );\n\n\t\tthis.server.respond( function ( request ) {\n\t\t\trequest.respond( 200, { 'Content-Type': 'application/json' }, data );\n\t\t} );\n\t} );\n\n\tQUnit.test( 'Split headers', function ( assert ) {\n\t\tvar translationUnits, expected, result;\n\t\ttranslationUnits = [\n\t\t\t'== already split ==',\n\t\t\t'some text\\nwith a newline',\n\t\t\t'==nospace l2==\\nabc',\n\t\t\t'===nospacel3===\\ndef',\n\t\t\t'== spaced l2 ==\\nghi',\n\t\t\t'=== spaced l3 ===\\njkl',\n\t\t\t'== bad spacing==\\nmno',\n\t\t\t'== multiple ==\\n===headers===\\nin\\n===succession===\\npqr',\n\t\t\t'== header ==\\nmore text\\nwith a newline'\n\t\t];\n\t\texpected = [\n\t\t\t'== already split ==',\n\t\t\t'some text\\nwith a newline',\n\t\t\t'==nospace l2==',\n\t\t\t'abc',\n\t\t\t'===nospacel3===',\n\t\t\t'def',\n\t\t\t'== spaced l2 ==',\n\t\t\t'ghi',\n\t\t\t'=== spaced l3 ===',\n\t\t\t'jkl',\n\t\t\t'== bad spacing==',\n\t\t\t'mno',\n\t\t\t'== multiple ==',\n\t\t\t'===headers===',\n\t\t\t'in\\n',\n\t\t\t'===succession===',\n\t\t\t'pqr',\n\t\t\t'== header ==',\n\t\t\t'more text\\nwith a newline'\n\t\t];\n\t\tresult = mw.translate.splitHeaders( translationUnits );\n\t\tassert.deepEqual( result, expected, 'Headers split into separate units' );\n\n\t} );\n\n\tQUnit.test( 'Align h2 headers', function ( assert ) {\n\t\tvar sourceUnits = [\n\t\t\t{ identifier: '1', definition: 'abc' }, { identifier: '2', definition: '==123==' },\n\t\t\t{ identifier: '3', definition: 'pqr' }, { identifier: '4', definition: 'xyz' },\n\t\t\t{ identifier: '5', definition: 'mno' }, { identifier: '6', definition: '==456==' }\n\t\t];\n\n\t\tvar translationUnits1 = [ '==123==', 'pqr', '==456==' ];\n\t\tvar translationUnits2 = [ 'abc', 'lmn', '==123==', 'pqr', '==456==' ];\n\n\t\tvar result1 = [ '', '==123==', 'pqr', '', '', '==456==' ];\n\t\tvar result2 = [ 'abc\\nlmn\\n', '==123==', 'pqr', '', '', '==456==' ];\n\n\t\ttranslationUnits1 = mw.translate.alignHeaders( sourceUnits, translationUnits1 );\n\t\tassert.deepEqual( result1, translationUnits1, 'h2 headers aligned without merging' );\n\n\t\ttranslationUnits2 = mw.translate.alignHeaders( sourceUnits, translationUnits2 );\n\t\tassert.deepEqual( result2, translationUnits2, 'h2 headers aligned with merging' );\n\t} );\n} );\n","usedDeprecatedRules":[{"ruleId":"arrow-parens","replacedBy":[]},{"ruleId":"arrow-spacing","replacedBy":[]},{"ruleId":"lines-between-class-members","replacedBy":[]},{"ruleId":"no-new-require","replacedBy":[]},{"ruleId":"template-curly-spacing","replacedBy":[]},{"ruleId":"implicit-arrow-linebreak","replacedBy":[]},{"ruleId":"array-bracket-spacing","replacedBy":[]},{"ruleId":"block-spacing","replacedBy":[]},{"ruleId":"brace-style","replacedBy":[]},{"ruleId":"comma-dangle","replacedBy":[]},{"ruleId":"comma-spacing","replacedBy":[]},{"ruleId":"comma-style","replacedBy":[]},{"ruleId":"computed-property-spacing","replacedBy":[]},{"ruleId":"dot-location","replacedBy":[]},{"ruleId":"eol-last","replacedBy":[]},{"ruleId":"func-call-spacing","replacedBy":[]},{"ruleId":"indent","replacedBy":[]},{"ruleId":"key-spacing","replacedBy":[]},{"ruleId":"keyword-spacing","replacedBy":[]},{"ruleId":"linebreak-style","replacedBy":[]},{"ruleId":"max-statements-per-line","replacedBy":[]},{"ruleId":"new-parens","replacedBy":[]},{"ruleId":"no-floating-decimal","replacedBy":[]},{"ruleId":"no-multi-spaces","replacedBy":[]},{"ruleId":"no-multiple-empty-lines","replacedBy":[]},{"ruleId":"no-new-object","replacedBy":["no-object-constructor"]},{"ruleId":"no-tabs","replacedBy":[]},{"ruleId":"no-trailing-spaces","replacedBy":[]},{"ruleId":"no-whitespace-before-property","replacedBy":[]},{"ruleId":"object-curly-spacing","replacedBy":[]},{"ruleId":"operator-linebreak","replacedBy":[]},{"ruleId":"quote-props","replacedBy":[]},{"ruleId":"quotes","replacedBy":[]},{"ruleId":"semi","replacedBy":[]},{"ruleId":"semi-spacing","replacedBy":[]},{"ruleId":"semi-style","replacedBy":[]},{"ruleId":"space-before-blocks","replacedBy":[]},{"ruleId":"space-before-function-paren","replacedBy":[]},{"ruleId":"space-in-parens","replacedBy":[]},{"ruleId":"space-infix-ops","replacedBy":[]},{"ruleId":"space-unary-ops","replacedBy":[]},{"ruleId":"spaced-comment","replacedBy":[]},{"ruleId":"switch-colon-spacing","replacedBy":[]},{"ruleId":"wrap-iife","replacedBy":[]},{"ruleId":"no-extra-semi","replacedBy":[]},{"ruleId":"no-mixed-spaces-and-tabs","replacedBy":[]}]}]

--- end ---
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in resources/.eslintrc.json) on resources/.eslintrc.json
Disabling eslint rule 'no-jquery/no-done-fail' (broken in tests/qunit/.eslintrc.json) on tests/qunit/.eslintrc.json
$ /usr/bin/npm ci
--- stderr ---
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '@wikimedia/codex-design-tokens@1.21.1',
npm WARN EBADENGINE   required: { node: '>=20', npm: '>=10.8.1' },
npm WARN EBADENGINE   current: { node: 'v18.19.0', npm: '9.2.0' }
npm WARN EBADENGINE }
--- stdout ---

added 445 packages, and audited 446 packages in 6s

95 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

--- end ---
$ /usr/bin/npm test
--- stdout ---

> test
> grunt test

Running "eslint:all" (eslint) task

/src/repo/resources/js/ext.translate.base.js
   6:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  40:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  66:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.editor.helpers.js
   32:3   warning  Missing JSDoc @return declaration                        jsdoc/require-returns
   84:11  warning  Prefer .then to .done                                    no-jquery/no-done-fail
   84:11  warning  Prefer .then to .fail                                    no-jquery/no-done-fail
   93:6   warning  Prefer .then to .done                                    no-jquery/no-done-fail
   93:6   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  393:1   warning  Missing JSDoc @param "e" type                            jsdoc/require-param-type
  394:1   warning  Missing JSDoc @param "suggestion" type                   jsdoc/require-param-type
  677:5   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  714:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  714:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  802:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  819:2   warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.editor.js
   270:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
   270:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
   773:6   warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  1124:22  warning  Prefer .then to .done                                    no-jquery/no-done-fail
  1283:7   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  1646:24  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.editor.shortcuts.js
  37:4  warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  73:2  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.messagerenamedialog.js
  250:2  warning  Prefer .then to .done  no-jquery/no-done-fail
  250:2  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.messagetable.js
   11:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   73:5   warning  ES2024 Resizable ArrayBuffer is forbidden                es-x/no-resizable-and-growable-arraybuffers
  275:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  285:25  warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  392:9   warning  Selector extensions are not allowed                      no-jquery/no-sizzle
  406:16  warning  Positional selector extensions are not allowed           no-jquery/no-sizzle
  409:5   warning  ES2024 Resizable ArrayBuffer is forbidden                es-x/no-resizable-and-growable-arraybuffers
  422:20  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  488:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  488:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  535:7   warning  Positional selector extensions are not allowed           no-jquery/no-sizzle

/src/repo/resources/js/ext.translate.parsers.js
  13:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.proofread.js
  235:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  235:4  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.aggregategroups.js
   19:16  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   24:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail
   24:3   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
   70:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   75:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
   75:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
   99:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
  103:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  103:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  145:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  145:3   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  397:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  397:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.managegroups.js
   18:11  warning  Prefer .then to .done  no-jquery/no-done-fail
   18:11  warning  Prefer .then to .fail  no-jquery/no-done-fail
   68:4   warning  Prefer .then to .done  no-jquery/no-done-fail
   68:4   warning  Prefer .then to .fail  no-jquery/no-done-fail
   98:4   warning  Prefer .then to .done  no-jquery/no-done-fail
   98:4   warning  Prefer .then to .fail  no-jquery/no-done-fail
  368:4   warning  Prefer .then to .done  no-jquery/no-done-fail
  368:4   warning  Prefer .then to .fail  no-jquery/no-done-fail
  391:4   warning  Prefer .then to .done  no-jquery/no-done-fail
  391:4   warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.managetranslatorsandbox.js
  100:8  warning  Prefer .then to .done  no-jquery/no-done-fail
  100:8  warning  Prefer .then to .fail  no-jquery/no-done-fail
  128:8  warning  Prefer .then to .done  no-jquery/no-done-fail
  145:8  warning  Prefer .then to .done  no-jquery/no-done-fail
  185:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  305:8  warning  Prefer .then to .done  no-jquery/no-done-fail
  322:8  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.pagemigration.js
  134:10  warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  388:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  388:4   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  562:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/js/ext.translate.special.pagepreparation.js
  327:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  327:4  warning  Prefer .then to .fail  no-jquery/no-done-fail
  354:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  354:4  warning  Prefer .then to .fail  no-jquery/no-done-fail
  372:5  warning  Prefer .then to .done  no-jquery/no-done-fail
  372:5  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.pagetranslation.js
  36:3  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.special.translate.js
   19:17  warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend
   59:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
   96:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  236:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  269:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  269:3   warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  664:4   warning  Prefer .then to .done                                    no-jquery/no-done-fail
  736:3   warning  Prefer .then to .done                                    no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.statsbar.js
  33:4  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.translationstats.graphbuilder.js
  69:3   warning  Missing JSDoc @return declaration    jsdoc/require-returns
  70:1   warning  Missing JSDoc @param "options" type  jsdoc/require-param-type
  85:11  warning  Prefer .then to .fail                no-jquery/no-done-fail

/src/repo/resources/js/ext.translate.workflowselector.js
   52:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  146:5  warning  Prefer .then to .done  no-jquery/no-done-fail
  146:5  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/js/jquery.ajaxdispatcher.js
  19:10  warning  Prefer .then to .fail                                    no-jquery/no-done-fail
  65:2   warning  Prefer Object.assign or the spread operator to $.extend  no-jquery/no-extend

/src/repo/resources/src/ext.translate.aggregategroups.refresh/components/AggregateGroupDialog.vue
  143:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  143:4  warning  Prefer .then to .fail  no-jquery/no-done-fail

/src/repo/resources/src/ext.translate.groupselector/index.js
  156:5  warning  Prefer .then to .done  no-jquery/no-done-fail
  348:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  391:4  warning  Prefer .then to .done  no-jquery/no-done-fail
  450:4  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/resources/src/ext.translate.special.exporttranslations/index.js
  22:25  warning  Selector extensions are not allowed  no-jquery/no-sizzle
  37:29  warning  Selector extensions are not allowed  no-jquery/no-sizzle

/src/repo/resources/src/ext.translate.special.languagestats/index.js
   20:3   warning  Positional selector extensions are not allowed                                  no-jquery/no-sizzle
   21:3   warning  Positional selector extensions are not allowed                                  no-jquery/no-sizzle
  214:23  warning  Selector extensions are not allowed                                             no-jquery/no-sizzle
  242:27  warning  Selector extensions are not allowed                                             no-jquery/no-sizzle
  300:3   warning  ResizeObserver.observe() is not supported in Safari 11.1, iOS Safari 11.3-11.4  compat/compat
  300:3   warning  ResizeObserver is not supported in Safari 11.1                                  compat/compat

/src/repo/resources/src/ext.translate.specialTranslationStash/index.js
  172:2  warning  Prefer .then to .done  no-jquery/no-done-fail
  172:2  warning  Prefer .then to .fail  no-jquery/no-done-fail
  247:2  warning  Prefer .then to .done  no-jquery/no-done-fail

/src/repo/tests/qunit/ext.translate.special.pagemigration.test.js
  17:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  31:3  warning  Prefer .then to .fail  no-jquery/no-done-fail
  46:3  warning  Prefer .then to .done  no-jquery/no-done-fail
  61:3  warning  Prefer .then to .done  no-jquery/no-done-fail

✖ 118 problems (0 errors, 118 warnings)


Running "banana:PageTranslation" (banana) task
>> 1 message directory checked.

Running "banana:Translate" (banana) task
>> 1 message directory checked.

Running "banana:TranslateApi" (banana) task
>> 1 message directory checked.

Running "banana:TranslateSandbox" (banana) task
>> 1 message directory checked.

Running "banana:TranslateSearch" (banana) task
>> 1 message directory checked.

Running "stylelint:all" (stylelint) task
>> Linted 37 files without errors

Done.

--- end ---
$ /usr/bin/npm audit --json
--- stdout ---
{
  "auditReportVersion": 2,
  "vulnerabilities": {},
  "metadata": {
    "vulnerabilities": {
      "info": 0,
      "low": 0,
      "moderate": 0,
      "high": 0,
      "critical": 0,
      "total": 0
    },
    "dependencies": {
      "prod": 1,
      "dev": 445,
      "optional": 0,
      "peer": 1,
      "peerOptional": 0,
      "total": 445
    }
  }
}

--- end ---
$ package-lock-lint package-lock.json
--- stdout ---
Checking package-lock.json

--- end ---
build: Updating eslint-config-wikimedia to 0.29.1

The following rules are failing and were disabled:
* resources:
  * no-jquery/no-done-fail* tests/qunit:
  * no-jquery/no-done-fail

$ git add .
--- stdout ---

--- end ---
$ git commit -F /tmp/tmpnpfgbk9z
--- stdout ---
[master 2162419] build: Updating eslint-config-wikimedia to 0.29.1
 17 files changed, 50 insertions(+), 45 deletions(-)

--- end ---
$ git format-patch HEAD~1 --stdout
--- stdout ---
From 216241917b758eeae5abb770798eb84dc62953ad Mon Sep 17 00:00:00 2001
From: libraryupgrader <tools.libraryupgrader@tools.wmflabs.org>
Date: Mon, 31 Mar 2025 06:36:23 +0000
Subject: [PATCH] build: Updating eslint-config-wikimedia to 0.29.1

The following rules are failing and were disabled:
* resources:
  * no-jquery/no-done-fail* tests/qunit:
  * no-jquery/no-done-fail

Change-Id: I1953f37dfe776fda2d996fbd90f961121a200a87
---
 package-lock.json                             | 35 ++++++++++---------
 package.json                                  |  2 +-
 resources/.eslintrc.json                      |  3 +-
 resources/js/ext.translate.editor.js          |  2 +-
 .../js/ext.translate.messagerenamedialog.js   |  4 +--
 resources/js/ext.translate.messagetable.js    | 10 +++---
 resources/js/ext.translate.proofread.js       |  2 +-
 ...anslate.special.managetranslatorsandbox.js |  4 +--
 .../js/ext.translate.special.pagemigration.js |  2 +-
 .../ext.translate.special.pagepreparation.js  |  4 +--
 ...xt.translate.special.searchtranslations.js |  8 ++---
 .../js/ext.translate.special.translate.js     |  4 +--
 ...translate.translationstats.graphbuilder.js |  2 +-
 .../ext.translate.entity.selector/index.js    |  2 +-
 .../src/ext.translate.mtHelpers/index.js      |  4 +--
 .../ve.ui.MWTranslateAnnotationContextItem.js |  2 +-
 tests/qunit/.eslintrc.json                    |  5 ++-
 17 files changed, 50 insertions(+), 45 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index 80fa8cd..f58c501 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -7,7 +7,7 @@
 			"name": "Translate",
 			"devDependencies": {
 				"@wikimedia/codex-design-tokens": "1.21.1",
-				"eslint-config-wikimedia": "0.28.2",
+				"eslint-config-wikimedia": "0.29.1",
 				"grunt": "1.6.1",
 				"grunt-banana-checker": "0.13.0",
 				"grunt-eslint": "24.3.0",
@@ -1586,11 +1586,10 @@
 			}
 		},
 		"node_modules/eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.29.1",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.29.1.tgz",
+			"integrity": "sha512-4dbL5o3hKGSvreyrGZWLPoTDLFubZ575IQOPhUaTcpbTsi0u05TBEMsOyYkthTaK21vsFQqhSYtxp/xU93BSdA==",
 			"dev": true,
-			"license": "MIT",
 			"dependencies": {
 				"browserslist-config-wikimedia": "^0.7.0",
 				"eslint": "^8.57.0",
@@ -1602,13 +1601,16 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
 				"eslint-plugin-vue": "^9.26.0",
 				"eslint-plugin-wdio": "^8.24.12",
 				"eslint-plugin-yml": "^1.14.0"
+			},
+			"engines": {
+				"node": ">=18 <23"
 			}
 		},
 		"node_modules/eslint-plugin-compat": {
@@ -1826,11 +1828,10 @@
 			}
 		},
 		"node_modules/eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
-			"license": "MIT",
 			"peerDependencies": {
 				"eslint": ">=8.0.0"
 			}
@@ -6507,9 +6508,9 @@
 			}
 		},
 		"eslint-config-wikimedia": {
-			"version": "0.28.2",
-			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.28.2.tgz",
-			"integrity": "sha512-5+rdnT7wH1gpKAO6tHYThg78eMhZMruJzvqku3Y5iaEY/A7kSKLFpA/vOj/snys9fKjDHC9BXmArQh+agkOoJQ==",
+			"version": "0.29.1",
+			"resolved": "https://registry.npmjs.org/eslint-config-wikimedia/-/eslint-config-wikimedia-0.29.1.tgz",
+			"integrity": "sha512-4dbL5o3hKGSvreyrGZWLPoTDLFubZ575IQOPhUaTcpbTsi0u05TBEMsOyYkthTaK21vsFQqhSYtxp/xU93BSdA==",
 			"dev": true,
 			"requires": {
 				"browserslist-config-wikimedia": "^0.7.0",
@@ -6522,7 +6523,7 @@
 				"eslint-plugin-mediawiki": "^0.7.0",
 				"eslint-plugin-mocha": "^10.4.3",
 				"eslint-plugin-n": "^17.7.0",
-				"eslint-plugin-no-jquery": "^3.0.1",
+				"eslint-plugin-no-jquery": "^3.1.1",
 				"eslint-plugin-qunit": "^8.1.1",
 				"eslint-plugin-security": "^1.7.1",
 				"eslint-plugin-unicorn": "^53.0.0",
@@ -6669,9 +6670,9 @@
 			}
 		},
 		"eslint-plugin-no-jquery": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.0.2.tgz",
-			"integrity": "sha512-n/+6p6PFhWDNPVLJj1463hw4OTIRBbROGcbhmtOHTgw7yihSKzkwZiQ00EJTneyeR3jRiw5lpWSMCCBhtb8t2g==",
+			"version": "3.1.1",
+			"resolved": "https://registry.npmjs.org/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-3.1.1.tgz",
+			"integrity": "sha512-LTLO3jH/Tjr1pmxCEqtV6qmt+OChv8La4fwgG470JRpgxyFF4NOzoC9CRy92GIWD3Yjl0qLEgPmD2FLQWcNEjg==",
 			"dev": true,
 			"requires": {}
 		},
diff --git a/package.json b/package.json
index 142e230..b09496e 100644
--- a/package.json
+++ b/package.json
@@ -9,7 +9,7 @@
 	},
 	"devDependencies": {
 		"@wikimedia/codex-design-tokens": "1.21.1",
-		"eslint-config-wikimedia": "0.28.2",
+		"eslint-config-wikimedia": "0.29.1",
 		"grunt": "1.6.1",
 		"grunt-banana-checker": "0.13.0",
 		"grunt-eslint": "24.3.0",
diff --git a/resources/.eslintrc.json b/resources/.eslintrc.json
index 897c2a7..a620368 100644
--- a/resources/.eslintrc.json
+++ b/resources/.eslintrc.json
@@ -22,6 +22,7 @@
 		"no-jquery/no-visibility": "error",
 		"compat/compat": "warn",
 		"no-jquery/no-extend": "warn",
-		"es-x/no-resizable-and-growable-arraybuffers": "warn"
+		"es-x/no-resizable-and-growable-arraybuffers": "warn",
+		"no-jquery/no-done-fail": "warn"
 	}
 }
diff --git a/resources/js/ext.translate.editor.js b/resources/js/ext.translate.editor.js
index a4f1429..a664349 100644
--- a/resources/js/ext.translate.editor.js
+++ b/resources/js/ext.translate.editor.js
@@ -1183,7 +1183,7 @@
 			}
 
 			for ( var index = 0; index < stringTypes.length; index++ ) {
-				if ( allNoticeTypes.indexOf( stringTypes[ index ] ) === -1 ) {
+				if ( !allNoticeTypes.includes( stringTypes[ index ] ) ) {
 					var errMsg = 'tux: Invalid notice type removeNotice - ' + stringTypes[ index ];
 					mw.log.error( errMsg );
 					throw new Error( errMsg );
diff --git a/resources/js/ext.translate.messagerenamedialog.js b/resources/js/ext.translate.messagerenamedialog.js
index 5e362e3..d5d3edb 100644
--- a/resources/js/ext.translate.messagerenamedialog.js
+++ b/resources/js/ext.translate.messagerenamedialog.js
@@ -277,8 +277,8 @@ mw.translate.MessageRenameDialog.prototype.filterMessages = function ( searchVal
 	}
 
 	filteredMessages = this.possibleRenames.filter( function ( message ) {
-		return message.key.toLowerCase().indexOf( normalizedSearchVal ) !== -1 &&
-			message.content.toLowerCase().indexOf( normalizedSearchVal ) !== -1;
+		return message.key.toLowerCase().includes( normalizedSearchVal ) &&
+			message.content.toLowerCase().includes( normalizedSearchVal );
 	} );
 
 	this.clearMessages();
diff --git a/resources/js/ext.translate.messagetable.js b/resources/js/ext.translate.messagetable.js
index 78d2de9..22ef0a0 100644
--- a/resources/js/ext.translate.messagetable.js
+++ b/resources/js/ext.translate.messagetable.js
@@ -33,7 +33,7 @@
 	function MessageTable( container, options, settings ) {
 		this.$container = $( container );
 		this.options = options;
-		this.options = $.extend( {}, $.fn.messagetable.defaults, options );
+		this.options = Object.assign( {}, $.fn.messagetable.defaults, options );
 		this.settings = settings;
 		// mode can be proofread, page or translate
 		this.mode = this.options.mode;
@@ -152,7 +152,7 @@
 			message.proofreadable = false;
 
 			if ( message.tags.length &&
-				message.tags.indexOf( 'optional' ) >= 0 &&
+				message.tags.includes( 'optional' ) &&
 				status === 'untranslated'
 			) {
 				status = 'optional';
@@ -752,7 +752,7 @@
 
 				// Fix the filter if it is untranslated. Untranslated does not make sense
 				// for proofread mode. Keep the filter if it is not 'untranslated'
-				if ( !filter || filter.indexOf( '!translated' ) >= 0 ) {
+				if ( !filter || filter.includes( '!translated' ) ) {
 					messageTable.messages = [];
 					// default filter for proofread mode
 					mw.translate.changeFilter( 'translated|!reviewer:' + userId +
@@ -766,11 +766,11 @@
 				$tuxTabUntranslated.removeClass( 'hide' );
 				$tuxTabUnproofread.addClass( 'hide' );
 
-				if ( filter.indexOf( '!translated' ) > -1 ) {
+				if ( filter.includes( '!translated' ) ) {
 					$hideTranslatedButton.removeClass( 'hide' );
 				}
 
-				if ( filter && filter.indexOf( '!last-translator' ) >= 0 ) {
+				if ( filter && filter.includes( '!last-translator' ) ) {
 					messageTable.messages = [];
 					// default filter for translate mode
 					mw.translate.changeFilter( '!translated' );
diff --git a/resources/js/ext.translate.proofread.js b/resources/js/ext.translate.proofread.js
index c0829ba..e483780 100644
--- a/resources/js/ext.translate.proofread.js
+++ b/resources/js/ext.translate.proofread.js
@@ -97,7 +97,7 @@
 			/* Whether the current user if the last translator of this message.
 			 * Accepting own translations is prohibited. */
 			var translatedBySelf = ( this.message.properties[ 'last-translator-text' ] === mw.user.getName() );
-			var proofreadBySelf = reviewers.indexOf( userId ) > -1;
+			var proofreadBySelf = reviewers.includes( userId );
 
 			var sourceLangDir = $.uls.data.getDir( this.options.sourcelangcode );
 
diff --git a/resources/js/ext.translate.special.managetranslatorsandbox.js b/resources/js/ext.translate.special.managetranslatorsandbox.js
index 56a5dbe..2c1aabe 100644
--- a/resources/js/ext.translate.special.managetranslatorsandbox.js
+++ b/resources/js/ext.translate.special.managetranslatorsandbox.js
@@ -28,7 +28,7 @@
 
 	function doApiAction( options ) {
 		var api = new mw.Api(),
-			optionsWithDefaults = $.extend( {}, { action: 'translatesandbox' }, options );
+			optionsWithDefaults = Object.assign( {}, { action: 'translatesandbox' }, options );
 
 		return api.postWithToken( 'csrf', optionsWithDefaults ).promise();
 	}
@@ -636,7 +636,7 @@
 			if ( !language ||
 				( requestData.languagepreferences &&
 					requestData.languagepreferences.languages &&
-					requestData.languagepreferences.languages.indexOf( language ) > -1 )
+					requestData.languagepreferences.languages.includes( language ) )
 			) {
 				// Found language
 				$request.removeClass( 'hide' );
diff --git a/resources/js/ext.translate.special.pagemigration.js b/resources/js/ext.translate.special.pagemigration.js
index 56ff257..a7808d6 100644
--- a/resources/js/ext.translate.special.pagemigration.js
+++ b/resources/js/ext.translate.special.pagemigration.js
@@ -154,7 +154,7 @@
 			var errorMessage = mw.msg( 'pm-translation-unit-fetch-failed' );
 			if (
 				code === 'badparameter' &&
-				result.error && result.error.info.indexOf( 'mcgroup' ) !== -1
+				result.error && result.error.info.includes( 'mcgroup' )
 			) {
 				errorMessage = mw.msg( 'pm-pagetitle-not-translatable', page );
 			}
diff --git a/resources/js/ext.translate.special.pagepreparation.js b/resources/js/ext.translate.special.pagepreparation.js
index 2b245e0..1cec366 100644
--- a/resources/js/ext.translate.special.pagepreparation.js
+++ b/resources/js/ext.translate.special.pagepreparation.js
@@ -124,13 +124,13 @@
 		var headerSearchRegex = new RegExp( '(==+[ ]*' + headerText + '[ ]*==+)', 'gi' );
 		// This is to ensure that the tags and the anchor are added only once
 
-		if ( pageContent.indexOf( '<span id="' + mw.html.escape( anchorID ) + '"' ) === -1 ) {
+		if ( !pageContent.includes( '<span id="' + mw.html.escape( anchorID ) + '"' ) ) {
 			pageContent = pageContent.replace( headerSearchRegex, '</translate>\n' +
 				'<span id="' + mw.html.escape( anchorID ) + '"></span>\n<translate>\n$1' );
 		}
 
 		// This is to add back the tags which were removed in cleanupTags()
-		if ( pageContent.indexOf( '</translate>\n<span id="' + anchorID + '"' ) === -1 ) {
+		if ( !pageContent.includes( '</translate>\n<span id="' + anchorID + '"' ) ) {
 			var spanSearchRegex = new RegExp( '(<span id="' + mw.util.escapeRegExp( anchorID ) + '"></span>)', 'gi' );
 			pageContent = pageContent.replace( spanSearchRegex, '\n</translate>\n$1\n</translate>\n' );
 		}
diff --git a/resources/js/ext.translate.special.searchtranslations.js b/resources/js/ext.translate.special.searchtranslations.js
index 65fa216..6151714 100644
--- a/resources/js/ext.translate.special.searchtranslations.js
+++ b/resources/js/ext.translate.special.searchtranslations.js
@@ -64,14 +64,14 @@
 
 		// Remove duplicates from the language list
 		quickLanguageList.forEach( function ( lang ) {
-			if ( languages[ lang ] && unique.indexOf( lang ) === -1 ) {
+			if ( languages[ lang ] && !unique.includes( lang ) ) {
 				unique.push( lang );
 			}
 		} );
 
-		if ( currentLanguage && quickLanguageList.indexOf( currentLanguage ) >= 0 ) {
+		if ( currentLanguage && quickLanguageList.includes( currentLanguage ) ) {
 			quickLanguageList = unique.splice( 0, 5 );
-			if ( quickLanguageList.indexOf( currentLanguage ) === -1 ) {
+			if ( !quickLanguageList.includes( currentLanguage ) ) {
 				quickLanguageList = quickLanguageList.concat( currentLanguage );
 			}
 		} else {
@@ -165,7 +165,7 @@
 		}
 		var grouppath = getParameterByName( 'grouppath' ).split( '|' )[ 0 ];
 		if ( currentGroup && resultGroups[ grouppath ] &&
-			groupList.indexOf( grouppath ) < 0 &&
+			!groupList.includes( grouppath ) &&
 			level === 0
 		) {
 			// Make sure current selected group is displayed always.
diff --git a/resources/js/ext.translate.special.translate.js b/resources/js/ext.translate.special.translate.js
index 3c117e5..b599913 100644
--- a/resources/js/ext.translate.special.translate.js
+++ b/resources/js/ext.translate.special.translate.js
@@ -396,7 +396,7 @@
 			return true;
 		}
 
-		return priorityLanguages.indexOf( language ) !== -1;
+		return priorityLanguages.includes( language );
 	}
 
 	function setupLanguageSelector( $element ) {
@@ -625,7 +625,7 @@
 				filter: actualFilter
 			} );
 
-			if ( actualFilter.indexOf( hideOptionalMessages ) === -1 ) {
+			if ( !actualFilter.includes( hideOptionalMessages ) ) {
 				$( '#tux-option-optional' ).prop( 'checked', true );
 			}
 		}
diff --git a/resources/js/ext.translate.translationstats.graphbuilder.js b/resources/js/ext.translate.translationstats.graphbuilder.js
index 640fd0c..64996ba 100644
--- a/resources/js/ext.translate.translationstats.graphbuilder.js
+++ b/resources/js/ext.translate.translationstats.graphbuilder.js
@@ -180,7 +180,7 @@
 				maxValue = 0, minValue = 0;
 
 			for ( var labelProp in jsonGraphData ) {
-				if ( labels.indexOf( labelProp ) === -1 ) {
+				if ( !labels.includes( labelProp ) ) {
 					labels.push( labelProp );
 				}
 
diff --git a/resources/src/ext.translate.entity.selector/index.js b/resources/src/ext.translate.entity.selector/index.js
index 2737103..f0c0423 100644
--- a/resources/src/ext.translate.entity.selector/index.js
+++ b/resources/src/ext.translate.entity.selector/index.js
@@ -78,7 +78,7 @@ var EntitySelectorWidget = function ( config ) {
 
 	if ( this.groupTypesToFetch ) {
 		for ( var i = 0; i < this.groupTypesToFetch.length; i++ ) {
-			if ( validGroupTypes.indexOf( this.groupTypesToFetch[ i ] ) === -1 ) {
+			if ( !validGroupTypes.includes( this.groupTypesToFetch[ i ] ) ) {
 				throw new Error(
 					this.groupTypesToFetch[ i ] +
 					' is invalid. Allowed types: ' + validGroupTypes );
diff --git a/resources/src/ext.translate.mtHelpers/index.js b/resources/src/ext.translate.mtHelpers/index.js
index 64d11ef..765c90b 100644
--- a/resources/src/ext.translate.mtHelpers/index.js
+++ b/resources/src/ext.translate.mtHelpers/index.js
@@ -46,7 +46,7 @@ const tokenize = function ( string, language ) {
 	if ( !string ) {
 		return [];
 	}
-	if ( CJKLanguages.indexOf( language ) !== -1 ) {
+	if ( CJKLanguages.includes( language ) ) {
 		return string.split( '' );
 	}
 	// Match all non whitespace characters for tokens.
@@ -81,7 +81,7 @@ const calculateUnmodifiedContent = {
 			smallSet = tokens1;
 		}
 		// Find the intersection (tokens that did not change) of two token sets
-		const unmodifiedTokens = bigSet.filter( ( token ) => smallSet.indexOf( token ) >= 0 );
+		const unmodifiedTokens = bigSet.filter( ( token ) => smallSet.includes( token ) );
 		// If string1 has 10 tokens and we see that 2 tokens are different or not present in
 		// string2, we are saying that string2 is 80% (ie. 10-2/10) of unmodified version
 		// for string1.
diff --git a/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js b/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js
index a69a095..4b7148a 100644
--- a/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js
+++ b/resources/src/ve-translate/ve.ui.MWTranslateAnnotationContextItem.js
@@ -48,7 +48,7 @@ ve.ui.MWTranslateAnnotationContextItem.prototype.getLabelMessage = function () {
 
 ve.ui.MWTranslateAnnotationContextItem.prototype.getDescriptionMessage = function () {
 	var type = this.model.getAttribute( 'type' );
-	if ( type.indexOf( '/End', type.length - 4 ) !== -1 ) {
+	if ( type.includes( '/End', type.length - 4 ) ) {
 		return '';
 	}
 	var map = {
diff --git a/tests/qunit/.eslintrc.json b/tests/qunit/.eslintrc.json
index 4c3e352..e79edce 100644
--- a/tests/qunit/.eslintrc.json
+++ b/tests/qunit/.eslintrc.json
@@ -3,5 +3,8 @@
 	"extends": [
 		"../../resources/.eslintrc.json",
 		"wikimedia/qunit"
-	]
+	],
+	"rules": {
+		"no-jquery/no-done-fail": "warn"
+	}
 }
-- 
2.39.2


--- end ---

composer dependencies

Dependencies
Development dependencies

npm dependencies

Development dependencies

Logs

Source code is licensed under the AGPL.