jqueryui-requirejs-rails 0.1.0

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