Merge "Make line breaks in <blockquote> behave like <div> (bug 6200)."
[mediawiki.git] / skins / common / protect.js
bloba23c0cbd8a27c0a7f215ad5cd1e82ecfcc8b38b2
2 window.ProtectionForm = {
3         'existingMatch': false,
5         /**
6          * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
7          * on the protection form
8          *
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
14          */
15         'init': function( opts ) {
16                 if( !( document.createTextNode && document.getElementById && document.getElementsByTagName ) )
17                         return false;
19                 var box = document.getElementById( opts.tableId );
20                 if( !box )
21                         return false;
22                 
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 );
47                 }
48                 
49                 $( '#mwProtect-reason' ).byteLimit( 180 );
51                 this.updateCascadeCheckbox();
53                 return true;
54         },
56         /**
57          * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
58          */
59         'updateCascadeCheckbox': function() {
60                 // For non-existent titles, there is no cascade option
61                 if( !document.getElementById( 'mwProtect-cascade' ) ) {
62                         return;
63                 }
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;
72                                         return;
73                                 }
74                         }
75                 }
76                 document.getElementById( 'mwProtect-cascade' ).disabled = false;
77         },
79         /**
80          * Checks if a cerain protection level is cascadeable.
81          * @param level {String}
82          * @return {Boolean}
83          */
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 ) {
92                                         return true;
93                                 }
94                         }
95                 }
96                 return false;
97         },
99         /**
100          * When protection levels are locked together, update the rest
101          * when one action's level changes
102          *
103          * @param source Element Level selector that changed
104          */
105         'updateLevels': function(source) {
106                 if( !this.isUnchained() )
107                         this.setAllSelectors( source.selectedIndex );
108                 this.updateCascadeCheckbox();
109         },
111         /**
112          * When protection levels are locked together, update the
113          * expiries when one changes
114          *
115          * @param source Element expiry input that changed
116          */
118         'updateExpiry': function(source) {
119                 if( !this.isUnchained() ) {
120                         var expiry = source.value;
121                         this.forEachExpiryInput(function(element) {
122                                 element.value = expiry;
123                         });
124                 }
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';
130                         } else {
131                                 this.forEachExpirySelector(function(element) {
132                                         element.value = 'othertime';
133                                 });
134                         }
135                 }
136         },
138         /**
139          * When protection levels are locked together, update the
140          * expiry lists when one changes and clear the custom inputs
141          *
142          * @param source Element expiry selector that changed
143          */
144         'updateExpiryList': function(source) {
145                 if( !this.isUnchained() ) {
146                         var expiry = source.value;
147                         this.forEachExpirySelector(function(element) {
148                                 element.value = expiry;
149                         });
150                         this.forEachExpiryInput(function(element) {
151                                 element.value = '';
152                         });
153                 }
154         },
156         /**
157          * Update chain status and enable/disable various bits of the UI
158          * when the user changes the "unlock move permissions" checkbox
159          */
160         'onChainClick': function() {
161                 if( this.isUnchained() ) {
162                         this.enableUnchainedInputs( true );
163                 } else {
164                         this.setAllSelectors( this.getMaxLevel() );
165                         this.enableUnchainedInputs( false );
166                 }
167                 this.updateCascadeCheckbox();
168         },
170         /**
171          * Returns true if the named attribute in all objects in the given array are matching
172          */
173         'matchAttribute' : function( objects, attrName ) {
174                 var value = null;
176                 // Check levels
177                 for ( var i = 0; i < objects.length; i++ ) {
178                         var element = objects[i];
179                         if ( value == null ) {
180                                 value = element[attrName];
181                         } else {
182                                 if ( value != element[attrName] ) {
183                                         return false;
184                                 }
185                         }
186                 }
187                 return true;
188         },
190         /**
191          * Are all actions protected at the same level, with the same expiry time?
192          *
193          * @return boolean
194          */
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' );
200         },
202         /**
203          * Is protection chaining off?
204          *
205          * @return bool
206          */
207         'isUnchained': function() {
208                 var element = document.getElementById( 'mwProtectUnchained' );
209                 return element
210                         ? element.checked
211                         : true; // No control, so we need to let the user set both levels
212         },
214         /**
215          * Find the highest protection level in any selector
216          */
217         'getMaxLevel': function() {
218                 var maxIndex = -1;
219                 this.forEachLevelSelector(function(element) {
220                         if (element.selectedIndex > maxIndex) {
221                                 maxIndex = element.selectedIndex;
222                         }
223                 });
224                 return maxIndex;
225         },
227         /**
228          * Protect all actions at the specified level
229          *
230          * @param index int Protection level
231          */
232         'setAllSelectors': function(index) {
233                 this.forEachLevelSelector(function(element) {
234                         if (element.selectedIndex != index) {
235                                 element.selectedIndex = index;
236                         }
237                 });
238         },
240         /**
241          * Apply a callback to each protection selector
242          *
243          * @param func callable Callback function
244          */
245         'forEachLevelSelector': function(func) {
246                 var selectors = this.getLevelSelectors();
247                 for (var i = 0; i < selectors.length; i++) {
248                         func(selectors[i]);
249                 }
250         },
252         /**
253          * Get a list of all protection selectors on the page
254          *
255          * @return Array
256          */
257         'getLevelSelectors': function() {
258                 var all = document.getElementsByTagName("select");
259                 var ours = [];
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;
264                         }
265                 }
266                 return ours;
267         },
269         /**
270          * Apply a callback to each expiry input
271          *
272          * @param func callable Callback function
273          */
274         'forEachExpiryInput': function(func) {
275                 var inputs = this.getExpiryInputs();
276                 for (var i = 0; i < inputs.length; i++) {
277                         func(inputs[i]);
278                 }
279         },
281         /**
282          * Get a list of all expiry inputs on the page
283          *
284          * @return Array
285          */
286         'getExpiryInputs': function() {
287                 var all = document.getElementsByTagName("input");
288                 var ours = [];
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;
293                         }
294                 }
295                 return ours;
296         },
298         /**
299          * Apply a callback to each expiry selector list
300          * @param func callable Callback function
301          */
302         'forEachExpirySelector': function(func) {
303                 var inputs = this.getExpirySelectors();
304                 for (var i = 0; i < inputs.length; i++) {
305                         func(inputs[i]);
306                 }
307         },
309         /**
310          * Get a list of all expiry selector lists on the page
311          *
312          * @return Array
313          */
314         'getExpirySelectors': function() {
315                 var all = document.getElementsByTagName("select");
316                 var ours = [];
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;
321                         }
322                 }
323                 return ours;
324         },
326         /**
327          * Enable/disable protection selectors and expiry inputs
328          *
329          * @param val boolean Enable?
330          */
331         'enableUnchainedInputs': function(val) {
332                 var first = true;
333                 this.forEachLevelSelector(function(element) {
334                         if (first) {
335                                 first = false;
336                         } else {
337                                 element.disabled = !val;
338                         }
339                 });
340                 first = true;
341                 this.forEachExpiryInput(function(element) {
342                         if (first) {
343                                 first = false;
344                         } else {
345                                 element.disabled = !val;
346                         }
347                 });
348                 first = true;
349                 this.forEachExpirySelector(function(element) {
350                         if (first) {
351                                 first = false;
352                         } else {
353                                 element.disabled = !val;
354                         }
355                 });
356         }