summaryrefslogtreecommitdiff
path: root/skins/common/protect.js
diff options
context:
space:
mode:
Diffstat (limited to 'skins/common/protect.js')
-rw-r--r--skins/common/protect.js527
1 files changed, 330 insertions, 197 deletions
diff --git a/skins/common/protect.js b/skins/common/protect.js
index 863b95bd..d9650c82 100644
--- a/skins/common/protect.js
+++ b/skins/common/protect.js
@@ -1,218 +1,351 @@
-/**
- * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
- * on the protection form
- *
- * @param String tableId Identifier of the table containing UI bits
- * @param String labelText Text to use for the checkbox label
- */
-function protectInitialize( tableId, labelText, types ) {
- if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
- return false;
-
- var box = document.getElementById( tableId );
- if( !box )
- return false;
+
+var ProtectionForm = {
+ 'existingMatch': false,
+
+ /**
+ * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
+ * on the protection form
+ *
+ * @param Object opts : parameters with members:
+ * tableId Identifier of the table containing UI bits
+ * labelText Text to use for the checkbox label
+ * numTypes The number of protection types
+ * existingMatch True if all the existing expiry times match
+ */
+ 'init': function( opts ) {
+ if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
+ return false;
+
+ var box = document.getElementById( opts.tableId );
+ if( !box )
+ return false;
- var tbody = box.getElementsByTagName( 'tbody' )[0];
- var row = document.createElement( 'tr' );
- tbody.appendChild( row );
-
- row.appendChild( document.createElement( 'td' ) );
- var col = document.createElement( 'td' );
- row.appendChild( col );
- // If there is only one protection type, there is nothing to chain
- if( types > 1 ) {
- var check = document.createElement( 'input' );
- check.id = 'mwProtectUnchained';
- check.type = 'checkbox';
- col.appendChild( check );
- addClickHandler( check, protectChainUpdate );
-
- col.appendChild( document.createTextNode( ' ' ) );
- var label = document.createElement( 'label' );
- label.htmlFor = 'mwProtectUnchained';
- label.appendChild( document.createTextNode( labelText ) );
- col.appendChild( label );
-
- check.checked = !protectAllMatch();
- protectEnable( check.checked );
- }
-
- setCascadeCheckbox();
-
- return true;
-}
+ var boxbody = box.getElementsByTagName('tbody')[0]
+ var row = document.createElement( 'tr' );
+ boxbody.insertBefore( row, boxbody.firstChild );
+
+ this.existingMatch = opts.existingMatch;
+
+ var cell = document.createElement( 'td' );
+ row.appendChild( cell );
+ // If there is only one protection type, there is nothing to chain
+ if( opts.numTypes > 1 ) {
+ var check = document.createElement( 'input' );
+ check.id = 'mwProtectUnchained';
+ check.type = 'checkbox';
+ cell.appendChild( check );
+ addClickHandler( check, function() { ProtectionForm.onChainClick(); } );
+
+ cell.appendChild( document.createTextNode( ' ' ) );
+ var label = document.createElement( 'label' );
+ label.htmlFor = 'mwProtectUnchained';
+ label.appendChild( document.createTextNode( opts.labelText ) );
+ cell.appendChild( label );
+
+ check.checked = !this.areAllTypesMatching();
+ this.enableUnchainedInputs( check.checked );
+ }
+
+ this.updateCascadeCheckbox();
+
+ return true;
+ },
-/**
-* Determine if, given the cascadeable protection levels
-* and what is currently selected, if the cascade box
-* can be checked
-*
-* @return boolean
-*
-*/
-function setCascadeCheckbox() {
- // For non-existent titles, there is no cascade option
- if( !document.getElementById( 'mwProtect-cascade' ) ) {
+ /**
+ * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
+ */
+ 'updateCascadeCheckbox': function() {
+ // For non-existent titles, there is no cascade option
+ if( !document.getElementById( 'mwProtect-cascade' ) ) {
+ return;
+ }
+ var lists = this.getLevelSelectors();
+ for( var i = 0; i < lists.length; i++ ) {
+ if( lists[i].selectedIndex > -1 ) {
+ var items = lists[i].getElementsByTagName( 'option' );
+ var selected = items[ lists[i].selectedIndex ].value;
+ if( !this.isCascadeableLevel(selected) ) {
+ document.getElementById( 'mwProtect-cascade' ).checked = false;
+ document.getElementById( 'mwProtect-cascade' ).disabled = true;
+ return;
+ }
+ }
+ }
+ document.getElementById( 'mwProtect-cascade' ).disabled = false;
+ },
+
+ /**
+ * Is this protection level cascadeable?
+ * @param String level
+ *
+ * @return boolean
+ *
+ */
+ 'isCascadeableLevel': function( level ) {
+ for (var k = 0; k < wgCascadeableLevels.length; k++) {
+ if ( wgCascadeableLevels[k] == level ) {
+ return true;
+ }
+ }
return false;
- }
- var lists = protectSelectors();
- for( var i = 0; i < lists.length; i++ ) {
- if( lists[i].selectedIndex > -1 ) {
- var items = lists[i].getElementsByTagName( 'option' );
- var selected = items[ lists[i].selectedIndex ].value;
- if( !isCascadeableLevel(selected) ) {
- document.getElementById( 'mwProtect-cascade' ).checked = false;
- document.getElementById( 'mwProtect-cascade' ).disabled = true;
- return false;
+ },
+
+ /**
+ * When protection levels are locked together, update the rest
+ * when one action's level changes
+ *
+ * @param Element source Level selector that changed
+ */
+ 'updateLevels': function(source) {
+ if( !this.isUnchained() )
+ this.setAllSelectors( source.selectedIndex );
+ this.updateCascadeCheckbox();
+ },
+
+ /**
+ * When protection levels are locked together, update the
+ * expiries when one changes
+ *
+ * @param Element source expiry input that changed
+ */
+
+ 'updateExpiry': function(source) {
+ if( !this.isUnchained() ) {
+ var expiry = source.value;
+ this.forEachExpiryInput(function(element) {
+ element.value = expiry;
+ });
+ }
+ var listId = source.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
+ var list = document.getElementById( listId );
+ if (list && list.value != 'othertime' ) {
+ if ( this.isUnchained() ) {
+ list.value = 'othertime';
+ } else {
+ this.forEachExpirySelector(function(element) {
+ element.value = 'othertime';
+ });
}
}
- }
- document.getElementById( 'mwProtect-cascade' ).disabled = false;
- return true;
-}
+ },
-/**
-* Is this protection level cascadeable?
-* @param String level
-*
-* @return boolean
-*
-*/
-function isCascadeableLevel( level ) {
- for (var k = 0; k < wgCascadeableLevels.length; k++) {
- if ( wgCascadeableLevels[k] == level ) {
- return true;
- }
- }
- return false;
-}
+ /**
+ * When protection levels are locked together, update the
+ * expiry lists when one changes and clear the custom inputs
+ *
+ * @param Element source expiry selector that changed
+ */
+ 'updateExpiryList': function(source) {
+ if( !this.isUnchained() ) {
+ var expiry = source.value;
+ this.forEachExpirySelector(function(element) {
+ element.value = expiry;
+ });
+ this.forEachExpiryInput(function(element) {
+ element.value = '';
+ });
+ }
+ },
-/**
- * When protection levels are locked together, update the rest
- * when one action's level changes
- *
- * @param Element source Level selector that changed
- */
-function protectLevelsUpdate(source) {
- if( !protectUnchained() )
- protectUpdateAll( source.selectedIndex );
- setCascadeCheckbox();
-}
+ /**
+ * Update chain status and enable/disable various bits of the UI
+ * when the user changes the "unlock move permissions" checkbox
+ */
+ 'onChainClick': function() {
+ if( this.isUnchained() ) {
+ this.enableUnchainedInputs( true );
+ } else {
+ this.setAllSelectors( this.getMaxLevel() );
+ this.enableUnchainedInputs( false );
+ }
+ this.updateCascadeCheckbox();
+ },
-/**
- * Update chain status and enable/disable various bits of the UI
- * when the user changes the "unlock move permissions" checkbox
- */
-function protectChainUpdate() {
- if( protectUnchained() ) {
- protectEnable( true );
- } else {
- protectChain();
- protectEnable( false );
- }
- setCascadeCheckbox();
-}
+ /**
+ * Returns true if the named attribute in all objects in the given array are matching
+ */
+ 'matchAttribute' : function( objects, attrName ) {
+ var value = null;
-/**
- * Are all actions protected at the same level?
- *
- * @return boolean
- */
-function protectAllMatch() {
- var values = new Array();
- protectForSelectors(function(set) {
- values[values.length] = set.selectedIndex;
- });
- for (var i = 1; i < values.length; i++) {
- if (values[i] != values[0]) {
- return false;
+ // Check levels
+ for ( var i = 0; i < objects.length; i++ ) {
+ var element = objects[i];
+ if ( value == null ) {
+ value = element[attrName];
+ } else {
+ if ( value != element[attrName] ) {
+ return false;
+ }
+ }
}
- }
- return true;
-}
+ return true;
+ },
-/**
- * Is protection chaining on or off?
- *
- * @return bool
- */
-function protectUnchained() {
- var unchain = document.getElementById( 'mwProtectUnchained' );
- return unchain
- ? unchain.checked
- : true; // No control, so we need to let the user set both levels
-}
+ /**
+ * Are all actions protected at the same level, with the same expiry time?
+ *
+ * @return boolean
+ */
+ 'areAllTypesMatching': function() {
+ return this.existingMatch
+ && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
+ && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
+ && this.matchAttribute( this.getExpiryInputs(), 'value' );
+ },
+
+ /**
+ * Is protection chaining off?
+ *
+ * @return bool
+ */
+ '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
+ */
+ 'getMaxLevel': function() {
+ var maxIndex = -1;
+ this.forEachLevelSelector(function(element) {
+ if (element.selectedIndex > maxIndex) {
+ maxIndex = element.selectedIndex;
+ }
+ });
+ return maxIndex;
+ },
-/**
- * Find the highest-protected action and set all others to that level
- */
-function protectChain() {
- var maxIndex = -1;
- protectForSelectors(function(set) {
- if (set.selectedIndex > maxIndex) {
- maxIndex = set.selectedIndex;
+ /**
+ * Protect all actions at the specified level
+ *
+ * @param int index Protection level
+ */
+ 'setAllSelectors': function(index) {
+ this.forEachLevelSelector(function(element) {
+ if (element.selectedIndex != index) {
+ element.selectedIndex = index;
+ }
+ });
+ },
+
+ /**
+ * Apply a callback to each protection selector
+ *
+ * @param callable func Callback function
+ */
+ 'forEachLevelSelector': function(func) {
+ var selectors = this.getLevelSelectors();
+ for (var i = 0; i < selectors.length; i++) {
+ func(selectors[i]);
}
- });
- protectUpdateAll(maxIndex);
-}
+ },
+
+ /**
+ * Get a list of all protection selectors on the page
+ *
+ * @return Array
+ */
+ 'getLevelSelectors': function() {
+ var all = document.getElementsByTagName("select");
+ var ours = new Array();
+ for (var i = 0; i < all.length; i++) {
+ var element = all[i];
+ if (element.id.match(/^mwProtect-level-/)) {
+ ours[ours.length] = element;
+ }
+ }
+ return ours;
+ },
-/**
- * Protect all actions at the specified level
- *
- * @param int index Protection level
- */
-function protectUpdateAll(index) {
- protectForSelectors(function(set) {
- if (set.selectedIndex != index) {
- set.selectedIndex = index;
+ /**
+ * Apply a callback to each expiry input
+ *
+ * @param callable func Callback function
+ */
+ 'forEachExpiryInput': function(func) {
+ var inputs = this.getExpiryInputs();
+ for (var i = 0; i < inputs.length; i++) {
+ func(inputs[i]);
}
- });
-}
+ },
-/**
- * Apply a callback to each protection selector
- *
- * @param callable func Callback function
- */
-function protectForSelectors(func) {
- var selectors = protectSelectors();
- for (var i = 0; i < selectors.length; i++) {
- func(selectors[i]);
- }
-}
+ /**
+ * Get a list of all expiry inputs on the page
+ *
+ * @return Array
+ */
+ 'getExpiryInputs': function() {
+ var all = document.getElementsByTagName("input");
+ var ours = new Array();
+ for (var i = 0; i < all.length; i++) {
+ var element = all[i];
+ if (element.name.match(/^mwProtect-expiry-/)) {
+ ours[ours.length] = element;
+ }
+ }
+ return ours;
+ },
-/**
- * Get a list of all protection selectors on the page
- *
- * @return Array
- */
-function protectSelectors() {
- var all = document.getElementsByTagName("select");
- var ours = new Array();
- for (var i = 0; i < all.length; i++) {
- var set = all[i];
- if (set.id.match(/^mwProtect-level-/)) {
- ours[ours.length] = set;
+ /**
+ * Apply a callback to each expiry selector list
+ * @param callable func Callback function
+ */
+ 'forEachExpirySelector': function(func) {
+ var inputs = this.getExpirySelectors();
+ for (var i = 0; i < inputs.length; i++) {
+ func(inputs[i]);
}
- }
- return ours;
-}
+ },
-/**
- * Enable/disable protection selectors
- *
- * @param boolean val Enable?
- */
-function protectEnable(val) {
- // fixme
- var first = true;
- protectForSelectors(function(set) {
- if (first) {
- first = false;
- } else {
- set.disabled = !val;
- set.style.visible = val ? "visible" : "hidden";
+ /**
+ * Get a list of all expiry selector lists on the page
+ *
+ * @return Array
+ */
+ 'getExpirySelectors': function() {
+ var all = document.getElementsByTagName("select");
+ var ours = new Array();
+ for (var i = 0; i < all.length; i++) {
+ var element = all[i];
+ if (element.id.match(/^mwProtectExpirySelection-/)) {
+ ours[ours.length] = element;
+ }
}
- });
+ return ours;
+ },
+
+ /**
+ * Enable/disable protection selectors and expiry inputs
+ *
+ * @param boolean val Enable?
+ */
+ 'enableUnchainedInputs': function(val) {
+ var first = true;
+ this.forEachLevelSelector(function(element) {
+ if (first) {
+ first = false;
+ } else {
+ element.disabled = !val;
+ }
+ });
+ first = true;
+ this.forEachExpiryInput(function(element) {
+ if (first) {
+ first = false;
+ } else {
+ element.disabled = !val;
+ }
+ });
+ first = true;
+ this.forEachExpirySelector(function(element) {
+ if (first) {
+ first = false;
+ } else {
+ element.disabled = !val;
+ }
+ });
+ }
}