2 * HTMLForm enhancements:
3 * Set up 'hide-if' behaviors for form fields that have them.
8 * Helper function for hide-if to find the nearby form field.
10 * Find the closest match for the given name, "closest" being the minimum
11 * level of parents to go to find a form field matching the given name or
12 * ending in array keys matching the given name (e.g. "baz" matches
18 * @param {string} name
19 * @return {jQuery|OO.ui.Widget|null}
21 function hideIfGetField( $el
, name
) {
22 var $found
, $p
, $widget
,
23 suffix
= name
.replace( /^([^\[]+)/, '[$1]' );
25 function nameFilter() {
26 return this.name
=== name
||
27 ( this.name
=== ( 'wp' + name
) ) ||
28 this.name
.slice( -suffix
.length
) === suffix
;
31 for ( $p
= $el
.parent(); $p
.length
> 0; $p
= $p
.parent() ) {
32 $found
= $p
.find( '[name]' ).filter( nameFilter
);
33 if ( $found
.length
) {
34 $widget
= $found
.closest( '.oo-ui-widget[data-ooui]' );
35 if ( $widget
.length
) {
36 return OO
.ui
.Widget
.static.infuse( $widget
);
45 * Helper function for hide-if to return a test function and list of
46 * dependent fields for a hide-if specification.
53 * @return {Array} return.0 Dependent fields, array of jQuery objects or OO.ui.Widgets
54 * @return {Function} return.1 Test function
56 function hideIfParse( $el
, spec
) {
57 var op
, i
, l
, v
, field
, $field
, fields
, func
, funcs
, getVal
;
68 for ( i
= 1; i
< l
; i
++ ) {
69 if ( !$.isArray( spec
[ i
] ) ) {
70 throw new Error( op
+ ' parameters must be arrays' );
72 v
= hideIfParse( $el
, spec
[ i
] );
73 fields
= fields
.concat( v
[ 0 ] );
82 for ( i
= 0; i
< l
; i
++ ) {
83 if ( !funcs
[ i
]() ) {
94 for ( i
= 0; i
< l
; i
++ ) {
106 for ( i
= 0; i
< l
; i
++ ) {
107 if ( !funcs
[ i
]() ) {
118 for ( i
= 0; i
< l
; i
++ ) {
119 if ( funcs
[ i
]() ) {
128 return [ fields
, func
];
132 throw new Error( 'NOT takes exactly one parameter' );
134 if ( !$.isArray( spec
[ 1 ] ) ) {
135 throw new Error( 'NOT parameters must be arrays' );
137 v
= hideIfParse( $el
, spec
[ 1 ] );
140 return [ fields
, function () {
147 throw new Error( op
+ ' takes exactly two parameters' );
149 field
= hideIfGetField( $el
, spec
[ 1 ] );
151 return [ [], function () {
157 if ( !( field
instanceof jQuery
) ) {
158 // field is a OO.ui.Widget
159 if ( field
.supports( 'isSelected' ) ) {
160 getVal = function () {
161 var selected
= field
.isSelected();
162 return selected
? field
.getValue() : '';
165 getVal = function () {
166 return field
.getValue();
171 if ( $field
.prop( 'type' ) === 'radio' || $field
.prop( 'type' ) === 'checkbox' ) {
172 getVal = function () {
173 var $selected
= $field
.filter( ':checked' );
174 return $selected
.length
? $selected
.val() : '';
177 getVal = function () {
186 return getVal() === v
;
191 return getVal() !== v
;
196 return [ [ field
], func
];
199 throw new Error( 'Unrecognized operation \'' + op
+ '\'' );
203 mw
.hook( 'htmlform.enhance' ).add( function ( $root
) {
204 $root
.find( '.mw-htmlform-hide-if' ).each( function () {
205 var v
, i
, fields
, test
, func
, spec
, self
, modules
, data
, extraModules
,
209 if ( $el
.is( '[data-ooui]' ) ) {
210 modules
.push( 'mediawiki.htmlform.ooui' );
211 data
= $el
.data( 'mw-modules' );
213 // We can trust this value, 'data-mw-*' attributes are banned from user content in Sanitizer
214 extraModules
= data
.split( ',' );
215 modules
.push
.apply( modules
, extraModules
);
219 mw
.loader
.using( modules
).done( function () {
220 if ( $el
.is( '[data-ooui]' ) ) {
221 // self should be a FieldLayout that mixes in mw.htmlform.Element
222 self
= OO
.ui
.FieldLayout
.static.infuse( $el
);
224 // The original element has been replaced with infused one
228 spec
= $el
.data( 'hideIf' );
235 v
= hideIfParse( $el
, spec
);
238 // The .toggle() method works mostly the same for jQuery objects and OO.ui.Widget
240 self
.toggle( !test() );
242 for ( i
= 0; i
< fields
.length
; i
++ ) {
243 // The .on() method works mostly the same for jQuery objects and OO.ui.Widget
244 fields
[ i
].on( 'change', func
);
251 }( mediaWiki
, jQuery
) );