3 'existingMatch': false,
6 * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
7 * on the protection form
9 * @param Object opts : parameters with members:
10 * tableId Identifier of the table containing UI bits
11 * labelText Text to use for the checkbox label
12 * numTypes The number of protection types
13 * existingMatch True if all the existing expiry times match
15 'init': function( opts ) {
16 if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
19 var box = document.getElementById( opts.tableId );
23 var boxbody = box.getElementsByTagName('tbody')[0]
24 var row = document.createElement( 'tr' );
25 boxbody.insertBefore( row, boxbody.firstChild.nextSibling );
27 this.existingMatch = opts.existingMatch;
29 var cell = document.createElement( 'td' );
30 row.appendChild( cell );
31 // If there is only one protection type, there is nothing to chain
32 if( opts.numTypes > 1 ) {
33 var check = document.createElement( 'input' );
34 check.id = 'mwProtectUnchained';
35 check.type = 'checkbox';
36 cell.appendChild( check );
37 addClickHandler( check, function() { ProtectionForm.onChainClick(); } );
39 cell.appendChild( document.createTextNode( ' ' ) );
40 var label = document.createElement( 'label' );
41 label.htmlFor = 'mwProtectUnchained';
42 label.appendChild( document.createTextNode( opts.labelText ) );
43 cell.appendChild( label );
45 check.checked = !this.areAllTypesMatching();
46 this.enableUnchainedInputs( check.checked );
49 this.updateCascadeCheckbox();
55 * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
57 'updateCascadeCheckbox': function() {
58 // For non-existent titles, there is no cascade option
59 if( !document.getElementById( 'mwProtect-cascade' ) ) {
62 var lists = this.getLevelSelectors();
63 for( var i = 0; i < lists.length; i++ ) {
64 if( lists[i].selectedIndex > -1 ) {
65 var items = lists[i].getElementsByTagName( 'option' );
66 var selected = items[ lists[i].selectedIndex ].value;
67 if( !this.isCascadeableLevel(selected) ) {
68 document.getElementById( 'mwProtect-cascade' ).checked = false;
69 document.getElementById( 'mwProtect-cascade' ).disabled = true;
74 document.getElementById( 'mwProtect-cascade' ).disabled = false;
78 * Is this protection level cascadeable?
84 'isCascadeableLevel': function( level ) {
85 for (var k = 0; k < wgCascadeableLevels.length; k++) {
86 if ( wgCascadeableLevels[k] == level ) {
94 * When protection levels are locked together, update the rest
95 * when one action's level changes
97 * @param Element source Level selector that changed
99 'updateLevels': function(source) {
100 if( !this.isUnchained() )
101 this.setAllSelectors( source.selectedIndex );
102 this.updateCascadeCheckbox();
106 * When protection levels are locked together, update the
107 * expiries when one changes
109 * @param Element source expiry input that changed
112 'updateExpiry': function(source) {
113 if( !this.isUnchained() ) {
114 var expiry = source.value;
115 this.forEachExpiryInput(function(element) {
116 element.value = expiry;
119 var listId = source.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
120 var list = document.getElementById( listId );
121 if (list && list.value != 'othertime' ) {
122 if ( this.isUnchained() ) {
123 list.value = 'othertime';
125 this.forEachExpirySelector(function(element) {
126 element.value = 'othertime';
133 * When protection levels are locked together, update the
134 * expiry lists when one changes and clear the custom inputs
136 * @param Element source expiry selector that changed
138 'updateExpiryList': function(source) {
139 if( !this.isUnchained() ) {
140 var expiry = source.value;
141 this.forEachExpirySelector(function(element) {
142 element.value = expiry;
144 this.forEachExpiryInput(function(element) {
151 * Update chain status and enable/disable various bits of the UI
152 * when the user changes the "unlock move permissions" checkbox
154 'onChainClick': function() {
155 if( this.isUnchained() ) {
156 this.enableUnchainedInputs( true );
158 this.setAllSelectors( this.getMaxLevel() );
159 this.enableUnchainedInputs( false );
161 this.updateCascadeCheckbox();
165 * Returns true if the named attribute in all objects in the given array are matching
167 'matchAttribute' : function( objects, attrName ) {
171 for ( var i = 0; i < objects.length; i++ ) {
172 var element = objects[i];
173 if ( value == null ) {
174 value = element[attrName];
176 if ( value != element[attrName] ) {
185 * Are all actions protected at the same level, with the same expiry time?
189 'areAllTypesMatching': function() {
190 return this.existingMatch
191 && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
192 && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
193 && this.matchAttribute( this.getExpiryInputs(), 'value' );
197 * Is protection chaining off?
201 'isUnchained': function() {
202 var element = document.getElementById( 'mwProtectUnchained' );
205 : true; // No control, so we need to let the user set both levels
209 * Find the highest protection level in any selector
211 'getMaxLevel': function() {
213 this.forEachLevelSelector(function(element) {
214 if (element.selectedIndex > maxIndex) {
215 maxIndex = element.selectedIndex;
222 * Protect all actions at the specified level
224 * @param int index Protection level
226 'setAllSelectors': function(index) {
227 this.forEachLevelSelector(function(element) {
228 if (element.selectedIndex != index) {
229 element.selectedIndex = index;
235 * Apply a callback to each protection selector
237 * @param callable func Callback function
239 'forEachLevelSelector': function(func) {
240 var selectors = this.getLevelSelectors();
241 for (var i = 0; i < selectors.length; i++) {
247 * Get a list of all protection selectors on the page
251 'getLevelSelectors': function() {
252 var all = document.getElementsByTagName("select");
253 var ours = new Array();
254 for (var i = 0; i < all.length; i++) {
255 var element = all[i];
256 if (element.id.match(/^mwProtect-level-/)) {
257 ours[ours.length] = element;
264 * Apply a callback to each expiry input
266 * @param callable func Callback function
268 'forEachExpiryInput': function(func) {
269 var inputs = this.getExpiryInputs();
270 for (var i = 0; i < inputs.length; i++) {
276 * Get a list of all expiry inputs on the page
280 'getExpiryInputs': function() {
281 var all = document.getElementsByTagName("input");
282 var ours = new Array();
283 for (var i = 0; i < all.length; i++) {
284 var element = all[i];
285 if (element.name.match(/^mwProtect-expiry-/)) {
286 ours[ours.length] = element;
293 * Apply a callback to each expiry selector list
294 * @param callable func Callback function
296 'forEachExpirySelector': function(func) {
297 var inputs = this.getExpirySelectors();
298 for (var i = 0; i < inputs.length; i++) {
304 * Get a list of all expiry selector lists on the page
308 'getExpirySelectors': function() {
309 var all = document.getElementsByTagName("select");
310 var ours = new Array();
311 for (var i = 0; i < all.length; i++) {
312 var element = all[i];
313 if (element.id.match(/^mwProtectExpirySelection-/)) {
314 ours[ours.length] = element;
321 * Enable/disable protection selectors and expiry inputs
323 * @param boolean val Enable?
325 'enableUnchainedInputs': function(val) {
327 this.forEachLevelSelector(function(element) {
331 element.disabled = !val;
335 this.forEachExpiryInput(function(element) {
339 element.disabled = !val;
343 this.forEachExpirySelector(function(element) {
347 element.disabled = !val;