3 var ProtectionForm
= window
.ProtectionForm
= {
7 * Set up the protection chaining interface (i.e. "unlock move permissions" checkbox)
8 * on the protection form
10 * @param opts Object : parameters with members:
11 * tableId Identifier of the table containing UI bits
12 * labelText Text to use for the checkbox label
13 * numTypes The number of protection types
14 * existingMatch True if all the existing expiry times match
16 init: function ( opts
) {
17 var box
, boxbody
, row
, cell
, check
, label
;
19 if ( !( document
.createTextNode
&& document
.getElementById
&& document
.getElementsByTagName
) ) {
23 box
= document
.getElementById( opts
.tableId
);
28 boxbody
= box
.getElementsByTagName( 'tbody' )[0];
29 row
= document
.createElement( 'tr' );
30 boxbody
.insertBefore( row
, boxbody
.firstChild
.nextSibling
);
32 this.existingMatch
= opts
.existingMatch
;
34 cell
= document
.createElement( 'td' );
35 row
.appendChild( cell
);
36 // If there is only one protection type, there is nothing to chain
37 if ( opts
.numTypes
> 1 ) {
38 check
= document
.createElement( 'input' );
39 check
.id
= 'mwProtectUnchained';
40 check
.type
= 'checkbox';
41 cell
.appendChild( check
);
42 window
.addClickHandler( check
, function () {
43 ProtectionForm
.onChainClick();
46 cell
.appendChild( document
.createTextNode( ' ' ) );
47 label
= document
.createElement( 'label' );
48 label
.htmlFor
= 'mwProtectUnchained';
49 label
.appendChild( document
.createTextNode( opts
.labelText
) );
50 cell
.appendChild( label
);
52 check
.checked
= !this.areAllTypesMatching();
53 this.enableUnchainedInputs( check
.checked
);
56 $( '#mwProtect-reason' ).byteLimit( 180 );
58 this.updateCascadeCheckbox();
64 * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
66 updateCascadeCheckbox: function () {
67 var i
, lists
, items
, selected
;
69 // For non-existent titles, there is no cascade option
70 if ( !document
.getElementById( 'mwProtect-cascade' ) ) {
73 lists
= this.getLevelSelectors();
74 for ( i
= 0; i
< lists
.length
; i
++ ) {
75 if ( lists
[i
].selectedIndex
> -1 ) {
76 items
= lists
[i
].getElementsByTagName( 'option' );
77 selected
= items
[ lists
[i
].selectedIndex
].value
;
78 if ( !this.isCascadeableLevel( selected
) ) {
79 document
.getElementById( 'mwProtect-cascade' ).checked
= false;
80 document
.getElementById( 'mwProtect-cascade' ).disabled
= true;
85 document
.getElementById( 'mwProtect-cascade' ).disabled
= false;
89 * Checks if a cerain protection level is cascadeable.
90 * @param level {String}
93 isCascadeableLevel: function ( level
) {
94 var cascadeLevels
, len
, i
;
96 cascadeLevels
= mw
.config
.get( 'wgCascadeableLevels' );
97 // cascadeLevels isn't defined on all pages
98 if ( cascadeLevels
) {
99 for ( i
= 0, len
= cascadeLevels
.length
; i
< len
; i
+= 1 ) {
100 if ( cascadeLevels
[i
] === level
) {
109 * When protection levels are locked together, update the rest
110 * when one action's level changes
112 * @param source Element Level selector that changed
114 updateLevels: function ( source
) {
115 if ( !this.isUnchained() ) {
116 this.setAllSelectors( source
.selectedIndex
);
118 this.updateCascadeCheckbox();
122 * When protection levels are locked together, update the
123 * expiries when one changes
125 * @param source Element expiry input that changed
128 updateExpiry: function ( source
) {
129 var expiry
, listId
, list
;
131 if ( !this.isUnchained() ) {
132 expiry
= source
.value
;
133 this.forEachExpiryInput( function ( element
) {
134 element
.value
= expiry
;
137 listId
= source
.id
.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
138 list
= document
.getElementById( listId
);
139 if ( list
&& list
.value
!== 'othertime' ) {
140 if ( this.isUnchained() ) {
141 list
.value
= 'othertime';
143 this.forEachExpirySelector( function ( element
) {
144 element
.value
= 'othertime';
151 * When protection levels are locked together, update the
152 * expiry lists when one changes and clear the custom inputs
154 * @param source Element expiry selector that changed
156 updateExpiryList: function ( source
) {
158 if ( !this.isUnchained() ) {
159 expiry
= source
.value
;
160 this.forEachExpirySelector( function ( element
) {
161 element
.value
= expiry
;
163 this.forEachExpiryInput( function ( element
) {
170 * Update chain status and enable/disable various bits of the UI
171 * when the user changes the "unlock move permissions" checkbox
173 onChainClick: function () {
174 if ( this.isUnchained() ) {
175 this.enableUnchainedInputs( true );
177 this.setAllSelectors( this.getMaxLevel() );
178 this.enableUnchainedInputs( false );
180 this.updateCascadeCheckbox();
184 * Returns true if the named attribute in all objects in the given array are matching
186 matchAttribute: function ( objects
, attrName
) {
187 var i
, element
, value
;
191 for ( i
= 0; i
< objects
.length
; i
++ ) {
192 element
= objects
[i
];
193 if ( value
=== null ) {
194 value
= element
[attrName
];
196 if ( value
!== element
[attrName
] ) {
205 * Are all actions protected at the same level, with the same expiry time?
209 areAllTypesMatching: function () {
210 return this.existingMatch
211 && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
212 && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
213 && this.matchAttribute( this.getExpiryInputs(), 'value' );
217 * Is protection chaining off?
221 isUnchained: function () {
222 var element
= document
.getElementById( 'mwProtectUnchained' );
225 : true; // No control, so we need to let the user set both levels
229 * Find the highest protection level in any selector
231 getMaxLevel: function () {
233 this.forEachLevelSelector( function ( element
) {
234 if ( element
.selectedIndex
> maxIndex
) {
235 maxIndex
= element
.selectedIndex
;
242 * Protect all actions at the specified level
244 * @param index int Protection level
246 setAllSelectors: function ( index
) {
247 this.forEachLevelSelector( function ( element
) {
248 if ( element
.selectedIndex
!== index
) {
249 element
.selectedIndex
= index
;
255 * Apply a callback to each protection selector
257 * @param func callable Callback function
259 forEachLevelSelector: function ( func
) {
262 selectors
= this.getLevelSelectors();
263 for ( i
= 0; i
< selectors
.length
; i
++ ) {
264 func( selectors
[i
] );
269 * Get a list of all protection selectors on the page
273 getLevelSelectors: function () {
274 var i
, ours
, all
, element
;
276 all
= document
.getElementsByTagName( 'select' );
278 for ( i
= 0; i
< all
.length
; i
++ ) {
280 if ( element
.id
.match( /^mwProtect-level-/ ) ) {
281 ours
[ours
.length
] = element
;
288 * Apply a callback to each expiry input
290 * @param func callable Callback function
292 forEachExpiryInput: function ( func
) {
295 inputs
= this.getExpiryInputs();
296 for ( i
= 0; i
< inputs
.length
; i
++ ) {
302 * Get a list of all expiry inputs on the page
306 getExpiryInputs: function () {
307 var i
, all
, element
, ours
;
309 all
= document
.getElementsByTagName( 'input' );
311 for ( i
= 0; i
< all
.length
; i
++ ) {
313 if ( element
.name
.match( /^mwProtect-expiry-/ ) ) {
314 ours
[ours
.length
] = element
;
321 * Apply a callback to each expiry selector list
322 * @param func callable Callback function
324 forEachExpirySelector: function ( func
) {
327 inputs
= this.getExpirySelectors();
328 for ( i
= 0; i
< inputs
.length
; i
++ ) {
334 * Get a list of all expiry selector lists on the page
338 getExpirySelectors: function () {
339 var i
, all
, ours
, element
;
341 all
= document
.getElementsByTagName( 'select' );
343 for ( i
= 0; i
< all
.length
; i
++ ) {
345 if ( element
.id
.match( /^mwProtectExpirySelection-/ ) ) {
346 ours
[ours
.length
] = element
;
353 * Enable/disable protection selectors and expiry inputs
355 * @param val boolean Enable?
357 enableUnchainedInputs: function ( val
) {
360 this.forEachLevelSelector( function ( element
) {
364 element
.disabled
= !val
;
368 this.forEachExpiryInput( function ( element
) {
372 element
.disabled
= !val
;
376 this.forEachExpirySelector( function ( element
) {
380 element
.disabled
= !val
;
386 }( mediaWiki
, jQuery
) );