8be1321ea4d0a3dd6bf53e11f34331cf40508489
2 * Utility functions for jazzing up HTMLForm elements.
4 * @class jQuery.plugin.htmlform
11 * Helper function for hide-if to find the nearby form field.
13 * Find the closest match for the given name, "closest" being the minimum
14 * level of parents to go to find a form field matching the given name or
15 * ending in array keys matching the given name (e.g. "baz" matches
18 * @param {jQuery} element
19 * @param {string} name
20 * @return {jQuery|null}
22 function hideIfGetField( $el
, name
) {
24 suffix
= name
.replace( /^([^\[]+)/, '[$1]' );
26 function nameFilter() {
27 return this.name
=== name
||
28 ( this.name
=== ( 'wp' + name
) ) ||
29 this.name
.slice( -suffix
.length
) === suffix
;
32 for ( $p
= $el
.parent(); $p
.length
> 0; $p
= $p
.parent() ) {
33 $found
= $p
.find( '[name]' ).filter( nameFilter
);
34 if ( $found
.length
) {
42 * Helper function for hide-if to return a test function and list of
43 * dependent fields for a hide-if specification.
45 * @param {jQuery} element
46 * @param {Array} hide-if spec
47 * @return {Array} 2 elements: jQuery of dependent fields, and test function
49 function hideIfParse( $el
, spec
) {
50 var op
, i
, l
, v
, $field
, $fields
, fields
, func
, funcs
, getVal
;
61 for ( i
= 1; i
< l
; i
++ ) {
62 if ( !$.isArray( spec
[i
] ) ) {
63 throw new Error( op
+ ' parameters must be arrays' );
65 v
= hideIfParse( $el
, spec
[i
] );
69 $fields
= $( fields
);
76 for ( i
= 0; i
< l
; i
++ ) {
88 for ( i
= 0; i
< l
; i
++ ) {
100 for ( i
= 0; i
< l
; i
++ ) {
112 for ( i
= 0; i
< l
; i
++ ) {
122 return [ $fields
, func
];
126 throw new Error( 'NOT takes exactly one parameter' );
128 if ( !$.isArray( spec
[1] ) ) {
129 throw new Error( 'NOT parameters must be arrays' );
131 v
= hideIfParse( $el
, spec
[1] );
134 return [ $fields
, function () {
141 throw new Error( op
+ ' takes exactly two parameters' );
143 $field
= hideIfGetField( $el
, spec
[1] );
145 return [ $(), function () {
151 if ( $field
.first().prop( 'type' ) === 'radio' ||
152 $field
.first().prop( 'type' ) === 'checkbox'
154 getVal = function () {
155 var $selected
= $field
.filter( ':checked' );
156 return $selected
.length
? $selected
.val() : '';
159 getVal = function () {
167 return getVal() === v
;
172 return getVal() !== v
;
177 return [ $field
, func
];
180 throw new Error( 'Unrecognized operation \'' + op
+ '\'' );
185 * jQuery plugin to fade or snap to visible state.
187 * @param {boolean} [instantToggle=false]
191 $.fn
.goIn = function ( instantToggle
) {
192 if ( instantToggle
=== true ) {
195 return this.stop( true, true ).fadeIn();
199 * jQuery plugin to fade or snap to hiding state.
201 * @param {boolean} [instantToggle=false]
205 $.fn
.goOut = function ( instantToggle
) {
206 if ( instantToggle
=== true ) {
209 return this.stop( true, true ).fadeOut();
213 * Bind a function to the jQuery object via live(), and also immediately trigger
214 * the function on the objects with an 'instant' parameter set to true.
216 * @method liveAndTestAtStart
217 * @deprecated since 1.24 Use .on() and .each() directly.
218 * @param {Function} callback
219 * @param {boolean|jQuery.Event} callback.immediate True when the event is called immediately,
220 * an event object when triggered from an event.
224 mw
.log
.deprecate( $.fn
, 'liveAndTestAtStart', function ( callback
) {
226 // Can't really migrate to .on() generically, needs knowledge of
227 // calling code to know the correct selector. Fix callers and
228 // get rid of this .liveAndTestAtStart() hack.
229 .live( 'change', callback
)
231 callback
.call( this, true );
235 function enhance( $root
) {
239 * @param {boolean|jQuery.Event} instant
241 function handleSelectOrOther( instant
) {
242 var $other
= $root
.find( '#' + $( this ).attr( 'id' ) + '-other' );
243 $other
= $other
.add( $other
.siblings( 'br' ) );
244 if ( $( this ).val() === 'other' ) {
245 $other
.goIn( instant
);
247 $other
.goOut( instant
);
251 // Animate the SelectOrOther fields, to only show the text field when
252 // 'other' is selected.
254 .on( 'change', '.mw-htmlform-select-or-other', handleSelectOrOther
)
256 handleSelectOrOther
.call( this, true );
259 // Set up hide-if elements
260 $root
.find( '.mw-htmlform-hide-if' ).each( function () {
261 var v
, $fields
, test
, func
,
263 spec
= $el
.data( 'hideIf' );
269 v
= hideIfParse( $el
, spec
);
279 $fields
.on( 'change', func
);
283 function addMulti( $oldContainer
, $container
) {
284 var name
= $oldContainer
.find( 'input:first-child' ).attr( 'name' ),
285 oldClass
= ( ' ' + $oldContainer
.attr( 'class' ) + ' ' ).replace( /(mw-htmlform-field-HTMLMultiSelectField|mw-chosen)/g, '' ),
286 $select
= $( '<select>' ),
287 dataPlaceholder
= mw
.message( 'htmlform-chosen-placeholder' );
288 oldClass
= $.trim( oldClass
);
291 multiple
: 'multiple',
292 'data-placeholder': dataPlaceholder
.plain(),
293 'class': 'htmlform-chzn-select mw-input ' + oldClass
295 $oldContainer
.find( 'input' ).each( function () {
296 var $oldInput
= $( this ),
297 checked
= $oldInput
.prop( 'checked' ),
298 $option
= $( '<option>' );
299 $option
.prop( 'value', $oldInput
.prop( 'value' ) );
301 $option
.prop( 'selected', true );
303 $option
.text( $oldInput
.prop( 'value' ) );
304 $select
.append( $option
);
306 $container
.append( $select
);
309 function convertCheckboxesToMulti( $oldContainer
, type
) {
310 var $fieldLabel
= $( '<td>' ),
312 $fieldLabelText
= $( '<label>' ),
314 if ( type
=== 'tr' ) {
315 addMulti( $oldContainer
, $td
);
316 $container
= $( '<tr>' );
317 $container
.append( $td
);
318 } else if ( type
=== 'div' ) {
319 $fieldLabel
= $( '<div>' );
320 $container
= $( '<div>' );
321 addMulti( $oldContainer
, $container
);
323 $fieldLabel
.attr( 'class', 'mw-label' );
324 $fieldLabelText
.text( $oldContainer
.find( '.mw-label label' ).text() );
325 $fieldLabel
.append( $fieldLabelText
);
326 $container
.prepend( $fieldLabel
);
327 $oldContainer
.replaceWith( $container
);
331 if ( $root
.find( '.mw-chosen' ).length
) {
332 mw
.loader
.using( 'jquery.chosen', function () {
333 $root
.find( '.mw-chosen' ).each( function () {
334 var type
= this.nodeName
.toLowerCase(),
335 $converted
= convertCheckboxesToMulti( $( this ), type
);
336 $converted
.find( '.htmlform-chzn-select' ).chosen( { width
: 'auto' } );
341 var $matrixTooltips
= $root
.find( '.mw-htmlform-matrix .mw-htmlform-tooltip' );
342 if ( $matrixTooltips
.length
) {
343 mw
.loader
.using( 'jquery.tipsy', function () {
344 $matrixTooltips
.tipsy( { gravity
: 's' } );
348 // Add/remove cloner clones without having to resubmit the form
349 $root
.find( '.mw-htmlform-cloner-delete-button' ).click( function ( ev
) {
351 $( this ).closest( 'li.mw-htmlform-cloner-li' ).remove();
354 $root
.find( '.mw-htmlform-cloner-create-button' ).click( function ( ev
) {
359 $ul
= $( this ).prev( 'ul.mw-htmlform-cloner-ul' );
361 html
= $ul
.data( 'template' ).replace(
362 $ul
.data( 'uniqueId' ), 'clone' + ( ++cloneCounter
), 'g'
366 .addClass( 'mw-htmlform-cloner-li' )
373 mw
.hook( 'htmlform.enhance' ).fire( $root
);
378 enhance( $( document
) );
383 * @mixins jQuery.plugin.htmlform
385 }( mediaWiki
, jQuery
) );