jquery-ui-rails 2.0.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of jquery-ui-rails might be problematic. Click here for more details.

Files changed (131) hide show
  1. data/History.md +15 -0
  2. data/License.txt +2 -3
  3. data/README.md +17 -19
  4. data/Rakefile +79 -28
  5. data/lib/jquery/ui/rails/version.rb +1 -1
  6. data/vendor/assets/javascripts/jquery.ui.accordion.js +537 -417
  7. data/vendor/assets/javascripts/jquery.ui.all.js +17 -14
  8. data/vendor/assets/javascripts/jquery.ui.autocomplete.js +311 -339
  9. data/vendor/assets/javascripts/jquery.ui.button.js +63 -59
  10. data/vendor/assets/javascripts/jquery.ui.core.js +134 -112
  11. data/vendor/assets/javascripts/jquery.ui.datepicker-ar-DZ.js +2 -2
  12. data/vendor/assets/javascripts/jquery.ui.datepicker-ar.js +3 -3
  13. data/vendor/assets/javascripts/jquery.ui.datepicker-az.js +3 -3
  14. data/vendor/assets/javascripts/jquery.ui.datepicker-bg.js +16 -16
  15. data/vendor/assets/javascripts/jquery.ui.datepicker-bs.js +5 -5
  16. data/vendor/assets/javascripts/jquery.ui.datepicker-ca.js +13 -13
  17. data/vendor/assets/javascripts/jquery.ui.datepicker-cs.js +3 -3
  18. data/vendor/assets/javascripts/jquery.ui.datepicker-cy-GB.js +1 -1
  19. data/vendor/assets/javascripts/jquery.ui.datepicker-da.js +9 -9
  20. data/vendor/assets/javascripts/jquery.ui.datepicker-de.js +2 -2
  21. data/vendor/assets/javascripts/jquery.ui.datepicker-el.js +1 -1
  22. data/vendor/assets/javascripts/jquery.ui.datepicker-eo.js +2 -2
  23. data/vendor/assets/javascripts/jquery.ui.datepicker-es.js +6 -6
  24. data/vendor/assets/javascripts/jquery.ui.datepicker-et.js +1 -1
  25. data/vendor/assets/javascripts/jquery.ui.datepicker-eu.js +3 -3
  26. data/vendor/assets/javascripts/jquery.ui.datepicker-fa.js +3 -3
  27. data/vendor/assets/javascripts/jquery.ui.datepicker-fi.js +5 -5
  28. data/vendor/assets/javascripts/jquery.ui.datepicker-fo.js +3 -3
  29. data/vendor/assets/javascripts/jquery.ui.datepicker-fr-CH.js +3 -3
  30. data/vendor/assets/javascripts/jquery.ui.datepicker-fr.js +2 -2
  31. data/vendor/assets/javascripts/jquery.ui.datepicker-gl.js +6 -6
  32. data/vendor/assets/javascripts/jquery.ui.datepicker-he.js +2 -2
  33. data/vendor/assets/javascripts/jquery.ui.datepicker-hr.js +3 -3
  34. data/vendor/assets/javascripts/jquery.ui.datepicker-hy.js +3 -3
  35. data/vendor/assets/javascripts/jquery.ui.datepicker-id.js +3 -3
  36. data/vendor/assets/javascripts/jquery.ui.datepicker-is.js +11 -11
  37. data/vendor/assets/javascripts/jquery.ui.datepicker-it.js +3 -3
  38. data/vendor/assets/javascripts/jquery.ui.datepicker-ja.js +3 -3
  39. data/vendor/assets/javascripts/jquery.ui.datepicker-kk.js +2 -2
  40. data/vendor/assets/javascripts/jquery.ui.datepicker-ko.js +1 -1
  41. data/vendor/assets/javascripts/jquery.ui.datepicker-lt.js +3 -3
  42. data/vendor/assets/javascripts/jquery.ui.datepicker-lv.js +1 -1
  43. data/vendor/assets/javascripts/jquery.ui.datepicker-ml.js +1 -1
  44. data/vendor/assets/javascripts/jquery.ui.datepicker-ms.js +3 -3
  45. data/vendor/assets/javascripts/jquery.ui.datepicker-nl.js +1 -1
  46. data/vendor/assets/javascripts/jquery.ui.datepicker-no.js +18 -18
  47. data/vendor/assets/javascripts/jquery.ui.datepicker-pl.js +2 -2
  48. data/vendor/assets/javascripts/jquery.ui.datepicker-pt-BR.js +7 -7
  49. data/vendor/assets/javascripts/jquery.ui.datepicker-pt.js +6 -6
  50. data/vendor/assets/javascripts/jquery.ui.datepicker-rm.js +2 -2
  51. data/vendor/assets/javascripts/jquery.ui.datepicker-ro.js +2 -2
  52. data/vendor/assets/javascripts/jquery.ui.datepicker-ru.js +3 -3
  53. data/vendor/assets/javascripts/jquery.ui.datepicker-sk.js +2 -2
  54. data/vendor/assets/javascripts/jquery.ui.datepicker-sl.js +6 -6
  55. data/vendor/assets/javascripts/jquery.ui.datepicker-sq.js +2 -2
  56. data/vendor/assets/javascripts/jquery.ui.datepicker-sr-SR.js +2 -2
  57. data/vendor/assets/javascripts/jquery.ui.datepicker-sr.js +2 -2
  58. data/vendor/assets/javascripts/jquery.ui.datepicker-sv.js +9 -9
  59. data/vendor/assets/javascripts/jquery.ui.datepicker-th.js +3 -3
  60. data/vendor/assets/javascripts/jquery.ui.datepicker-tj.js +1 -1
  61. data/vendor/assets/javascripts/jquery.ui.datepicker-tr.js +2 -2
  62. data/vendor/assets/javascripts/jquery.ui.datepicker-uk.js +3 -3
  63. data/vendor/assets/javascripts/jquery.ui.datepicker-vi.js +2 -2
  64. data/vendor/assets/javascripts/jquery.ui.datepicker-zh-CN.js +2 -2
  65. data/vendor/assets/javascripts/jquery.ui.datepicker-zh-HK.js +2 -2
  66. data/vendor/assets/javascripts/jquery.ui.datepicker-zh-TW.js +2 -2
  67. data/vendor/assets/javascripts/jquery.ui.datepicker.js +51 -59
  68. data/vendor/assets/javascripts/jquery.ui.dialog.js +402 -409
  69. data/vendor/assets/javascripts/jquery.ui.draggable.js +79 -75
  70. data/vendor/assets/javascripts/jquery.ui.droppable.js +10 -17
  71. data/vendor/assets/javascripts/jquery.ui.effect-blind.js +84 -0
  72. data/vendor/assets/javascripts/jquery.ui.effect-bounce.js +115 -0
  73. data/vendor/assets/javascripts/jquery.ui.effect-clip.js +69 -0
  74. data/vendor/assets/javascripts/jquery.ui.effect-drop.js +67 -0
  75. data/vendor/assets/javascripts/jquery.ui.effect-explode.js +99 -0
  76. data/vendor/assets/javascripts/jquery.ui.effect-fade.js +32 -0
  77. data/vendor/assets/javascripts/jquery.ui.effect-fold.js +78 -0
  78. data/vendor/assets/javascripts/jquery.ui.effect-highlight.js +52 -0
  79. data/vendor/assets/javascripts/jquery.ui.effect-pulsate.js +65 -0
  80. data/vendor/assets/javascripts/jquery.ui.effect-scale.js +320 -0
  81. data/vendor/assets/javascripts/jquery.ui.effect-shake.js +76 -0
  82. data/vendor/assets/javascripts/jquery.ui.effect-slide.js +66 -0
  83. data/vendor/assets/javascripts/jquery.ui.effect-transfer.js +49 -0
  84. data/vendor/assets/javascripts/jquery.ui.effect.all.js +14 -0
  85. data/vendor/assets/javascripts/jquery.ui.effect.js +1276 -0
  86. data/vendor/assets/javascripts/jquery.ui.menu.js +614 -0
  87. data/vendor/assets/javascripts/jquery.ui.mouse.js +22 -20
  88. data/vendor/assets/javascripts/jquery.ui.position.js +367 -158
  89. data/vendor/assets/javascripts/jquery.ui.progressbar.js +10 -14
  90. data/vendor/assets/javascripts/jquery.ui.resizable.js +143 -149
  91. data/vendor/assets/javascripts/jquery.ui.selectable.js +22 -28
  92. data/vendor/assets/javascripts/jquery.ui.slider.js +88 -106
  93. data/vendor/assets/javascripts/jquery.ui.sortable.js +97 -95
  94. data/vendor/assets/javascripts/jquery.ui.spinner.js +482 -0
  95. data/vendor/assets/javascripts/jquery.ui.tabs.js +1189 -580
  96. data/vendor/assets/javascripts/jquery.ui.tooltip.js +402 -0
  97. data/vendor/assets/javascripts/jquery.ui.widget.js +373 -117
  98. data/vendor/assets/stylesheets/jquery.ui.accordion.css.erb +10 -13
  99. data/vendor/assets/stylesheets/jquery.ui.all.css.erb +4 -3
  100. data/vendor/assets/stylesheets/jquery.ui.autocomplete.css.erb +10 -44
  101. data/vendor/assets/stylesheets/jquery.ui.base.css.erb +7 -3
  102. data/vendor/assets/stylesheets/jquery.ui.button.css.erb +6 -4
  103. data/vendor/assets/stylesheets/jquery.ui.core.css.erb +5 -4
  104. data/vendor/assets/stylesheets/jquery.ui.datepicker.css.erb +4 -3
  105. data/vendor/assets/stylesheets/jquery.ui.dialog.css.erb +6 -5
  106. data/vendor/assets/stylesheets/jquery.ui.menu.css.erb +34 -0
  107. data/vendor/assets/stylesheets/jquery.ui.progressbar.css.erb +4 -3
  108. data/vendor/assets/stylesheets/jquery.ui.resizable.css.erb +4 -3
  109. data/vendor/assets/stylesheets/jquery.ui.selectable.css.erb +4 -3
  110. data/vendor/assets/stylesheets/jquery.ui.slider.css.erb +4 -3
  111. data/vendor/assets/stylesheets/jquery.ui.spinner.css.erb +27 -0
  112. data/vendor/assets/stylesheets/jquery.ui.tabs.css.erb +8 -8
  113. data/vendor/assets/stylesheets/jquery.ui.theme.css.erb +8 -7
  114. data/vendor/assets/stylesheets/jquery.ui.tooltip.css.erb +25 -0
  115. metadata +24 -19
  116. data/dependencies.js +0 -31
  117. data/vendor/assets/javascripts/jquery.effects.all.js +0 -14
  118. data/vendor/assets/javascripts/jquery.effects.blind.js +0 -51
  119. data/vendor/assets/javascripts/jquery.effects.bounce.js +0 -80
  120. data/vendor/assets/javascripts/jquery.effects.clip.js +0 -56
  121. data/vendor/assets/javascripts/jquery.effects.core.js +0 -612
  122. data/vendor/assets/javascripts/jquery.effects.drop.js +0 -52
  123. data/vendor/assets/javascripts/jquery.effects.explode.js +0 -81
  124. data/vendor/assets/javascripts/jquery.effects.fade.js +0 -34
  125. data/vendor/assets/javascripts/jquery.effects.fold.js +0 -58
  126. data/vendor/assets/javascripts/jquery.effects.highlight.js +0 -52
  127. data/vendor/assets/javascripts/jquery.effects.pulsate.js +0 -53
  128. data/vendor/assets/javascripts/jquery.effects.scale.js +0 -180
  129. data/vendor/assets/javascripts/jquery.effects.shake.js +0 -59
  130. data/vendor/assets/javascripts/jquery.effects.slide.js +0 -52
  131. data/vendor/assets/javascripts/jquery.effects.transfer.js +0 -47
@@ -0,0 +1,614 @@
1
+ //= require jquery.ui.core
2
+ //= require jquery.ui.widget
3
+ //= require jquery.ui.position
4
+
5
+ /*!
6
+ * jQuery UI Menu 1.9.2
7
+ * http://jqueryui.com
8
+ *
9
+ * Copyright 2012 jQuery Foundation and other contributors
10
+ * Released under the MIT license.
11
+ * http://jquery.org/license
12
+ *
13
+ * http://api.jqueryui.com/menu/
14
+ *
15
+ * Depends:
16
+ * jquery.ui.core.js
17
+ * jquery.ui.widget.js
18
+ * jquery.ui.position.js
19
+ */
20
+ (function( $, undefined ) {
21
+
22
+ var mouseHandled = false;
23
+
24
+ $.widget( "ui.menu", {
25
+ version: "1.9.2",
26
+ defaultElement: "<ul>",
27
+ delay: 300,
28
+ options: {
29
+ icons: {
30
+ submenu: "ui-icon-carat-1-e"
31
+ },
32
+ menus: "ul",
33
+ position: {
34
+ my: "left top",
35
+ at: "right top"
36
+ },
37
+ role: "menu",
38
+
39
+ // callbacks
40
+ blur: null,
41
+ focus: null,
42
+ select: null
43
+ },
44
+
45
+ _create: function() {
46
+ this.activeMenu = this.element;
47
+ this.element
48
+ .uniqueId()
49
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
50
+ .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
51
+ .attr({
52
+ role: this.options.role,
53
+ tabIndex: 0
54
+ })
55
+ // need to catch all clicks on disabled menu
56
+ // not possible through _on
57
+ .bind( "click" + this.eventNamespace, $.proxy(function( event ) {
58
+ if ( this.options.disabled ) {
59
+ event.preventDefault();
60
+ }
61
+ }, this ));
62
+
63
+ if ( this.options.disabled ) {
64
+ this.element
65
+ .addClass( "ui-state-disabled" )
66
+ .attr( "aria-disabled", "true" );
67
+ }
68
+
69
+ this._on({
70
+ // Prevent focus from sticking to links inside menu after clicking
71
+ // them (focus should always stay on UL during navigation).
72
+ "mousedown .ui-menu-item > a": function( event ) {
73
+ event.preventDefault();
74
+ },
75
+ "click .ui-state-disabled > a": function( event ) {
76
+ event.preventDefault();
77
+ },
78
+ "click .ui-menu-item:has(a)": function( event ) {
79
+ var target = $( event.target ).closest( ".ui-menu-item" );
80
+ if ( !mouseHandled && target.not( ".ui-state-disabled" ).length ) {
81
+ mouseHandled = true;
82
+
83
+ this.select( event );
84
+ // Open submenu on click
85
+ if ( target.has( ".ui-menu" ).length ) {
86
+ this.expand( event );
87
+ } else if ( !this.element.is( ":focus" ) ) {
88
+ // Redirect focus to the menu
89
+ this.element.trigger( "focus", [ true ] );
90
+
91
+ // If the active item is on the top level, let it stay active.
92
+ // Otherwise, blur the active item since it is no longer visible.
93
+ if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
94
+ clearTimeout( this.timer );
95
+ }
96
+ }
97
+ }
98
+ },
99
+ "mouseenter .ui-menu-item": function( event ) {
100
+ var target = $( event.currentTarget );
101
+ // Remove ui-state-active class from siblings of the newly focused menu item
102
+ // to avoid a jump caused by adjacent elements both having a class with a border
103
+ target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" );
104
+ this.focus( event, target );
105
+ },
106
+ mouseleave: "collapseAll",
107
+ "mouseleave .ui-menu": "collapseAll",
108
+ focus: function( event, keepActiveItem ) {
109
+ // If there's already an active item, keep it active
110
+ // If not, activate the first item
111
+ var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 );
112
+
113
+ if ( !keepActiveItem ) {
114
+ this.focus( event, item );
115
+ }
116
+ },
117
+ blur: function( event ) {
118
+ this._delay(function() {
119
+ if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
120
+ this.collapseAll( event );
121
+ }
122
+ });
123
+ },
124
+ keydown: "_keydown"
125
+ });
126
+
127
+ this.refresh();
128
+
129
+ // Clicks outside of a menu collapse any open menus
130
+ this._on( this.document, {
131
+ click: function( event ) {
132
+ if ( !$( event.target ).closest( ".ui-menu" ).length ) {
133
+ this.collapseAll( event );
134
+ }
135
+
136
+ // Reset the mouseHandled flag
137
+ mouseHandled = false;
138
+ }
139
+ });
140
+ },
141
+
142
+ _destroy: function() {
143
+ // Destroy (sub)menus
144
+ this.element
145
+ .removeAttr( "aria-activedescendant" )
146
+ .find( ".ui-menu" ).andSelf()
147
+ .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" )
148
+ .removeAttr( "role" )
149
+ .removeAttr( "tabIndex" )
150
+ .removeAttr( "aria-labelledby" )
151
+ .removeAttr( "aria-expanded" )
152
+ .removeAttr( "aria-hidden" )
153
+ .removeAttr( "aria-disabled" )
154
+ .removeUniqueId()
155
+ .show();
156
+
157
+ // Destroy menu items
158
+ this.element.find( ".ui-menu-item" )
159
+ .removeClass( "ui-menu-item" )
160
+ .removeAttr( "role" )
161
+ .removeAttr( "aria-disabled" )
162
+ .children( "a" )
163
+ .removeUniqueId()
164
+ .removeClass( "ui-corner-all ui-state-hover" )
165
+ .removeAttr( "tabIndex" )
166
+ .removeAttr( "role" )
167
+ .removeAttr( "aria-haspopup" )
168
+ .children().each( function() {
169
+ var elem = $( this );
170
+ if ( elem.data( "ui-menu-submenu-carat" ) ) {
171
+ elem.remove();
172
+ }
173
+ });
174
+
175
+ // Destroy menu dividers
176
+ this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
177
+ },
178
+
179
+ _keydown: function( event ) {
180
+ var match, prev, character, skip, regex,
181
+ preventDefault = true;
182
+
183
+ function escape( value ) {
184
+ return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
185
+ }
186
+
187
+ switch ( event.keyCode ) {
188
+ case $.ui.keyCode.PAGE_UP:
189
+ this.previousPage( event );
190
+ break;
191
+ case $.ui.keyCode.PAGE_DOWN:
192
+ this.nextPage( event );
193
+ break;
194
+ case $.ui.keyCode.HOME:
195
+ this._move( "first", "first", event );
196
+ break;
197
+ case $.ui.keyCode.END:
198
+ this._move( "last", "last", event );
199
+ break;
200
+ case $.ui.keyCode.UP:
201
+ this.previous( event );
202
+ break;
203
+ case $.ui.keyCode.DOWN:
204
+ this.next( event );
205
+ break;
206
+ case $.ui.keyCode.LEFT:
207
+ this.collapse( event );
208
+ break;
209
+ case $.ui.keyCode.RIGHT:
210
+ if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
211
+ this.expand( event );
212
+ }
213
+ break;
214
+ case $.ui.keyCode.ENTER:
215
+ case $.ui.keyCode.SPACE:
216
+ this._activate( event );
217
+ break;
218
+ case $.ui.keyCode.ESCAPE:
219
+ this.collapse( event );
220
+ break;
221
+ default:
222
+ preventDefault = false;
223
+ prev = this.previousFilter || "";
224
+ character = String.fromCharCode( event.keyCode );
225
+ skip = false;
226
+
227
+ clearTimeout( this.filterTimer );
228
+
229
+ if ( character === prev ) {
230
+ skip = true;
231
+ } else {
232
+ character = prev + character;
233
+ }
234
+
235
+ regex = new RegExp( "^" + escape( character ), "i" );
236
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
237
+ return regex.test( $( this ).children( "a" ).text() );
238
+ });
239
+ match = skip && match.index( this.active.next() ) !== -1 ?
240
+ this.active.nextAll( ".ui-menu-item" ) :
241
+ match;
242
+
243
+ // If no matches on the current filter, reset to the last character pressed
244
+ // to move down the menu to the first item that starts with that character
245
+ if ( !match.length ) {
246
+ character = String.fromCharCode( event.keyCode );
247
+ regex = new RegExp( "^" + escape( character ), "i" );
248
+ match = this.activeMenu.children( ".ui-menu-item" ).filter(function() {
249
+ return regex.test( $( this ).children( "a" ).text() );
250
+ });
251
+ }
252
+
253
+ if ( match.length ) {
254
+ this.focus( event, match );
255
+ if ( match.length > 1 ) {
256
+ this.previousFilter = character;
257
+ this.filterTimer = this._delay(function() {
258
+ delete this.previousFilter;
259
+ }, 1000 );
260
+ } else {
261
+ delete this.previousFilter;
262
+ }
263
+ } else {
264
+ delete this.previousFilter;
265
+ }
266
+ }
267
+
268
+ if ( preventDefault ) {
269
+ event.preventDefault();
270
+ }
271
+ },
272
+
273
+ _activate: function( event ) {
274
+ if ( !this.active.is( ".ui-state-disabled" ) ) {
275
+ if ( this.active.children( "a[aria-haspopup='true']" ).length ) {
276
+ this.expand( event );
277
+ } else {
278
+ this.select( event );
279
+ }
280
+ }
281
+ },
282
+
283
+ refresh: function() {
284
+ var menus,
285
+ icon = this.options.icons.submenu,
286
+ submenus = this.element.find( this.options.menus );
287
+
288
+ // Initialize nested menus
289
+ submenus.filter( ":not(.ui-menu)" )
290
+ .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" )
291
+ .hide()
292
+ .attr({
293
+ role: this.options.role,
294
+ "aria-hidden": "true",
295
+ "aria-expanded": "false"
296
+ })
297
+ .each(function() {
298
+ var menu = $( this ),
299
+ item = menu.prev( "a" ),
300
+ submenuCarat = $( "<span>" )
301
+ .addClass( "ui-menu-icon ui-icon " + icon )
302
+ .data( "ui-menu-submenu-carat", true );
303
+
304
+ item
305
+ .attr( "aria-haspopup", "true" )
306
+ .prepend( submenuCarat );
307
+ menu.attr( "aria-labelledby", item.attr( "id" ) );
308
+ });
309
+
310
+ menus = submenus.add( this.element );
311
+
312
+ // Don't refresh list items that are already adapted
313
+ menus.children( ":not(.ui-menu-item):has(a)" )
314
+ .addClass( "ui-menu-item" )
315
+ .attr( "role", "presentation" )
316
+ .children( "a" )
317
+ .uniqueId()
318
+ .addClass( "ui-corner-all" )
319
+ .attr({
320
+ tabIndex: -1,
321
+ role: this._itemRole()
322
+ });
323
+
324
+ // Initialize unlinked menu-items containing spaces and/or dashes only as dividers
325
+ menus.children( ":not(.ui-menu-item)" ).each(function() {
326
+ var item = $( this );
327
+ // hyphen, em dash, en dash
328
+ if ( !/[^\-—–\s]/.test( item.text() ) ) {
329
+ item.addClass( "ui-widget-content ui-menu-divider" );
330
+ }
331
+ });
332
+
333
+ // Add aria-disabled attribute to any disabled menu item
334
+ menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
335
+
336
+ // If the active item has been removed, blur the menu
337
+ if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
338
+ this.blur();
339
+ }
340
+ },
341
+
342
+ _itemRole: function() {
343
+ return {
344
+ menu: "menuitem",
345
+ listbox: "option"
346
+ }[ this.options.role ];
347
+ },
348
+
349
+ focus: function( event, item ) {
350
+ var nested, focused;
351
+ this.blur( event, event && event.type === "focus" );
352
+
353
+ this._scrollIntoView( item );
354
+
355
+ this.active = item.first();
356
+ focused = this.active.children( "a" ).addClass( "ui-state-focus" );
357
+ // Only update aria-activedescendant if there's a role
358
+ // otherwise we assume focus is managed elsewhere
359
+ if ( this.options.role ) {
360
+ this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
361
+ }
362
+
363
+ // Highlight active parent menu item, if any
364
+ this.active
365
+ .parent()
366
+ .closest( ".ui-menu-item" )
367
+ .children( "a:first" )
368
+ .addClass( "ui-state-active" );
369
+
370
+ if ( event && event.type === "keydown" ) {
371
+ this._close();
372
+ } else {
373
+ this.timer = this._delay(function() {
374
+ this._close();
375
+ }, this.delay );
376
+ }
377
+
378
+ nested = item.children( ".ui-menu" );
379
+ if ( nested.length && ( /^mouse/.test( event.type ) ) ) {
380
+ this._startOpening(nested);
381
+ }
382
+ this.activeMenu = item.parent();
383
+
384
+ this._trigger( "focus", event, { item: item } );
385
+ },
386
+
387
+ _scrollIntoView: function( item ) {
388
+ var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
389
+ if ( this._hasScroll() ) {
390
+ borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
391
+ paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
392
+ offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
393
+ scroll = this.activeMenu.scrollTop();
394
+ elementHeight = this.activeMenu.height();
395
+ itemHeight = item.height();
396
+
397
+ if ( offset < 0 ) {
398
+ this.activeMenu.scrollTop( scroll + offset );
399
+ } else if ( offset + itemHeight > elementHeight ) {
400
+ this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
401
+ }
402
+ }
403
+ },
404
+
405
+ blur: function( event, fromFocus ) {
406
+ if ( !fromFocus ) {
407
+ clearTimeout( this.timer );
408
+ }
409
+
410
+ if ( !this.active ) {
411
+ return;
412
+ }
413
+
414
+ this.active.children( "a" ).removeClass( "ui-state-focus" );
415
+ this.active = null;
416
+
417
+ this._trigger( "blur", event, { item: this.active } );
418
+ },
419
+
420
+ _startOpening: function( submenu ) {
421
+ clearTimeout( this.timer );
422
+
423
+ // Don't open if already open fixes a Firefox bug that caused a .5 pixel
424
+ // shift in the submenu position when mousing over the carat icon
425
+ if ( submenu.attr( "aria-hidden" ) !== "true" ) {
426
+ return;
427
+ }
428
+
429
+ this.timer = this._delay(function() {
430
+ this._close();
431
+ this._open( submenu );
432
+ }, this.delay );
433
+ },
434
+
435
+ _open: function( submenu ) {
436
+ var position = $.extend({
437
+ of: this.active
438
+ }, this.options.position );
439
+
440
+ clearTimeout( this.timer );
441
+ this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
442
+ .hide()
443
+ .attr( "aria-hidden", "true" );
444
+
445
+ submenu
446
+ .show()
447
+ .removeAttr( "aria-hidden" )
448
+ .attr( "aria-expanded", "true" )
449
+ .position( position );
450
+ },
451
+
452
+ collapseAll: function( event, all ) {
453
+ clearTimeout( this.timer );
454
+ this.timer = this._delay(function() {
455
+ // If we were passed an event, look for the submenu that contains the event
456
+ var currentMenu = all ? this.element :
457
+ $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
458
+
459
+ // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
460
+ if ( !currentMenu.length ) {
461
+ currentMenu = this.element;
462
+ }
463
+
464
+ this._close( currentMenu );
465
+
466
+ this.blur( event );
467
+ this.activeMenu = currentMenu;
468
+ }, this.delay );
469
+ },
470
+
471
+ // With no arguments, closes the currently active menu - if nothing is active
472
+ // it closes all menus. If passed an argument, it will search for menus BELOW
473
+ _close: function( startMenu ) {
474
+ if ( !startMenu ) {
475
+ startMenu = this.active ? this.active.parent() : this.element;
476
+ }
477
+
478
+ startMenu
479
+ .find( ".ui-menu" )
480
+ .hide()
481
+ .attr( "aria-hidden", "true" )
482
+ .attr( "aria-expanded", "false" )
483
+ .end()
484
+ .find( "a.ui-state-active" )
485
+ .removeClass( "ui-state-active" );
486
+ },
487
+
488
+ collapse: function( event ) {
489
+ var newItem = this.active &&
490
+ this.active.parent().closest( ".ui-menu-item", this.element );
491
+ if ( newItem && newItem.length ) {
492
+ this._close();
493
+ this.focus( event, newItem );
494
+ }
495
+ },
496
+
497
+ expand: function( event ) {
498
+ var newItem = this.active &&
499
+ this.active
500
+ .children( ".ui-menu " )
501
+ .children( ".ui-menu-item" )
502
+ .first();
503
+
504
+ if ( newItem && newItem.length ) {
505
+ this._open( newItem.parent() );
506
+
507
+ // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
508
+ this._delay(function() {
509
+ this.focus( event, newItem );
510
+ });
511
+ }
512
+ },
513
+
514
+ next: function( event ) {
515
+ this._move( "next", "first", event );
516
+ },
517
+
518
+ previous: function( event ) {
519
+ this._move( "prev", "last", event );
520
+ },
521
+
522
+ isFirstItem: function() {
523
+ return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
524
+ },
525
+
526
+ isLastItem: function() {
527
+ return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
528
+ },
529
+
530
+ _move: function( direction, filter, event ) {
531
+ var next;
532
+ if ( this.active ) {
533
+ if ( direction === "first" || direction === "last" ) {
534
+ next = this.active
535
+ [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
536
+ .eq( -1 );
537
+ } else {
538
+ next = this.active
539
+ [ direction + "All" ]( ".ui-menu-item" )
540
+ .eq( 0 );
541
+ }
542
+ }
543
+ if ( !next || !next.length || !this.active ) {
544
+ next = this.activeMenu.children( ".ui-menu-item" )[ filter ]();
545
+ }
546
+
547
+ this.focus( event, next );
548
+ },
549
+
550
+ nextPage: function( event ) {
551
+ var item, base, height;
552
+
553
+ if ( !this.active ) {
554
+ this.next( event );
555
+ return;
556
+ }
557
+ if ( this.isLastItem() ) {
558
+ return;
559
+ }
560
+ if ( this._hasScroll() ) {
561
+ base = this.active.offset().top;
562
+ height = this.element.height();
563
+ this.active.nextAll( ".ui-menu-item" ).each(function() {
564
+ item = $( this );
565
+ return item.offset().top - base - height < 0;
566
+ });
567
+
568
+ this.focus( event, item );
569
+ } else {
570
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" )
571
+ [ !this.active ? "first" : "last" ]() );
572
+ }
573
+ },
574
+
575
+ previousPage: function( event ) {
576
+ var item, base, height;
577
+ if ( !this.active ) {
578
+ this.next( event );
579
+ return;
580
+ }
581
+ if ( this.isFirstItem() ) {
582
+ return;
583
+ }
584
+ if ( this._hasScroll() ) {
585
+ base = this.active.offset().top;
586
+ height = this.element.height();
587
+ this.active.prevAll( ".ui-menu-item" ).each(function() {
588
+ item = $( this );
589
+ return item.offset().top - base + height > 0;
590
+ });
591
+
592
+ this.focus( event, item );
593
+ } else {
594
+ this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() );
595
+ }
596
+ },
597
+
598
+ _hasScroll: function() {
599
+ return this.element.outerHeight() < this.element.prop( "scrollHeight" );
600
+ },
601
+
602
+ select: function( event ) {
603
+ // TODO: It should never be possible to not have an active item at this
604
+ // point, but the tests don't trigger mouseenter before click.
605
+ this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
606
+ var ui = { item: this.active };
607
+ if ( !this.active.has( ".ui-menu" ).length ) {
608
+ this.collapseAll( event, true );
609
+ }
610
+ this._trigger( "select", event, ui );
611
+ }
612
+ });
613
+
614
+ }( jQuery ));