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
;