- this.updateCascadeCheckbox();
- },
-
- /**
- * Returns true if the named attribute in all objects in the given array are matching
- *
- * @param {Object[]} objects
- * @param {string} attrName
- * @return {boolean}
- */
- matchAttribute: function ( objects, attrName ) {
- // eslint-disable-next-line jquery/no-map-util
- return $.map( objects, function ( object ) {
- return object[ attrName ];
- } ).filter( function ( item, index, a ) {
- return index === a.indexOf( item );
- } ).length === 1;
- },
-
- /**
- * Are all actions protected at the same level, with the same expiry time?
- *
- * @return {boolean}
- */
- areAllTypesMatching: function () {
- return this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' ) &&
- this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' ) &&
- this.matchAttribute( this.getExpiryInputs(), 'value' );
- },
-
- /**
- * Is protection chaining off?
- *
- * @return {boolean}
- */
- isUnchained: function () {
- var element = document.getElementById( 'mwProtectUnchained' );
- return element ?
- element.checked :
- true; // No control, so we need to let the user set both levels
- },
-
- /**
- * Find the highest protection level in any selector
- *
- * @return {number}
- */
- getMaxLevel: function () {
- return Math.max.apply( Math, this.getLevelSelectors().map( function () {
- return this.selectedIndex;
- } ) );
- },
-
- /**
- * Protect all actions at the specified level
- *
- * @param {number} index Protection level
- */
- setAllSelectors: function ( index ) {
- this.getLevelSelectors().each( function () {
- this.selectedIndex = index;
- } );
- },
-
- /**
- * Get a list of all protection selectors on the page
- *
- * @return {jQuery}
- */
- getLevelSelectors: function () {
- return $( 'select[id ^= mwProtect-level-]' );
- },
-
- /**
- * Get a list of all expiry inputs on the page
- *
- * @return {jQuery}
- */
- getExpiryInputs: function () {
- return $( 'input[id ^= mwProtect-][id $= -expires]' );
- },
+ } );
+ }
+
+ /**
+ * Returns true if the named attribute in all objects in the given array are matching
+ *
+ * @param {Object[]} objects
+ * @param {string} attrName
+ * @return {boolean}
+ */
+ function matchAttribute( objects, attrName ) {
+ // eslint-disable-next-line no-jquery/no-map-util
+ return $.map( objects, function ( object ) {
+ return object[ attrName ];
+ } ).filter( function ( item, index, a ) {
+ return index === a.indexOf( item );
+ } ).length === 1;
+ }
+
+ /**
+ * Are all actions protected at the same level, with the same expiry time?
+ *
+ * @return {boolean}
+ */
+ function areAllTypesMatching() {
+ return matchAttribute( getLevelSelectors(), 'selectedIndex' ) &&
+ matchAttribute( getExpirySelectors(), 'selectedIndex' ) &&
+ matchAttribute( getExpiryInputs(), 'value' );
+ }
+
+ /**
+ * Is protection chaining off?
+ *
+ * @return {boolean}
+ */
+ function isUnchained() {
+ var element = document.getElementById( 'mwProtectUnchained' );
+ return element ?
+ element.checked :
+ true; // No control, so we need to let the user set both levels
+ }
+
+ /**
+ * Find the highest protection level in any selector
+ *
+ * @return {number}
+ */
+ function getMaxLevel() {
+ return Math.max.apply( Math, getLevelSelectors().map( function () {
+ return this.selectedIndex;
+ } ) );
+ }
+
+ /**
+ * Protect all actions at the specified level
+ *
+ * @param {number} index Protection level
+ */
+ function setAllSelectors( index ) {
+ getLevelSelectors().prop( 'selectedIndex', index );
+ }
+
+ /**
+ * When protection levels are locked together, update the rest
+ * when one action's level changes
+ *
+ * @param {Event} event Level selector that changed
+ */
+ function updateLevels( event ) {
+ if ( !isUnchained() ) {
+ setAllSelectors( event.target.selectedIndex );
+ }
+ updateCascadeCheckbox();
+ }
+
+ /**
+ * When protection levels are locked together, update the
+ * expiries when one changes
+ *
+ * @param {Event} event Expiry input that changed
+ */
+ function updateExpiry( event ) {
+ if ( !isUnchained() ) {
+ getExpiryInputs().val( event.target.value );
+ }
+ if ( isUnchained() ) {
+ $( '#' + event.target.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' ) ).val( 'othertime' );
+ } else {
+ getExpirySelectors().val( 'othertime' );
+ }
+ }
+
+ /**
+ * When protection levels are locked together, update the
+ * expiry lists when one changes and clear the custom inputs
+ *
+ * @param {Event} event Expiry selector that changed
+ */
+ function updateExpiryList( event ) {
+ if ( !isUnchained() ) {
+ getExpirySelectors().val( event.target.value );
+ getExpiryInputs().val( '' );
+ }
+ }
+
+ /**
+ * Update chain status and enable/disable various bits of the UI
+ * when the user changes the "unlock move permissions" checkbox
+ */
+ function onChainClick() {
+ toggleUnchainedInputs( isUnchained() );
+ if ( !isUnchained() ) {
+ setAllSelectors( getMaxLevel() );
+ }
+ updateCascadeCheckbox();
+ }
+
+ /**
+ * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
+ * on the protection form
+ */
+ function init() {
+ var $cell = $( '<td>' ),
+ $row = $( '<tr>' ).append( $cell );
+
+ if ( !$( '#mwProtectSet' ).length ) {
+ return;
+ }