2 window.ProtectionForm = {
3 'existingMatch': false,
6 * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
7 * on the protection form
9 * @param opts Object : 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 $( '#mwProtect-reason' ).byteLimit( 180 );
51 this.updateCascadeCheckbox();
57 * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
59 'updateCascadeCheckbox': function() {
60 // For non-existent titles, there is no cascade option
61 if( !document.getElementById( 'mwProtect-cascade' ) ) {
64 var lists = this.getLevelSelectors();
65 for( var i = 0; i < lists.length; i++ ) {
66 if( lists[i].selectedIndex > -1 ) {
67 var items = lists[i].getElementsByTagName( 'option' );
68 var selected = items[ lists[i].selectedIndex ].value;
69 if( !this.isCascadeableLevel(selected) ) {
70 document.getElementById( 'mwProtect-cascade' ).checked = false;
71 document.getElementById( 'mwProtect-cascade' ).disabled = true;
76 document.getElementById( 'mwProtect-cascade' ).disabled = false;
80 * Checks if a cerain protection level is cascadeable.
81 * @param level {String}
84 'isCascadeableLevel': function( level ) {
85 var cascadeLevels, len, i;
87 cascadeLevels = mw.config.get( 'wgCascadeableLevels' );
88 // cascadeLevels isn't defined on all pages
89 if ( cascadeLevels ) {
90 for ( i = 0, len = cascadeLevels.length; i < len; i += 1 ) {
91 if ( cascadeLevels[i] === level ) {
100 * When protection levels are locked together, update the rest
101 * when one action's level changes
103 * @param source Element Level selector that changed
105 'updateLevels': function(source) {
106 if( !this.isUnchained() )
107 this.setAllSelectors( source.selectedIndex );
108 this.updateCascadeCheckbox();
112 * When protection levels are locked together, update the
113 * expiries when one changes
115 * @param source Element expiry input that changed
118 'updateExpiry': function(source) {
119 if( !this.isUnchained() ) {
120 var expiry = source.value;
121 this.forEachExpiryInput(function(element) {
122 element.value = expiry;
125 var listId = source.id.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
126 var list = document.getElementById( listId );
127 if (list && list.value != 'othertime' ) {
128 if ( this.isUnchained() ) {
129 list.value = 'othertime';
131 this.forEachExpirySelector(function(element) {
132 element.value = 'othertime';
139 * When protection levels are locked together, update the
140 * expiry lists when one changes and clear the custom inputs
142 * @param source Element expiry selector that changed
144 'updateExpiryList': function(source) {
145 if( !this.isUnchained() ) {
146 var expiry = source.value;
147 this.forEachExpirySelector(function(element) {
148 element.value = expiry;
150 this.forEachExpiryInput(function(element) {
157 * Update chain status and enable/disable various bits of the UI
158 * when the user changes the "unlock move permissions" checkbox
160 'onChainClick': function() {
161 if( this.isUnchained() ) {
162 this.enableUnchainedInputs( true );
164 this.setAllSelectors( this.getMaxLevel() );
165 this.enableUnchainedInputs( false );
167 this.updateCascadeCheckbox();
171 * Returns true if the named attribute in all objects in the given array are matching
173 'matchAttribute' : function( objects, attrName ) {
177 for ( var i = 0; i < objects.length; i++ ) {
178 var element = objects[i];
179 if ( value == null ) {
180 value = element[attrName];
182 if ( value != element[attrName] ) {
191 * Are all actions protected at the same level, with the same expiry time?
195 'areAllTypesMatching': function() {
196 return this.existingMatch
197 && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
198 && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
199 && this.matchAttribute( this.getExpiryInputs(), 'value' );
203 * Is protection chaining off?
207 'isUnchained': function() {
208 var element = document.getElementById( 'mwProtectUnchained' );
211 : true; // No control, so we need to let the user set both levels
215 * Find the highest protection level in any selector
217 'getMaxLevel': function() {
219 this.forEachLevelSelector(function(element) {
220 if (element.selectedIndex > maxIndex) {
221 maxIndex = element.selectedIndex;
228 * Protect all actions at the specified level
230 * @param index int Protection level
232 'setAllSelectors': function(index) {
233 this.forEachLevelSelector(function(element) {
234 if (element.selectedIndex != index) {
235 element.selectedIndex = index;
241 * Apply a callback to each protection selector
243 * @param func callable Callback function
245 'forEachLevelSelector': function(func) {
246 var selectors = this.getLevelSelectors();
247 for (var i = 0; i < selectors.length; i++) {
253 * Get a list of all protection selectors on the page
257 'getLevelSelectors': function() {
258 var all = document.getElementsByTagName("select");
260 for (var i = 0; i < all.length; i++) {
261 var element = all[i];
262 if (element.id.match(/^mwProtect-level-/)) {
263 ours[ours.length] = element;
270 * Apply a callback to each expiry input
272 * @param func callable Callback function
274 'forEachExpiryInput': function(func) {
275 var inputs = this.getExpiryInputs();
276 for (var i = 0; i < inputs.length; i++) {
282 * Get a list of all expiry inputs on the page
286 'getExpiryInputs': function() {
287 var all = document.getElementsByTagName("input");
289 for (var i = 0; i < all.length; i++) {
290 var element = all[i];
291 if (element.name.match(/^mwProtect-expiry-/)) {
292 ours[ours.length] = element;
299 * Apply a callback to each expiry selector list
300 * @param func callable Callback function
302 'forEachExpirySelector': function(func) {
303 var inputs = this.getExpirySelectors();
304 for (var i = 0; i < inputs.length; i++) {
310 * Get a list of all expiry selector lists on the page
314 'getExpirySelectors': function() {
315 var all = document.getElementsByTagName("select");
317 for (var i = 0; i < all.length; i++) {
318 var element = all[i];
319 if (element.id.match(/^mwProtectExpirySelection-/)) {
320 ours[ours.length] = element;
327 * Enable/disable protection selectors and expiry inputs
329 * @param val boolean Enable?
331 'enableUnchainedInputs': function(val) {
333 this.forEachLevelSelector(function(element) {
337 element.disabled = !val;
341 this.forEachExpiryInput(function(element) {
345 element.disabled = !val;
349 this.forEachExpirySelector(function(element) {
353 element.disabled = !val;