Merge "Add PreferencesFormPreSave hook"
[mediawiki.git] / resources / jquery.ui / jquery.ui.button.js
blob8326262c23afd248bd8bb5d49cf6b87dc4495ed0
1 /*!
2  * jQuery UI Button 1.8.24
3  *
4  * Copyright 2012, AUTHORS.txt (http://jqueryui.com/about)
5  * Dual licensed under the MIT or GPL Version 2 licenses.
6  * http://jquery.org/license
7  *
8  * http://docs.jquery.com/UI/Button
9  *
10  * Depends:
11  *      jquery.ui.core.js
12  *      jquery.ui.widget.js
13  */
14 (function( $, undefined ) {
16 var lastActive, startXPos, startYPos, clickDragged,
17         baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
18         stateClasses = "ui-state-hover ui-state-active ",
19         typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
20         formResetHandler = function() {
21                 var buttons = $( this ).find( ":ui-button" );
22                 setTimeout(function() {
23                         buttons.button( "refresh" );
24                 }, 1 );
25         },
26         radioGroup = function( radio ) {
27                 var name = radio.name,
28                         form = radio.form,
29                         radios = $( [] );
30                 if ( name ) {
31                         if ( form ) {
32                                 radios = $( form ).find( "[name='" + name + "']" );
33                         } else {
34                                 radios = $( "[name='" + name + "']", radio.ownerDocument )
35                                         .filter(function() {
36                                                 return !this.form;
37                                         });
38                         }
39                 }
40                 return radios;
41         };
43 $.widget( "ui.button", {
44         options: {
45                 disabled: null,
46                 text: true,
47                 label: null,
48                 icons: {
49                         primary: null,
50                         secondary: null
51                 }
52         },
53         _create: function() {
54                 this.element.closest( "form" )
55                         .unbind( "reset.button" )
56                         .bind( "reset.button", formResetHandler );
58                 if ( typeof this.options.disabled !== "boolean" ) {
59                         this.options.disabled = !!this.element.propAttr( "disabled" );
60                 } else {
61                         this.element.propAttr( "disabled", this.options.disabled );
62                 }
64                 this._determineButtonType();
65                 this.hasTitle = !!this.buttonElement.attr( "title" );
67                 var self = this,
68                         options = this.options,
69                         toggleButton = this.type === "checkbox" || this.type === "radio",
70                         hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
71                         focusClass = "ui-state-focus";
73                 if ( options.label === null ) {
74                         options.label = this.buttonElement.html();
75                 }
77                 this.buttonElement
78                         .addClass( baseClasses )
79                         .attr( "role", "button" )
80                         .bind( "mouseenter.button", function() {
81                                 if ( options.disabled ) {
82                                         return;
83                                 }
84                                 $( this ).addClass( "ui-state-hover" );
85                                 if ( this === lastActive ) {
86                                         $( this ).addClass( "ui-state-active" );
87                                 }
88                         })
89                         .bind( "mouseleave.button", function() {
90                                 if ( options.disabled ) {
91                                         return;
92                                 }
93                                 $( this ).removeClass( hoverClass );
94                         })
95                         .bind( "click.button", function( event ) {
96                                 if ( options.disabled ) {
97                                         event.preventDefault();
98                                         event.stopImmediatePropagation();
99                                 }
100                         });
102                 this.element
103                         .bind( "focus.button", function() {
104                                 // no need to check disabled, focus won't be triggered anyway
105                                 self.buttonElement.addClass( focusClass );
106                         })
107                         .bind( "blur.button", function() {
108                                 self.buttonElement.removeClass( focusClass );
109                         });
111                 if ( toggleButton ) {
112                         this.element.bind( "change.button", function() {
113                                 if ( clickDragged ) {
114                                         return;
115                                 }
116                                 self.refresh();
117                         });
118                         // if mouse moves between mousedown and mouseup (drag) set clickDragged flag
119                         // prevents issue where button state changes but checkbox/radio checked state
120                         // does not in Firefox (see ticket #6970)
121                         this.buttonElement
122                                 .bind( "mousedown.button", function( event ) {
123                                         if ( options.disabled ) {
124                                                 return;
125                                         }
126                                         clickDragged = false;
127                                         startXPos = event.pageX;
128                                         startYPos = event.pageY;
129                                 })
130                                 .bind( "mouseup.button", function( event ) {
131                                         if ( options.disabled ) {
132                                                 return;
133                                         }
134                                         if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
135                                                 clickDragged = true;
136                                         }
137                         });
138                 }
140                 if ( this.type === "checkbox" ) {
141                         this.buttonElement.bind( "click.button", function() {
142                                 if ( options.disabled || clickDragged ) {
143                                         return false;
144                                 }
145                                 $( this ).toggleClass( "ui-state-active" );
146                                 self.buttonElement.attr( "aria-pressed", self.element[0].checked );
147                         });
148                 } else if ( this.type === "radio" ) {
149                         this.buttonElement.bind( "click.button", function() {
150                                 if ( options.disabled || clickDragged ) {
151                                         return false;
152                                 }
153                                 $( this ).addClass( "ui-state-active" );
154                                 self.buttonElement.attr( "aria-pressed", "true" );
156                                 var radio = self.element[ 0 ];
157                                 radioGroup( radio )
158                                         .not( radio )
159                                         .map(function() {
160                                                 return $( this ).button( "widget" )[ 0 ];
161                                         })
162                                         .removeClass( "ui-state-active" )
163                                         .attr( "aria-pressed", "false" );
164                         });
165                 } else {
166                         this.buttonElement
167                                 .bind( "mousedown.button", function() {
168                                         if ( options.disabled ) {
169                                                 return false;
170                                         }
171                                         $( this ).addClass( "ui-state-active" );
172                                         lastActive = this;
173                                         $( document ).one( "mouseup", function() {
174                                                 lastActive = null;
175                                         });
176                                 })
177                                 .bind( "mouseup.button", function() {
178                                         if ( options.disabled ) {
179                                                 return false;
180                                         }
181                                         $( this ).removeClass( "ui-state-active" );
182                                 })
183                                 .bind( "keydown.button", function(event) {
184                                         if ( options.disabled ) {
185                                                 return false;
186                                         }
187                                         if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
188                                                 $( this ).addClass( "ui-state-active" );
189                                         }
190                                 })
191                                 .bind( "keyup.button", function() {
192                                         $( this ).removeClass( "ui-state-active" );
193                                 });
195                         if ( this.buttonElement.is("a") ) {
196                                 this.buttonElement.keyup(function(event) {
197                                         if ( event.keyCode === $.ui.keyCode.SPACE ) {
198                                                 // TODO pass through original event correctly (just as 2nd argument doesn't work)
199                                                 $( this ).click();
200                                         }
201                                 });
202                         }
203                 }
205                 // TODO: pull out $.Widget's handling for the disabled option into
206                 // $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
207                 // be overridden by individual plugins
208                 this._setOption( "disabled", options.disabled );
209                 this._resetButton();
210         },
212         _determineButtonType: function() {
214                 if ( this.element.is(":checkbox") ) {
215                         this.type = "checkbox";
216                 } else if ( this.element.is(":radio") ) {
217                         this.type = "radio";
218                 } else if ( this.element.is("input") ) {
219                         this.type = "input";
220                 } else {
221                         this.type = "button";
222                 }
224                 if ( this.type === "checkbox" || this.type === "radio" ) {
225                         // we don't search against the document in case the element
226                         // is disconnected from the DOM
227                         var ancestor = this.element.parents().filter(":last"),
228                                 labelSelector = "label[for='" + this.element.attr("id") + "']";
229                         this.buttonElement = ancestor.find( labelSelector );
230                         if ( !this.buttonElement.length ) {
231                                 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
232                                 this.buttonElement = ancestor.filter( labelSelector );
233                                 if ( !this.buttonElement.length ) {
234                                         this.buttonElement = ancestor.find( labelSelector );
235                                 }
236                         }
237                         this.element.addClass( "ui-helper-hidden-accessible" );
239                         var checked = this.element.is( ":checked" );
240                         if ( checked ) {
241                                 this.buttonElement.addClass( "ui-state-active" );
242                         }
243                         this.buttonElement.attr( "aria-pressed", checked );
244                 } else {
245                         this.buttonElement = this.element;
246                 }
247         },
249         widget: function() {
250                 return this.buttonElement;
251         },
253         destroy: function() {
254                 this.element
255                         .removeClass( "ui-helper-hidden-accessible" );
256                 this.buttonElement
257                         .removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
258                         .removeAttr( "role" )
259                         .removeAttr( "aria-pressed" )
260                         .html( this.buttonElement.find(".ui-button-text").html() );
262                 if ( !this.hasTitle ) {
263                         this.buttonElement.removeAttr( "title" );
264                 }
266                 $.Widget.prototype.destroy.call( this );
267         },
269         _setOption: function( key, value ) {
270                 $.Widget.prototype._setOption.apply( this, arguments );
271                 if ( key === "disabled" ) {
272                         if ( value ) {
273                                 this.element.propAttr( "disabled", true );
274                         } else {
275                                 this.element.propAttr( "disabled", false );
276                         }
277                         return;
278                 }
279                 this._resetButton();
280         },
282         refresh: function() {
283                 var isDisabled = this.element.is( ":disabled" );
284                 if ( isDisabled !== this.options.disabled ) {
285                         this._setOption( "disabled", isDisabled );
286                 }
287                 if ( this.type === "radio" ) {
288                         radioGroup( this.element[0] ).each(function() {
289                                 if ( $( this ).is( ":checked" ) ) {
290                                         $( this ).button( "widget" )
291                                                 .addClass( "ui-state-active" )
292                                                 .attr( "aria-pressed", "true" );
293                                 } else {
294                                         $( this ).button( "widget" )
295                                                 .removeClass( "ui-state-active" )
296                                                 .attr( "aria-pressed", "false" );
297                                 }
298                         });
299                 } else if ( this.type === "checkbox" ) {
300                         if ( this.element.is( ":checked" ) ) {
301                                 this.buttonElement
302                                         .addClass( "ui-state-active" )
303                                         .attr( "aria-pressed", "true" );
304                         } else {
305                                 this.buttonElement
306                                         .removeClass( "ui-state-active" )
307                                         .attr( "aria-pressed", "false" );
308                         }
309                 }
310         },
312         _resetButton: function() {
313                 if ( this.type === "input" ) {
314                         if ( this.options.label ) {
315                                 this.element.val( this.options.label );
316                         }
317                         return;
318                 }
319                 var buttonElement = this.buttonElement.removeClass( typeClasses ),
320                         buttonText = $( "<span></span>", this.element[0].ownerDocument )
321                                 .addClass( "ui-button-text" )
322                                 .html( this.options.label )
323                                 .appendTo( buttonElement.empty() )
324                                 .text(),
325                         icons = this.options.icons,
326                         multipleIcons = icons.primary && icons.secondary,
327                         buttonClasses = [];  
329                 if ( icons.primary || icons.secondary ) {
330                         if ( this.options.text ) {
331                                 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
332                         }
334                         if ( icons.primary ) {
335                                 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
336                         }
338                         if ( icons.secondary ) {
339                                 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
340                         }
342                         if ( !this.options.text ) {
343                                 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
345                                 if ( !this.hasTitle ) {
346                                         buttonElement.attr( "title", buttonText );
347                                 }
348                         }
349                 } else {
350                         buttonClasses.push( "ui-button-text-only" );
351                 }
352                 buttonElement.addClass( buttonClasses.join( " " ) );
353         }
356 $.widget( "ui.buttonset", {
357         options: {
358                 items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)"
359         },
361         _create: function() {
362                 this.element.addClass( "ui-buttonset" );
363         },
364         
365         _init: function() {
366                 this.refresh();
367         },
369         _setOption: function( key, value ) {
370                 if ( key === "disabled" ) {
371                         this.buttons.button( "option", key, value );
372                 }
374                 $.Widget.prototype._setOption.apply( this, arguments );
375         },
376         
377         refresh: function() {
378                 var rtl = this.element.css( "direction" ) === "rtl";
379                 
380                 this.buttons = this.element.find( this.options.items )
381                         .filter( ":ui-button" )
382                                 .button( "refresh" )
383                         .end()
384                         .not( ":ui-button" )
385                                 .button()
386                         .end()
387                         .map(function() {
388                                 return $( this ).button( "widget" )[ 0 ];
389                         })
390                                 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
391                                 .filter( ":first" )
392                                         .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
393                                 .end()
394                                 .filter( ":last" )
395                                         .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
396                                 .end()
397                         .end();
398         },
400         destroy: function() {
401                 this.element.removeClass( "ui-buttonset" );
402                 this.buttons
403                         .map(function() {
404                                 return $( this ).button( "widget" )[ 0 ];
405                         })
406                                 .removeClass( "ui-corner-left ui-corner-right" )
407                         .end()
408                         .button( "destroy" );
410                 $.Widget.prototype.destroy.call( this );
411         }
414 }( jQuery ) );