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