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 $( check
).click( function () {
42 ProtectionForm
.onChainClick();
45 label
= document
.createElement( 'label' );
46 label
.htmlFor
= 'mwProtectUnchained';
47 label
.appendChild( document
.createTextNode( opts
.labelText
) );
49 cell
.appendChild( check
);
50 cell
.appendChild( document
.createTextNode( ' ' ) );
51 cell
.appendChild( label
);
53 check
.checked
= !this.areAllTypesMatching();
54 this.enableUnchainedInputs( check
.checked
);
57 $( '#mwProtect-reason' ).byteLimit( 180 );
59 this.updateCascadeCheckbox();
65 * Sets the disabled attribute on the cascade checkbox depending on the current selected levels
67 updateCascadeCheckbox: function () {
68 var i
, lists
, items
, selected
;
70 // For non-existent titles, there is no cascade option
71 if ( !document
.getElementById( 'mwProtect-cascade' ) ) {
74 lists
= this.getLevelSelectors();
75 for ( i
= 0; i
< lists
.length
; i
++ ) {
76 if ( lists
[i
].selectedIndex
> -1 ) {
77 items
= lists
[i
].getElementsByTagName( 'option' );
78 selected
= items
[ lists
[i
].selectedIndex
].value
;
79 if ( !this.isCascadeableLevel( selected
) ) {
80 document
.getElementById( 'mwProtect-cascade' ).checked
= false;
81 document
.getElementById( 'mwProtect-cascade' ).disabled
= true;
86 document
.getElementById( 'mwProtect-cascade' ).disabled
= false;
90 * Checks if a cerain protection level is cascadeable.
91 * @param level {String}
94 isCascadeableLevel: function ( level
) {
95 var cascadeLevels
, len
, i
;
97 cascadeLevels
= mw
.config
.get( 'wgCascadeableLevels' );
98 // cascadeLevels isn't defined on all pages
99 if ( cascadeLevels
) {
100 for ( i
= 0, len
= cascadeLevels
.length
; i
< len
; i
+= 1 ) {
101 if ( cascadeLevels
[i
] === level
) {
110 * When protection levels are locked together, update the rest
111 * when one action's level changes
113 * @param source Element Level selector that changed
115 updateLevels: function ( source
) {
116 if ( !this.isUnchained() ) {
117 this.setAllSelectors( source
.selectedIndex
);
119 this.updateCascadeCheckbox();
123 * When protection levels are locked together, update the
124 * expiries when one changes
126 * @param source Element expiry input that changed
129 updateExpiry: function ( source
) {
130 var expiry
, listId
, list
;
132 if ( !this.isUnchained() ) {
133 expiry
= source
.value
;
134 this.forEachExpiryInput( function ( element
) {
135 element
.value
= expiry
;
138 listId
= source
.id
.replace( /^mwProtect-(\w+)-expires$/, 'mwProtectExpirySelection-$1' );
139 list
= document
.getElementById( listId
);
140 if ( list
&& list
.value
!== 'othertime' ) {
141 if ( this.isUnchained() ) {
142 list
.value
= 'othertime';
144 this.forEachExpirySelector( function ( element
) {
145 element
.value
= 'othertime';
152 * When protection levels are locked together, update the
153 * expiry lists when one changes and clear the custom inputs
155 * @param source Element expiry selector that changed
157 updateExpiryList: function ( source
) {
159 if ( !this.isUnchained() ) {
160 expiry
= source
.value
;
161 this.forEachExpirySelector( function ( element
) {
162 element
.value
= expiry
;
164 this.forEachExpiryInput( function ( element
) {
171 * Update chain status and enable/disable various bits of the UI
172 * when the user changes the "unlock move permissions" checkbox
174 onChainClick: function () {
175 if ( this.isUnchained() ) {
176 this.enableUnchainedInputs( true );
178 this.setAllSelectors( this.getMaxLevel() );
179 this.enableUnchainedInputs( false );
181 this.updateCascadeCheckbox();
185 * Returns true if the named attribute in all objects in the given array are matching
187 matchAttribute: function ( objects
, attrName
) {
188 var i
, element
, value
;
192 for ( i
= 0; i
< objects
.length
; i
++ ) {
193 element
= objects
[i
];
194 if ( value
=== null ) {
195 value
= element
[attrName
];
197 if ( value
!== element
[attrName
] ) {
206 * Are all actions protected at the same level, with the same expiry time?
210 areAllTypesMatching: function () {
211 return this.existingMatch
212 && this.matchAttribute( this.getLevelSelectors(), 'selectedIndex' )
213 && this.matchAttribute( this.getExpirySelectors(), 'selectedIndex' )
214 && this.matchAttribute( this.getExpiryInputs(), 'value' );
218 * Is protection chaining off?
222 isUnchained: function () {
223 var element
= document
.getElementById( 'mwProtectUnchained' );
226 : true; // No control, so we need to let the user set both levels
230 * Find the highest protection level in any selector
232 getMaxLevel: function () {
234 this.forEachLevelSelector( function ( element
) {
235 if ( element
.selectedIndex
> maxIndex
) {
236 maxIndex
= element
.selectedIndex
;
243 * Protect all actions at the specified level
245 * @param index int Protection level
247 setAllSelectors: function ( index
) {
248 this.forEachLevelSelector( function ( element
) {
249 if ( element
.selectedIndex
!== index
) {
250 element
.selectedIndex
= index
;
256 * Apply a callback to each protection selector
258 * @param func callable Callback function
260 forEachLevelSelector: function ( func
) {
263 selectors
= this.getLevelSelectors();
264 for ( i
= 0; i
< selectors
.length
; i
++ ) {
265 func( selectors
[i
] );
270 * Get a list of all protection selectors on the page
274 getLevelSelectors: function () {
275 var i
, ours
, all
, element
;
277 all
= document
.getElementsByTagName( 'select' );
279 for ( i
= 0; i
< all
.length
; i
++ ) {
281 if ( element
.id
.match( /^mwProtect-level-/ ) ) {
282 ours
[ours
.length
] = element
;
289 * Apply a callback to each expiry input
291 * @param func callable Callback function
293 forEachExpiryInput: function ( func
) {
296 inputs
= this.getExpiryInputs();
297 for ( i
= 0; i
< inputs
.length
; i
++ ) {
303 * Get a list of all expiry inputs on the page
307 getExpiryInputs: function () {
308 var i
, all
, element
, ours
;
310 all
= document
.getElementsByTagName( 'input' );
312 for ( i
= 0; i
< all
.length
; i
++ ) {
314 if ( element
.name
.match( /^mwProtect-expiry-/ ) ) {
315 ours
[ours
.length
] = element
;
322 * Apply a callback to each expiry selector list
323 * @param func callable Callback function
325 forEachExpirySelector: function ( func
) {
328 inputs
= this.getExpirySelectors();
329 for ( i
= 0; i
< inputs
.length
; i
++ ) {
335 * Get a list of all expiry selector lists on the page
339 getExpirySelectors: function () {
340 var i
, all
, ours
, element
;
342 all
= document
.getElementsByTagName( 'select' );
344 for ( i
= 0; i
< all
.length
; i
++ ) {
346 if ( element
.id
.match( /^mwProtectExpirySelection-/ ) ) {
347 ours
[ours
.length
] = element
;
354 * Enable/disable protection selectors and expiry inputs
356 * @param val boolean Enable?
358 enableUnchainedInputs: function ( val
) {
361 this.forEachLevelSelector( function ( element
) {
365 element
.disabled
= !val
;
369 this.forEachExpiryInput( function ( element
) {
373 element
.disabled
= !val
;
377 this.forEachExpirySelector( function ( element
) {
381 element
.disabled
= !val
;
387 }( mediaWiki
, jQuery
) );