]>
Commit | Line | Data |
---|---|---|
fb26cc93 MR |
1 | /*! jQuery UI - v1.10.4 - 2014-03-08 |
2 | * http://jqueryui.com | |
3 | * Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.position.js, jquery.ui.autocomplete.js, jquery.ui.menu.js | |
4 | * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */ | |
5 | ||
6 | (function( $, undefined ) { | |
7 | ||
8 | var uuid = 0, | |
9 | runiqueId = /^ui-id-\d+$/; | |
10 | ||
11 | // $.ui might exist from components with no dependencies, e.g., $.ui.position | |
12 | $.ui = $.ui || {}; | |
13 | ||
14 | $.extend( $.ui, { | |
15 | version: "1.10.4", | |
16 | ||
17 | keyCode: { | |
18 | BACKSPACE: 8, | |
19 | COMMA: 188, | |
20 | DELETE: 46, | |
21 | DOWN: 40, | |
22 | END: 35, | |
23 | ENTER: 13, | |
24 | ESCAPE: 27, | |
25 | HOME: 36, | |
26 | LEFT: 37, | |
27 | NUMPAD_ADD: 107, | |
28 | NUMPAD_DECIMAL: 110, | |
29 | NUMPAD_DIVIDE: 111, | |
30 | NUMPAD_ENTER: 108, | |
31 | NUMPAD_MULTIPLY: 106, | |
32 | NUMPAD_SUBTRACT: 109, | |
33 | PAGE_DOWN: 34, | |
34 | PAGE_UP: 33, | |
35 | PERIOD: 190, | |
36 | RIGHT: 39, | |
37 | SPACE: 32, | |
38 | TAB: 9, | |
39 | UP: 38 | |
40 | } | |
41 | }); | |
42 | ||
43 | // plugins | |
44 | $.fn.extend({ | |
45 | focus: (function( orig ) { | |
46 | return function( delay, fn ) { | |
47 | return typeof delay === "number" ? | |
48 | this.each(function() { | |
49 | var elem = this; | |
50 | setTimeout(function() { | |
51 | $( elem ).focus(); | |
52 | if ( fn ) { | |
53 | fn.call( elem ); | |
54 | } | |
55 | }, delay ); | |
56 | }) : | |
57 | orig.apply( this, arguments ); | |
58 | }; | |
59 | })( $.fn.focus ), | |
60 | ||
61 | scrollParent: function() { | |
62 | var scrollParent; | |
63 | if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { | |
64 | scrollParent = this.parents().filter(function() { | |
65 | return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); | |
66 | }).eq(0); | |
67 | } else { | |
68 | scrollParent = this.parents().filter(function() { | |
69 | return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); | |
70 | }).eq(0); | |
71 | } | |
72 | ||
73 | return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; | |
74 | }, | |
75 | ||
76 | zIndex: function( zIndex ) { | |
77 | if ( zIndex !== undefined ) { | |
78 | return this.css( "zIndex", zIndex ); | |
79 | } | |
80 | ||
81 | if ( this.length ) { | |
82 | var elem = $( this[ 0 ] ), position, value; | |
83 | while ( elem.length && elem[ 0 ] !== document ) { | |
84 | // Ignore z-index if position is set to a value where z-index is ignored by the browser | |
85 | // This makes behavior of this function consistent across browsers | |
86 | // WebKit always returns auto if the element is positioned | |
87 | position = elem.css( "position" ); | |
88 | if ( position === "absolute" || position === "relative" || position === "fixed" ) { | |
89 | // IE returns 0 when zIndex is not specified | |
90 | // other browsers return a string | |
91 | // we ignore the case of nested elements with an explicit value of 0 | |
92 | // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> | |
93 | value = parseInt( elem.css( "zIndex" ), 10 ); | |
94 | if ( !isNaN( value ) && value !== 0 ) { | |
95 | return value; | |
96 | } | |
97 | } | |
98 | elem = elem.parent(); | |
99 | } | |
100 | } | |
101 | ||
102 | return 0; | |
103 | }, | |
104 | ||
105 | uniqueId: function() { | |
106 | return this.each(function() { | |
107 | if ( !this.id ) { | |
108 | this.id = "ui-id-" + (++uuid); | |
109 | } | |
110 | }); | |
111 | }, | |
112 | ||
113 | removeUniqueId: function() { | |
114 | return this.each(function() { | |
115 | if ( runiqueId.test( this.id ) ) { | |
116 | $( this ).removeAttr( "id" ); | |
117 | } | |
118 | }); | |
119 | } | |
120 | }); | |
121 | ||
122 | // selectors | |
123 | function focusable( element, isTabIndexNotNaN ) { | |
124 | var map, mapName, img, | |
125 | nodeName = element.nodeName.toLowerCase(); | |
126 | if ( "area" === nodeName ) { | |
127 | map = element.parentNode; | |
128 | mapName = map.name; | |
129 | if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { | |
130 | return false; | |
131 | } | |
132 | img = $( "img[usemap=#" + mapName + "]" )[0]; | |
133 | return !!img && visible( img ); | |
134 | } | |
135 | return ( /input|select|textarea|button|object/.test( nodeName ) ? | |
136 | !element.disabled : | |
137 | "a" === nodeName ? | |
138 | element.href || isTabIndexNotNaN : | |
139 | isTabIndexNotNaN) && | |
140 | // the element and all of its ancestors must be visible | |
141 | visible( element ); | |
142 | } | |
143 | ||
144 | function visible( element ) { | |
145 | return $.expr.filters.visible( element ) && | |
146 | !$( element ).parents().addBack().filter(function() { | |
147 | return $.css( this, "visibility" ) === "hidden"; | |
148 | }).length; | |
149 | } | |
150 | ||
151 | $.extend( $.expr[ ":" ], { | |
152 | data: $.expr.createPseudo ? | |
153 | $.expr.createPseudo(function( dataName ) { | |
154 | return function( elem ) { | |
155 | return !!$.data( elem, dataName ); | |
156 | }; | |
157 | }) : | |
158 | // support: jQuery <1.8 | |
159 | function( elem, i, match ) { | |
160 | return !!$.data( elem, match[ 3 ] ); | |
161 | }, | |
162 | ||
163 | focusable: function( element ) { | |
164 | return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); | |
165 | }, | |
166 | ||
167 | tabbable: function( element ) { | |
168 | var tabIndex = $.attr( element, "tabindex" ), | |
169 | isTabIndexNaN = isNaN( tabIndex ); | |
170 | return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); | |
171 | } | |
172 | }); | |
173 | ||
174 | // support: jQuery <1.8 | |
175 | if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { | |
176 | $.each( [ "Width", "Height" ], function( i, name ) { | |
177 | var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], | |
178 | type = name.toLowerCase(), | |
179 | orig = { | |
180 | innerWidth: $.fn.innerWidth, | |
181 | innerHeight: $.fn.innerHeight, | |
182 | outerWidth: $.fn.outerWidth, | |
183 | outerHeight: $.fn.outerHeight | |
184 | }; | |
185 | ||
186 | function reduce( elem, size, border, margin ) { | |
187 | $.each( side, function() { | |
188 | size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; | |
189 | if ( border ) { | |
190 | size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; | |
191 | } | |
192 | if ( margin ) { | |
193 | size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; | |
194 | } | |
195 | }); | |
196 | return size; | |
197 | } | |
198 | ||
199 | $.fn[ "inner" + name ] = function( size ) { | |
200 | if ( size === undefined ) { | |
201 | return orig[ "inner" + name ].call( this ); | |
202 | } | |
203 | ||
204 | return this.each(function() { | |
205 | $( this ).css( type, reduce( this, size ) + "px" ); | |
206 | }); | |
207 | }; | |
208 | ||
209 | $.fn[ "outer" + name] = function( size, margin ) { | |
210 | if ( typeof size !== "number" ) { | |
211 | return orig[ "outer" + name ].call( this, size ); | |
212 | } | |
213 | ||
214 | return this.each(function() { | |
215 | $( this).css( type, reduce( this, size, true, margin ) + "px" ); | |
216 | }); | |
217 | }; | |
218 | }); | |
219 | } | |
220 | ||
221 | // support: jQuery <1.8 | |
222 | if ( !$.fn.addBack ) { | |
223 | $.fn.addBack = function( selector ) { | |
224 | return this.add( selector == null ? | |
225 | this.prevObject : this.prevObject.filter( selector ) | |
226 | ); | |
227 | }; | |
228 | } | |
229 | ||
230 | // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) | |
231 | if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { | |
232 | $.fn.removeData = (function( removeData ) { | |
233 | return function( key ) { | |
234 | if ( arguments.length ) { | |
235 | return removeData.call( this, $.camelCase( key ) ); | |
236 | } else { | |
237 | return removeData.call( this ); | |
238 | } | |
239 | }; | |
240 | })( $.fn.removeData ); | |
241 | } | |
242 | ||
243 | ||
244 | ||
245 | ||
246 | ||
247 | // deprecated | |
248 | $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); | |
249 | ||
250 | $.support.selectstart = "onselectstart" in document.createElement( "div" ); | |
251 | $.fn.extend({ | |
252 | disableSelection: function() { | |
253 | return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + | |
254 | ".ui-disableSelection", function( event ) { | |
255 | event.preventDefault(); | |
256 | }); | |
257 | }, | |
258 | ||
259 | enableSelection: function() { | |
260 | return this.unbind( ".ui-disableSelection" ); | |
261 | } | |
262 | }); | |
263 | ||
264 | $.extend( $.ui, { | |
265 | // $.ui.plugin is deprecated. Use $.widget() extensions instead. | |
266 | plugin: { | |
267 | add: function( module, option, set ) { | |
268 | var i, | |
269 | proto = $.ui[ module ].prototype; | |
270 | for ( i in set ) { | |
271 | proto.plugins[ i ] = proto.plugins[ i ] || []; | |
272 | proto.plugins[ i ].push( [ option, set[ i ] ] ); | |
273 | } | |
274 | }, | |
275 | call: function( instance, name, args ) { | |
276 | var i, | |
277 | set = instance.plugins[ name ]; | |
278 | if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { | |
279 | return; | |
280 | } | |
281 | ||
282 | for ( i = 0; i < set.length; i++ ) { | |
283 | if ( instance.options[ set[ i ][ 0 ] ] ) { | |
284 | set[ i ][ 1 ].apply( instance.element, args ); | |
285 | } | |
286 | } | |
287 | } | |
288 | }, | |
289 | ||
290 | // only used by resizable | |
291 | hasScroll: function( el, a ) { | |
292 | ||
293 | //If overflow is hidden, the element might have extra content, but the user wants to hide it | |
294 | if ( $( el ).css( "overflow" ) === "hidden") { | |
295 | return false; | |
296 | } | |
297 | ||
298 | var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", | |
299 | has = false; | |
300 | ||
301 | if ( el[ scroll ] > 0 ) { | |
302 | return true; | |
303 | } | |
304 | ||
305 | // TODO: determine which cases actually cause this to happen | |
306 | // if the element doesn't have the scroll set, see if it's possible to | |
307 | // set the scroll | |
308 | el[ scroll ] = 1; | |
309 | has = ( el[ scroll ] > 0 ); | |
310 | el[ scroll ] = 0; | |
311 | return has; | |
312 | } | |
313 | }); | |
314 | ||
315 | })( jQuery ); | |
316 | (function( $, undefined ) { | |
317 | ||
318 | var uuid = 0, | |
319 | slice = Array.prototype.slice, | |
320 | _cleanData = $.cleanData; | |
321 | $.cleanData = function( elems ) { | |
322 | for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { | |
323 | try { | |
324 | $( elem ).triggerHandler( "remove" ); | |
325 | // http://bugs.jquery.com/ticket/8235 | |
326 | } catch( e ) {} | |
327 | } | |
328 | _cleanData( elems ); | |
329 | }; | |
330 | ||
331 | $.widget = function( name, base, prototype ) { | |
332 | var fullName, existingConstructor, constructor, basePrototype, | |
333 | // proxiedPrototype allows the provided prototype to remain unmodified | |
334 | // so that it can be used as a mixin for multiple widgets (#8876) | |
335 | proxiedPrototype = {}, | |
336 | namespace = name.split( "." )[ 0 ]; | |
337 | ||
338 | name = name.split( "." )[ 1 ]; | |
339 | fullName = namespace + "-" + name; | |
340 | ||
341 | if ( !prototype ) { | |
342 | prototype = base; | |
343 | base = $.Widget; | |
344 | } | |
345 | ||
346 | // create selector for plugin | |
347 | $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { | |
348 | return !!$.data( elem, fullName ); | |
349 | }; | |
350 | ||
351 | $[ namespace ] = $[ namespace ] || {}; | |
352 | existingConstructor = $[ namespace ][ name ]; | |
353 | constructor = $[ namespace ][ name ] = function( options, element ) { | |
354 | // allow instantiation without "new" keyword | |
355 | if ( !this._createWidget ) { | |
356 | return new constructor( options, element ); | |
357 | } | |
358 | ||
359 | // allow instantiation without initializing for simple inheritance | |
360 | // must use "new" keyword (the code above always passes args) | |
361 | if ( arguments.length ) { | |
362 | this._createWidget( options, element ); | |
363 | } | |
364 | }; | |
365 | // extend with the existing constructor to carry over any static properties | |
366 | $.extend( constructor, existingConstructor, { | |
367 | version: prototype.version, | |
368 | // copy the object used to create the prototype in case we need to | |
369 | // redefine the widget later | |
370 | _proto: $.extend( {}, prototype ), | |
371 | // track widgets that inherit from this widget in case this widget is | |
372 | // redefined after a widget inherits from it | |
373 | _childConstructors: [] | |
374 | }); | |
375 | ||
376 | basePrototype = new base(); | |
377 | // we need to make the options hash a property directly on the new instance | |
378 | // otherwise we'll modify the options hash on the prototype that we're | |
379 | // inheriting from | |
380 | basePrototype.options = $.widget.extend( {}, basePrototype.options ); | |
381 | $.each( prototype, function( prop, value ) { | |
382 | if ( !$.isFunction( value ) ) { | |
383 | proxiedPrototype[ prop ] = value; | |
384 | return; | |
385 | } | |
386 | proxiedPrototype[ prop ] = (function() { | |
387 | var _super = function() { | |
388 | return base.prototype[ prop ].apply( this, arguments ); | |
389 | }, | |
390 | _superApply = function( args ) { | |
391 | return base.prototype[ prop ].apply( this, args ); | |
392 | }; | |
393 | return function() { | |
394 | var __super = this._super, | |
395 | __superApply = this._superApply, | |
396 | returnValue; | |
397 | ||
398 | this._super = _super; | |
399 | this._superApply = _superApply; | |
400 | ||
401 | returnValue = value.apply( this, arguments ); | |
402 | ||
403 | this._super = __super; | |
404 | this._superApply = __superApply; | |
405 | ||
406 | return returnValue; | |
407 | }; | |
408 | })(); | |
409 | }); | |
410 | constructor.prototype = $.widget.extend( basePrototype, { | |
411 | // TODO: remove support for widgetEventPrefix | |
412 | // always use the name + a colon as the prefix, e.g., draggable:start | |
413 | // don't prefix for widgets that aren't DOM-based | |
414 | widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name | |
415 | }, proxiedPrototype, { | |
416 | constructor: constructor, | |
417 | namespace: namespace, | |
418 | widgetName: name, | |
419 | widgetFullName: fullName | |
420 | }); | |
421 | ||
422 | // If this widget is being redefined then we need to find all widgets that | |
423 | // are inheriting from it and redefine all of them so that they inherit from | |
424 | // the new version of this widget. We're essentially trying to replace one | |
425 | // level in the prototype chain. | |
426 | if ( existingConstructor ) { | |
427 | $.each( existingConstructor._childConstructors, function( i, child ) { | |
428 | var childPrototype = child.prototype; | |
429 | ||
430 | // redefine the child widget using the same prototype that was | |
431 | // originally used, but inherit from the new version of the base | |
432 | $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); | |
433 | }); | |
434 | // remove the list of existing child constructors from the old constructor | |
435 | // so the old child constructors can be garbage collected | |
436 | delete existingConstructor._childConstructors; | |
437 | } else { | |
438 | base._childConstructors.push( constructor ); | |
439 | } | |
440 | ||
441 | $.widget.bridge( name, constructor ); | |
442 | }; | |
443 | ||
444 | $.widget.extend = function( target ) { | |
445 | var input = slice.call( arguments, 1 ), | |
446 | inputIndex = 0, | |
447 | inputLength = input.length, | |
448 | key, | |
449 | value; | |
450 | for ( ; inputIndex < inputLength; inputIndex++ ) { | |
451 | for ( key in input[ inputIndex ] ) { | |
452 | value = input[ inputIndex ][ key ]; | |
453 | if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { | |
454 | // Clone objects | |
455 | if ( $.isPlainObject( value ) ) { | |
456 | target[ key ] = $.isPlainObject( target[ key ] ) ? | |
457 | $.widget.extend( {}, target[ key ], value ) : | |
458 | // Don't extend strings, arrays, etc. with objects | |
459 | $.widget.extend( {}, value ); | |
460 | // Copy everything else by reference | |
461 | } else { | |
462 | target[ key ] = value; | |
463 | } | |
464 | } | |
465 | } | |
466 | } | |
467 | return target; | |
468 | }; | |
469 | ||
470 | $.widget.bridge = function( name, object ) { | |
471 | var fullName = object.prototype.widgetFullName || name; | |
472 | $.fn[ name ] = function( options ) { | |
473 | var isMethodCall = typeof options === "string", | |
474 | args = slice.call( arguments, 1 ), | |
475 | returnValue = this; | |
476 | ||
477 | // allow multiple hashes to be passed on init | |
478 | options = !isMethodCall && args.length ? | |
479 | $.widget.extend.apply( null, [ options ].concat(args) ) : | |
480 | options; | |
481 | ||
482 | if ( isMethodCall ) { | |
483 | this.each(function() { | |
484 | var methodValue, | |
485 | instance = $.data( this, fullName ); | |
486 | if ( !instance ) { | |
487 | return $.error( "cannot call methods on " + name + " prior to initialization; " + | |
488 | "attempted to call method '" + options + "'" ); | |
489 | } | |
490 | if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { | |
491 | return $.error( "no such method '" + options + "' for " + name + " widget instance" ); | |
492 | } | |
493 | methodValue = instance[ options ].apply( instance, args ); | |
494 | if ( methodValue !== instance && methodValue !== undefined ) { | |
495 | returnValue = methodValue && methodValue.jquery ? | |
496 | returnValue.pushStack( methodValue.get() ) : | |
497 | methodValue; | |
498 | return false; | |
499 | } | |
500 | }); | |
501 | } else { | |
502 | this.each(function() { | |
503 | var instance = $.data( this, fullName ); | |
504 | if ( instance ) { | |
505 | instance.option( options || {} )._init(); | |
506 | } else { | |
507 | $.data( this, fullName, new object( options, this ) ); | |
508 | } | |
509 | }); | |
510 | } | |
511 | ||
512 | return returnValue; | |
513 | }; | |
514 | }; | |
515 | ||
516 | $.Widget = function( /* options, element */ ) {}; | |
517 | $.Widget._childConstructors = []; | |
518 | ||
519 | $.Widget.prototype = { | |
520 | widgetName: "widget", | |
521 | widgetEventPrefix: "", | |
522 | defaultElement: "<div>", | |
523 | options: { | |
524 | disabled: false, | |
525 | ||
526 | // callbacks | |
527 | create: null | |
528 | }, | |
529 | _createWidget: function( options, element ) { | |
530 | element = $( element || this.defaultElement || this )[ 0 ]; | |
531 | this.element = $( element ); | |
532 | this.uuid = uuid++; | |
533 | this.eventNamespace = "." + this.widgetName + this.uuid; | |
534 | this.options = $.widget.extend( {}, | |
535 | this.options, | |
536 | this._getCreateOptions(), | |
537 | options ); | |
538 | ||
539 | this.bindings = $(); | |
540 | this.hoverable = $(); | |
541 | this.focusable = $(); | |
542 | ||
543 | if ( element !== this ) { | |
544 | $.data( element, this.widgetFullName, this ); | |
545 | this._on( true, this.element, { | |
546 | remove: function( event ) { | |
547 | if ( event.target === element ) { | |
548 | this.destroy(); | |
549 | } | |
550 | } | |
551 | }); | |
552 | this.document = $( element.style ? | |
553 | // element within the document | |
554 | element.ownerDocument : | |
555 | // element is window or document | |
556 | element.document || element ); | |
557 | this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); | |
558 | } | |
559 | ||
560 | this._create(); | |
561 | this._trigger( "create", null, this._getCreateEventData() ); | |
562 | this._init(); | |
563 | }, | |
564 | _getCreateOptions: $.noop, | |
565 | _getCreateEventData: $.noop, | |
566 | _create: $.noop, | |
567 | _init: $.noop, | |
568 | ||
569 | destroy: function() { | |
570 | this._destroy(); | |
571 | // we can probably remove the unbind calls in 2.0 | |
572 | // all event bindings should go through this._on() | |
573 | this.element | |
574 | .unbind( this.eventNamespace ) | |
575 | // 1.9 BC for #7810 | |
576 | // TODO remove dual storage | |
577 | .removeData( this.widgetName ) | |
578 | .removeData( this.widgetFullName ) | |
579 | // support: jquery <1.6.3 | |
580 | // http://bugs.jquery.com/ticket/9413 | |
581 | .removeData( $.camelCase( this.widgetFullName ) ); | |
582 | this.widget() | |
583 | .unbind( this.eventNamespace ) | |
584 | .removeAttr( "aria-disabled" ) | |
585 | .removeClass( | |
586 | this.widgetFullName + "-disabled " + | |
587 | "ui-state-disabled" ); | |
588 | ||
589 | // clean up events and states | |
590 | this.bindings.unbind( this.eventNamespace ); | |
591 | this.hoverable.removeClass( "ui-state-hover" ); | |
592 | this.focusable.removeClass( "ui-state-focus" ); | |
593 | }, | |
594 | _destroy: $.noop, | |
595 | ||
596 | widget: function() { | |
597 | return this.element; | |
598 | }, | |
599 | ||
600 | option: function( key, value ) { | |
601 | var options = key, | |
602 | parts, | |
603 | curOption, | |
604 | i; | |
605 | ||
606 | if ( arguments.length === 0 ) { | |
607 | // don't return a reference to the internal hash | |
608 | return $.widget.extend( {}, this.options ); | |
609 | } | |
610 | ||
611 | if ( typeof key === "string" ) { | |
612 | // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } | |
613 | options = {}; | |
614 | parts = key.split( "." ); | |
615 | key = parts.shift(); | |
616 | if ( parts.length ) { | |
617 | curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); | |
618 | for ( i = 0; i < parts.length - 1; i++ ) { | |
619 | curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; | |
620 | curOption = curOption[ parts[ i ] ]; | |
621 | } | |
622 | key = parts.pop(); | |
623 | if ( arguments.length === 1 ) { | |
624 | return curOption[ key ] === undefined ? null : curOption[ key ]; | |
625 | } | |
626 | curOption[ key ] = value; | |
627 | } else { | |
628 | if ( arguments.length === 1 ) { | |
629 | return this.options[ key ] === undefined ? null : this.options[ key ]; | |
630 | } | |
631 | options[ key ] = value; | |
632 | } | |
633 | } | |
634 | ||
635 | this._setOptions( options ); | |
636 | ||
637 | return this; | |
638 | }, | |
639 | _setOptions: function( options ) { | |
640 | var key; | |
641 | ||
642 | for ( key in options ) { | |
643 | this._setOption( key, options[ key ] ); | |
644 | } | |
645 | ||
646 | return this; | |
647 | }, | |
648 | _setOption: function( key, value ) { | |
649 | this.options[ key ] = value; | |
650 | ||
651 | if ( key === "disabled" ) { | |
652 | this.widget() | |
653 | .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) | |
654 | .attr( "aria-disabled", value ); | |
655 | this.hoverable.removeClass( "ui-state-hover" ); | |
656 | this.focusable.removeClass( "ui-state-focus" ); | |
657 | } | |
658 | ||
659 | return this; | |
660 | }, | |
661 | ||
662 | enable: function() { | |
663 | return this._setOption( "disabled", false ); | |
664 | }, | |
665 | disable: function() { | |
666 | return this._setOption( "disabled", true ); | |
667 | }, | |
668 | ||
669 | _on: function( suppressDisabledCheck, element, handlers ) { | |
670 | var delegateElement, | |
671 | instance = this; | |
672 | ||
673 | // no suppressDisabledCheck flag, shuffle arguments | |
674 | if ( typeof suppressDisabledCheck !== "boolean" ) { | |
675 | handlers = element; | |
676 | element = suppressDisabledCheck; | |
677 | suppressDisabledCheck = false; | |
678 | } | |
679 | ||
680 | // no element argument, shuffle and use this.element | |
681 | if ( !handlers ) { | |
682 | handlers = element; | |
683 | element = this.element; | |
684 | delegateElement = this.widget(); | |
685 | } else { | |
686 | // accept selectors, DOM elements | |
687 | element = delegateElement = $( element ); | |
688 | this.bindings = this.bindings.add( element ); | |
689 | } | |
690 | ||
691 | $.each( handlers, function( event, handler ) { | |
692 | function handlerProxy() { | |
693 | // allow widgets to customize the disabled handling | |
694 | // - disabled as an array instead of boolean | |
695 | // - disabled class as method for disabling individual parts | |
696 | if ( !suppressDisabledCheck && | |
697 | ( instance.options.disabled === true || | |
698 | $( this ).hasClass( "ui-state-disabled" ) ) ) { | |
699 | return; | |
700 | } | |
701 | return ( typeof handler === "string" ? instance[ handler ] : handler ) | |
702 | .apply( instance, arguments ); | |
703 | } | |
704 | ||
705 | // copy the guid so direct unbinding works | |
706 | if ( typeof handler !== "string" ) { | |
707 | handlerProxy.guid = handler.guid = | |
708 | handler.guid || handlerProxy.guid || $.guid++; | |
709 | } | |
710 | ||
711 | var match = event.match( /^(\w+)\s*(.*)$/ ), | |
712 | eventName = match[1] + instance.eventNamespace, | |
713 | selector = match[2]; | |
714 | if ( selector ) { | |
715 | delegateElement.delegate( selector, eventName, handlerProxy ); | |
716 | } else { | |
717 | element.bind( eventName, handlerProxy ); | |
718 | } | |
719 | }); | |
720 | }, | |
721 | ||
722 | _off: function( element, eventName ) { | |
723 | eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; | |
724 | element.unbind( eventName ).undelegate( eventName ); | |
725 | }, | |
726 | ||
727 | _delay: function( handler, delay ) { | |
728 | function handlerProxy() { | |
729 | return ( typeof handler === "string" ? instance[ handler ] : handler ) | |
730 | .apply( instance, arguments ); | |
731 | } | |
732 | var instance = this; | |
733 | return setTimeout( handlerProxy, delay || 0 ); | |
734 | }, | |
735 | ||
736 | _hoverable: function( element ) { | |
737 | this.hoverable = this.hoverable.add( element ); | |
738 | this._on( element, { | |
739 | mouseenter: function( event ) { | |
740 | $( event.currentTarget ).addClass( "ui-state-hover" ); | |
741 | }, | |
742 | mouseleave: function( event ) { | |
743 | $( event.currentTarget ).removeClass( "ui-state-hover" ); | |
744 | } | |
745 | }); | |
746 | }, | |
747 | ||
748 | _focusable: function( element ) { | |
749 | this.focusable = this.focusable.add( element ); | |
750 | this._on( element, { | |
751 | focusin: function( event ) { | |
752 | $( event.currentTarget ).addClass( "ui-state-focus" ); | |
753 | }, | |
754 | focusout: function( event ) { | |
755 | $( event.currentTarget ).removeClass( "ui-state-focus" ); | |
756 | } | |
757 | }); | |
758 | }, | |
759 | ||
760 | _trigger: function( type, event, data ) { | |
761 | var prop, orig, | |
762 | callback = this.options[ type ]; | |
763 | ||
764 | data = data || {}; | |
765 | event = $.Event( event ); | |
766 | event.type = ( type === this.widgetEventPrefix ? | |
767 | type : | |
768 | this.widgetEventPrefix + type ).toLowerCase(); | |
769 | // the original event may come from any element | |
770 | // so we need to reset the target on the new event | |
771 | event.target = this.element[ 0 ]; | |
772 | ||
773 | // copy original event properties over to the new event | |
774 | orig = event.originalEvent; | |
775 | if ( orig ) { | |
776 | for ( prop in orig ) { | |
777 | if ( !( prop in event ) ) { | |
778 | event[ prop ] = orig[ prop ]; | |
779 | } | |
780 | } | |
781 | } | |
782 | ||
783 | this.element.trigger( event, data ); | |
784 | return !( $.isFunction( callback ) && | |
785 | callback.apply( this.element[0], [ event ].concat( data ) ) === false || | |
786 | event.isDefaultPrevented() ); | |
787 | } | |
788 | }; | |
789 | ||
790 | $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { | |
791 | $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { | |
792 | if ( typeof options === "string" ) { | |
793 | options = { effect: options }; | |
794 | } | |
795 | var hasOptions, | |
796 | effectName = !options ? | |
797 | method : | |
798 | options === true || typeof options === "number" ? | |
799 | defaultEffect : | |
800 | options.effect || defaultEffect; | |
801 | options = options || {}; | |
802 | if ( typeof options === "number" ) { | |
803 | options = { duration: options }; | |
804 | } | |
805 | hasOptions = !$.isEmptyObject( options ); | |
806 | options.complete = callback; | |
807 | if ( options.delay ) { | |
808 | element.delay( options.delay ); | |
809 | } | |
810 | if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { | |
811 | element[ method ]( options ); | |
812 | } else if ( effectName !== method && element[ effectName ] ) { | |
813 | element[ effectName ]( options.duration, options.easing, callback ); | |
814 | } else { | |
815 | element.queue(function( next ) { | |
816 | $( this )[ method ](); | |
817 | if ( callback ) { | |
818 | callback.call( element[ 0 ] ); | |
819 | } | |
820 | next(); | |
821 | }); | |
822 | } | |
823 | }; | |
824 | }); | |
825 | ||
826 | })( jQuery ); | |
827 | (function( $, undefined ) { | |
828 | ||
829 | $.ui = $.ui || {}; | |
830 | ||
831 | var cachedScrollbarWidth, | |
832 | max = Math.max, | |
833 | abs = Math.abs, | |
834 | round = Math.round, | |
835 | rhorizontal = /left|center|right/, | |
836 | rvertical = /top|center|bottom/, | |
837 | roffset = /[\+\-]\d+(\.[\d]+)?%?/, | |
838 | rposition = /^\w+/, | |
839 | rpercent = /%$/, | |
840 | _position = $.fn.position; | |
841 | ||
842 | function getOffsets( offsets, width, height ) { | |
843 | return [ | |
844 | parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), | |
845 | parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) | |
846 | ]; | |
847 | } | |
848 | ||
849 | function parseCss( element, property ) { | |
850 | return parseInt( $.css( element, property ), 10 ) || 0; | |
851 | } | |
852 | ||
853 | function getDimensions( elem ) { | |
854 | var raw = elem[0]; | |
855 | if ( raw.nodeType === 9 ) { | |
856 | return { | |
857 | width: elem.width(), | |
858 | height: elem.height(), | |
859 | offset: { top: 0, left: 0 } | |
860 | }; | |
861 | } | |
862 | if ( $.isWindow( raw ) ) { | |
863 | return { | |
864 | width: elem.width(), | |
865 | height: elem.height(), | |
866 | offset: { top: elem.scrollTop(), left: elem.scrollLeft() } | |
867 | }; | |
868 | } | |
869 | if ( raw.preventDefault ) { | |
870 | return { | |
871 | width: 0, | |
872 | height: 0, | |
873 | offset: { top: raw.pageY, left: raw.pageX } | |
874 | }; | |
875 | } | |
876 | return { | |
877 | width: elem.outerWidth(), | |
878 | height: elem.outerHeight(), | |
879 | offset: elem.offset() | |
880 | }; | |
881 | } | |
882 | ||
883 | $.position = { | |
884 | scrollbarWidth: function() { | |
885 | if ( cachedScrollbarWidth !== undefined ) { | |
886 | return cachedScrollbarWidth; | |
887 | } | |
888 | var w1, w2, | |
889 | div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), | |
890 | innerDiv = div.children()[0]; | |
891 | ||
892 | $( "body" ).append( div ); | |
893 | w1 = innerDiv.offsetWidth; | |
894 | div.css( "overflow", "scroll" ); | |
895 | ||
896 | w2 = innerDiv.offsetWidth; | |
897 | ||
898 | if ( w1 === w2 ) { | |
899 | w2 = div[0].clientWidth; | |
900 | } | |
901 | ||
902 | div.remove(); | |
903 | ||
904 | return (cachedScrollbarWidth = w1 - w2); | |
905 | }, | |
906 | getScrollInfo: function( within ) { | |
907 | var overflowX = within.isWindow || within.isDocument ? "" : | |
908 | within.element.css( "overflow-x" ), | |
909 | overflowY = within.isWindow || within.isDocument ? "" : | |
910 | within.element.css( "overflow-y" ), | |
911 | hasOverflowX = overflowX === "scroll" || | |
912 | ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), | |
913 | hasOverflowY = overflowY === "scroll" || | |
914 | ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); | |
915 | return { | |
916 | width: hasOverflowY ? $.position.scrollbarWidth() : 0, | |
917 | height: hasOverflowX ? $.position.scrollbarWidth() : 0 | |
918 | }; | |
919 | }, | |
920 | getWithinInfo: function( element ) { | |
921 | var withinElement = $( element || window ), | |
922 | isWindow = $.isWindow( withinElement[0] ), | |
923 | isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; | |
924 | return { | |
925 | element: withinElement, | |
926 | isWindow: isWindow, | |
927 | isDocument: isDocument, | |
928 | offset: withinElement.offset() || { left: 0, top: 0 }, | |
929 | scrollLeft: withinElement.scrollLeft(), | |
930 | scrollTop: withinElement.scrollTop(), | |
931 | width: isWindow ? withinElement.width() : withinElement.outerWidth(), | |
932 | height: isWindow ? withinElement.height() : withinElement.outerHeight() | |
933 | }; | |
934 | } | |
935 | }; | |
936 | ||
937 | $.fn.position = function( options ) { | |
938 | if ( !options || !options.of ) { | |
939 | return _position.apply( this, arguments ); | |
940 | } | |
941 | ||
942 | // make a copy, we don't want to modify arguments | |
943 | options = $.extend( {}, options ); | |
944 | ||
945 | var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, | |
946 | target = $( options.of ), | |
947 | within = $.position.getWithinInfo( options.within ), | |
948 | scrollInfo = $.position.getScrollInfo( within ), | |
949 | collision = ( options.collision || "flip" ).split( " " ), | |
950 | offsets = {}; | |
951 | ||
952 | dimensions = getDimensions( target ); | |
953 | if ( target[0].preventDefault ) { | |
954 | // force left top to allow flipping | |
955 | options.at = "left top"; | |
956 | } | |
957 | targetWidth = dimensions.width; | |
958 | targetHeight = dimensions.height; | |
959 | targetOffset = dimensions.offset; | |
960 | // clone to reuse original targetOffset later | |
961 | basePosition = $.extend( {}, targetOffset ); | |
962 | ||
963 | // force my and at to have valid horizontal and vertical positions | |
964 | // if a value is missing or invalid, it will be converted to center | |
965 | $.each( [ "my", "at" ], function() { | |
966 | var pos = ( options[ this ] || "" ).split( " " ), | |
967 | horizontalOffset, | |
968 | verticalOffset; | |
969 | ||
970 | if ( pos.length === 1) { | |
971 | pos = rhorizontal.test( pos[ 0 ] ) ? | |
972 | pos.concat( [ "center" ] ) : | |
973 | rvertical.test( pos[ 0 ] ) ? | |
974 | [ "center" ].concat( pos ) : | |
975 | [ "center", "center" ]; | |
976 | } | |
977 | pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; | |
978 | pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; | |
979 | ||
980 | // calculate offsets | |
981 | horizontalOffset = roffset.exec( pos[ 0 ] ); | |
982 | verticalOffset = roffset.exec( pos[ 1 ] ); | |
983 | offsets[ this ] = [ | |
984 | horizontalOffset ? horizontalOffset[ 0 ] : 0, | |
985 | verticalOffset ? verticalOffset[ 0 ] : 0 | |
986 | ]; | |
987 | ||
988 | // reduce to just the positions without the offsets | |
989 | options[ this ] = [ | |
990 | rposition.exec( pos[ 0 ] )[ 0 ], | |
991 | rposition.exec( pos[ 1 ] )[ 0 ] | |
992 | ]; | |
993 | }); | |
994 | ||
995 | // normalize collision option | |
996 | if ( collision.length === 1 ) { | |
997 | collision[ 1 ] = collision[ 0 ]; | |
998 | } | |
999 | ||
1000 | if ( options.at[ 0 ] === "right" ) { | |
1001 | basePosition.left += targetWidth; | |
1002 | } else if ( options.at[ 0 ] === "center" ) { | |
1003 | basePosition.left += targetWidth / 2; | |
1004 | } | |
1005 | ||
1006 | if ( options.at[ 1 ] === "bottom" ) { | |
1007 | basePosition.top += targetHeight; | |
1008 | } else if ( options.at[ 1 ] === "center" ) { | |
1009 | basePosition.top += targetHeight / 2; | |
1010 | } | |
1011 | ||
1012 | atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); | |
1013 | basePosition.left += atOffset[ 0 ]; | |
1014 | basePosition.top += atOffset[ 1 ]; | |
1015 | ||
1016 | return this.each(function() { | |
1017 | var collisionPosition, using, | |
1018 | elem = $( this ), | |
1019 | elemWidth = elem.outerWidth(), | |
1020 | elemHeight = elem.outerHeight(), | |
1021 | marginLeft = parseCss( this, "marginLeft" ), | |
1022 | marginTop = parseCss( this, "marginTop" ), | |
1023 | collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, | |
1024 | collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, | |
1025 | position = $.extend( {}, basePosition ), | |
1026 | myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); | |
1027 | ||
1028 | if ( options.my[ 0 ] === "right" ) { | |
1029 | position.left -= elemWidth; | |
1030 | } else if ( options.my[ 0 ] === "center" ) { | |
1031 | position.left -= elemWidth / 2; | |
1032 | } | |
1033 | ||
1034 | if ( options.my[ 1 ] === "bottom" ) { | |
1035 | position.top -= elemHeight; | |
1036 | } else if ( options.my[ 1 ] === "center" ) { | |
1037 | position.top -= elemHeight / 2; | |
1038 | } | |
1039 | ||
1040 | position.left += myOffset[ 0 ]; | |
1041 | position.top += myOffset[ 1 ]; | |
1042 | ||
1043 | // if the browser doesn't support fractions, then round for consistent results | |
1044 | if ( !$.support.offsetFractions ) { | |
1045 | position.left = round( position.left ); | |
1046 | position.top = round( position.top ); | |
1047 | } | |
1048 | ||
1049 | collisionPosition = { | |
1050 | marginLeft: marginLeft, | |
1051 | marginTop: marginTop | |
1052 | }; | |
1053 | ||
1054 | $.each( [ "left", "top" ], function( i, dir ) { | |
1055 | if ( $.ui.position[ collision[ i ] ] ) { | |
1056 | $.ui.position[ collision[ i ] ][ dir ]( position, { | |
1057 | targetWidth: targetWidth, | |
1058 | targetHeight: targetHeight, | |
1059 | elemWidth: elemWidth, | |
1060 | elemHeight: elemHeight, | |
1061 | collisionPosition: collisionPosition, | |
1062 | collisionWidth: collisionWidth, | |
1063 | collisionHeight: collisionHeight, | |
1064 | offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], | |
1065 | my: options.my, | |
1066 | at: options.at, | |
1067 | within: within, | |
1068 | elem : elem | |
1069 | }); | |
1070 | } | |
1071 | }); | |
1072 | ||
1073 | if ( options.using ) { | |
1074 | // adds feedback as second argument to using callback, if present | |
1075 | using = function( props ) { | |
1076 | var left = targetOffset.left - position.left, | |
1077 | right = left + targetWidth - elemWidth, | |
1078 | top = targetOffset.top - position.top, | |
1079 | bottom = top + targetHeight - elemHeight, | |
1080 | feedback = { | |
1081 | target: { | |
1082 | element: target, | |
1083 | left: targetOffset.left, | |
1084 | top: targetOffset.top, | |
1085 | width: targetWidth, | |
1086 | height: targetHeight | |
1087 | }, | |
1088 | element: { | |
1089 | element: elem, | |
1090 | left: position.left, | |
1091 | top: position.top, | |
1092 | width: elemWidth, | |
1093 | height: elemHeight | |
1094 | }, | |
1095 | horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", | |
1096 | vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" | |
1097 | }; | |
1098 | if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { | |
1099 | feedback.horizontal = "center"; | |
1100 | } | |
1101 | if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { | |
1102 | feedback.vertical = "middle"; | |
1103 | } | |
1104 | if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { | |
1105 | feedback.important = "horizontal"; | |
1106 | } else { | |
1107 | feedback.important = "vertical"; | |
1108 | } | |
1109 | options.using.call( this, props, feedback ); | |
1110 | }; | |
1111 | } | |
1112 | ||
1113 | elem.offset( $.extend( position, { using: using } ) ); | |
1114 | }); | |
1115 | }; | |
1116 | ||
1117 | $.ui.position = { | |
1118 | fit: { | |
1119 | left: function( position, data ) { | |
1120 | var within = data.within, | |
1121 | withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, | |
1122 | outerWidth = within.width, | |
1123 | collisionPosLeft = position.left - data.collisionPosition.marginLeft, | |
1124 | overLeft = withinOffset - collisionPosLeft, | |
1125 | overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, | |
1126 | newOverRight; | |
1127 | ||
1128 | // element is wider than within | |
1129 | if ( data.collisionWidth > outerWidth ) { | |
1130 | // element is initially over the left side of within | |
1131 | if ( overLeft > 0 && overRight <= 0 ) { | |
1132 | newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; | |
1133 | position.left += overLeft - newOverRight; | |
1134 | // element is initially over right side of within | |
1135 | } else if ( overRight > 0 && overLeft <= 0 ) { | |
1136 | position.left = withinOffset; | |
1137 | // element is initially over both left and right sides of within | |
1138 | } else { | |
1139 | if ( overLeft > overRight ) { | |
1140 | position.left = withinOffset + outerWidth - data.collisionWidth; | |
1141 | } else { | |
1142 | position.left = withinOffset; | |
1143 | } | |
1144 | } | |
1145 | // too far left -> align with left edge | |
1146 | } else if ( overLeft > 0 ) { | |
1147 | position.left += overLeft; | |
1148 | // too far right -> align with right edge | |
1149 | } else if ( overRight > 0 ) { | |
1150 | position.left -= overRight; | |
1151 | // adjust based on position and margin | |
1152 | } else { | |
1153 | position.left = max( position.left - collisionPosLeft, position.left ); | |
1154 | } | |
1155 | }, | |
1156 | top: function( position, data ) { | |
1157 | var within = data.within, | |
1158 | withinOffset = within.isWindow ? within.scrollTop : within.offset.top, | |
1159 | outerHeight = data.within.height, | |
1160 | collisionPosTop = position.top - data.collisionPosition.marginTop, | |
1161 | overTop = withinOffset - collisionPosTop, | |
1162 | overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, | |
1163 | newOverBottom; | |
1164 | ||
1165 | // element is taller than within | |
1166 | if ( data.collisionHeight > outerHeight ) { | |
1167 | // element is initially over the top of within | |
1168 | if ( overTop > 0 && overBottom <= 0 ) { | |
1169 | newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; | |
1170 | position.top += overTop - newOverBottom; | |
1171 | // element is initially over bottom of within | |
1172 | } else if ( overBottom > 0 && overTop <= 0 ) { | |
1173 | position.top = withinOffset; | |
1174 | // element is initially over both top and bottom of within | |
1175 | } else { | |
1176 | if ( overTop > overBottom ) { | |
1177 | position.top = withinOffset + outerHeight - data.collisionHeight; | |
1178 | } else { | |
1179 | position.top = withinOffset; | |
1180 | } | |
1181 | } | |
1182 | // too far up -> align with top | |
1183 | } else if ( overTop > 0 ) { | |
1184 | position.top += overTop; | |
1185 | // too far down -> align with bottom edge | |
1186 | } else if ( overBottom > 0 ) { | |
1187 | position.top -= overBottom; | |
1188 | // adjust based on position and margin | |
1189 | } else { | |
1190 | position.top = max( position.top - collisionPosTop, position.top ); | |
1191 | } | |
1192 | } | |
1193 | }, | |
1194 | flip: { | |
1195 | left: function( position, data ) { | |
1196 | var within = data.within, | |
1197 | withinOffset = within.offset.left + within.scrollLeft, | |
1198 | outerWidth = within.width, | |
1199 | offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, | |
1200 | collisionPosLeft = position.left - data.collisionPosition.marginLeft, | |
1201 | overLeft = collisionPosLeft - offsetLeft, | |
1202 | overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, | |
1203 | myOffset = data.my[ 0 ] === "left" ? | |
1204 | -data.elemWidth : | |
1205 | data.my[ 0 ] === "right" ? | |
1206 | data.elemWidth : | |
1207 | 0, | |
1208 | atOffset = data.at[ 0 ] === "left" ? | |
1209 | data.targetWidth : | |
1210 | data.at[ 0 ] === "right" ? | |
1211 | -data.targetWidth : | |
1212 | 0, | |
1213 | offset = -2 * data.offset[ 0 ], | |
1214 | newOverRight, | |
1215 | newOverLeft; | |
1216 | ||
1217 | if ( overLeft < 0 ) { | |
1218 | newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; | |
1219 | if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { | |
1220 | position.left += myOffset + atOffset + offset; | |
1221 | } | |
1222 | } | |
1223 | else if ( overRight > 0 ) { | |
1224 | newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; | |
1225 | if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { | |
1226 | position.left += myOffset + atOffset + offset; | |
1227 | } | |
1228 | } | |
1229 | }, | |
1230 | top: function( position, data ) { | |
1231 | var within = data.within, | |
1232 | withinOffset = within.offset.top + within.scrollTop, | |
1233 | outerHeight = within.height, | |
1234 | offsetTop = within.isWindow ? within.scrollTop : within.offset.top, | |
1235 | collisionPosTop = position.top - data.collisionPosition.marginTop, | |
1236 | overTop = collisionPosTop - offsetTop, | |
1237 | overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, | |
1238 | top = data.my[ 1 ] === "top", | |
1239 | myOffset = top ? | |
1240 | -data.elemHeight : | |
1241 | data.my[ 1 ] === "bottom" ? | |
1242 | data.elemHeight : | |
1243 | 0, | |
1244 | atOffset = data.at[ 1 ] === "top" ? | |
1245 | data.targetHeight : | |
1246 | data.at[ 1 ] === "bottom" ? | |
1247 | -data.targetHeight : | |
1248 | 0, | |
1249 | offset = -2 * data.offset[ 1 ], | |
1250 | newOverTop, | |
1251 | newOverBottom; | |
1252 | if ( overTop < 0 ) { | |
1253 | newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; | |
1254 | if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { | |
1255 | position.top += myOffset + atOffset + offset; | |
1256 | } | |
1257 | } | |
1258 | else if ( overBottom > 0 ) { | |
1259 | newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; | |
1260 | if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { | |
1261 | position.top += myOffset + atOffset + offset; | |
1262 | } | |
1263 | } | |
1264 | } | |
1265 | }, | |
1266 | flipfit: { | |
1267 | left: function() { | |
1268 | $.ui.position.flip.left.apply( this, arguments ); | |
1269 | $.ui.position.fit.left.apply( this, arguments ); | |
1270 | }, | |
1271 | top: function() { | |
1272 | $.ui.position.flip.top.apply( this, arguments ); | |
1273 | $.ui.position.fit.top.apply( this, arguments ); | |
1274 | } | |
1275 | } | |
1276 | }; | |
1277 | ||
1278 | // fraction support test | |
1279 | (function () { | |
1280 | var testElement, testElementParent, testElementStyle, offsetLeft, i, | |
1281 | body = document.getElementsByTagName( "body" )[ 0 ], | |
1282 | div = document.createElement( "div" ); | |
1283 | ||
1284 | //Create a "fake body" for testing based on method used in jQuery.support | |
1285 | testElement = document.createElement( body ? "div" : "body" ); | |
1286 | testElementStyle = { | |
1287 | visibility: "hidden", | |
1288 | width: 0, | |
1289 | height: 0, | |
1290 | border: 0, | |
1291 | margin: 0, | |
1292 | background: "none" | |
1293 | }; | |
1294 | if ( body ) { | |
1295 | $.extend( testElementStyle, { | |
1296 | position: "absolute", | |
1297 | left: "-1000px", | |
1298 | top: "-1000px" | |
1299 | }); | |
1300 | } | |
1301 | for ( i in testElementStyle ) { | |
1302 | testElement.style[ i ] = testElementStyle[ i ]; | |
1303 | } | |
1304 | testElement.appendChild( div ); | |
1305 | testElementParent = body || document.documentElement; | |
1306 | testElementParent.insertBefore( testElement, testElementParent.firstChild ); | |
1307 | ||
1308 | div.style.cssText = "position: absolute; left: 10.7432222px;"; | |
1309 | ||
1310 | offsetLeft = $( div ).offset().left; | |
1311 | $.support.offsetFractions = offsetLeft > 10 && offsetLeft < 11; | |
1312 | ||
1313 | testElement.innerHTML = ""; | |
1314 | testElementParent.removeChild( testElement ); | |
1315 | })(); | |
1316 | ||
1317 | }( jQuery ) ); | |
1318 | (function( $, undefined ) { | |
1319 | ||
1320 | $.widget( "ui.autocomplete", { | |
1321 | version: "1.10.4", | |
1322 | defaultElement: "<input>", | |
1323 | options: { | |
1324 | appendTo: null, | |
1325 | autoFocus: false, | |
1326 | delay: 300, | |
1327 | minLength: 1, | |
1328 | position: { | |
1329 | my: "left top", | |
1330 | at: "left bottom", | |
1331 | collision: "none" | |
1332 | }, | |
1333 | source: null, | |
1334 | ||
1335 | // callbacks | |
1336 | change: null, | |
1337 | close: null, | |
1338 | focus: null, | |
1339 | open: null, | |
1340 | response: null, | |
1341 | search: null, | |
1342 | select: null | |
1343 | }, | |
1344 | ||
1345 | requestIndex: 0, | |
1346 | pending: 0, | |
1347 | ||
1348 | _create: function() { | |
1349 | // Some browsers only repeat keydown events, not keypress events, | |
1350 | // so we use the suppressKeyPress flag to determine if we've already | |
1351 | // handled the keydown event. #7269 | |
1352 | // Unfortunately the code for & in keypress is the same as the up arrow, | |
1353 | // so we use the suppressKeyPressRepeat flag to avoid handling keypress | |
1354 | // events when we know the keydown event was used to modify the | |
1355 | // search term. #7799 | |
1356 | var suppressKeyPress, suppressKeyPressRepeat, suppressInput, | |
1357 | nodeName = this.element[0].nodeName.toLowerCase(), | |
1358 | isTextarea = nodeName === "textarea", | |
1359 | isInput = nodeName === "input"; | |
1360 | ||
1361 | this.isMultiLine = | |
1362 | // Textareas are always multi-line | |
1363 | isTextarea ? true : | |
1364 | // Inputs are always single-line, even if inside a contentEditable element | |
1365 | // IE also treats inputs as contentEditable | |
1366 | isInput ? false : | |
1367 | // All other element types are determined by whether or not they're contentEditable | |
1368 | this.element.prop( "isContentEditable" ); | |
1369 | ||
1370 | this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; | |
1371 | this.isNewMenu = true; | |
1372 | ||
1373 | this.element | |
1374 | .addClass( "ui-autocomplete-input" ) | |
1375 | .attr( "autocomplete", "off" ); | |
1376 | ||
1377 | this._on( this.element, { | |
1378 | keydown: function( event ) { | |
1379 | if ( this.element.prop( "readOnly" ) ) { | |
1380 | suppressKeyPress = true; | |
1381 | suppressInput = true; | |
1382 | suppressKeyPressRepeat = true; | |
1383 | return; | |
1384 | } | |
1385 | ||
1386 | suppressKeyPress = false; | |
1387 | suppressInput = false; | |
1388 | suppressKeyPressRepeat = false; | |
1389 | var keyCode = $.ui.keyCode; | |
1390 | switch( event.keyCode ) { | |
1391 | case keyCode.PAGE_UP: | |
1392 | suppressKeyPress = true; | |
1393 | this._move( "previousPage", event ); | |
1394 | break; | |
1395 | case keyCode.PAGE_DOWN: | |
1396 | suppressKeyPress = true; | |
1397 | this._move( "nextPage", event ); | |
1398 | break; | |
1399 | case keyCode.UP: | |
1400 | suppressKeyPress = true; | |
1401 | this._keyEvent( "previous", event ); | |
1402 | break; | |
1403 | case keyCode.DOWN: | |
1404 | suppressKeyPress = true; | |
1405 | this._keyEvent( "next", event ); | |
1406 | break; | |
1407 | case keyCode.ENTER: | |
1408 | case keyCode.NUMPAD_ENTER: | |
1409 | // when menu is open and has focus | |
1410 | if ( this.menu.active ) { | |
1411 | // #6055 - Opera still allows the keypress to occur | |
1412 | // which causes forms to submit | |
1413 | suppressKeyPress = true; | |
1414 | event.preventDefault(); | |
1415 | this.menu.select( event ); | |
1416 | } | |
1417 | break; | |
1418 | case keyCode.TAB: | |
1419 | if ( this.menu.active ) { | |
1420 | this.menu.select( event ); | |
1421 | } | |
1422 | break; | |
1423 | case keyCode.ESCAPE: | |
1424 | if ( this.menu.element.is( ":visible" ) ) { | |
1425 | this._value( this.term ); | |
1426 | this.close( event ); | |
1427 | // Different browsers have different default behavior for escape | |
1428 | // Single press can mean undo or clear | |
1429 | // Double press in IE means clear the whole form | |
1430 | event.preventDefault(); | |
1431 | } | |
1432 | break; | |
1433 | default: | |
1434 | suppressKeyPressRepeat = true; | |
1435 | // search timeout should be triggered before the input value is changed | |
1436 | this._searchTimeout( event ); | |
1437 | break; | |
1438 | } | |
1439 | }, | |
1440 | keypress: function( event ) { | |
1441 | if ( suppressKeyPress ) { | |
1442 | suppressKeyPress = false; | |
1443 | if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { | |
1444 | event.preventDefault(); | |
1445 | } | |
1446 | return; | |
1447 | } | |
1448 | if ( suppressKeyPressRepeat ) { | |
1449 | return; | |
1450 | } | |
1451 | ||
1452 | // replicate some key handlers to allow them to repeat in Firefox and Opera | |
1453 | var keyCode = $.ui.keyCode; | |
1454 | switch( event.keyCode ) { | |
1455 | case keyCode.PAGE_UP: | |
1456 | this._move( "previousPage", event ); | |
1457 | break; | |
1458 | case keyCode.PAGE_DOWN: | |
1459 | this._move( "nextPage", event ); | |
1460 | break; | |
1461 | case keyCode.UP: | |
1462 | this._keyEvent( "previous", event ); | |
1463 | break; | |
1464 | case keyCode.DOWN: | |
1465 | this._keyEvent( "next", event ); | |
1466 | break; | |
1467 | } | |
1468 | }, | |
1469 | input: function( event ) { | |
1470 | if ( suppressInput ) { | |
1471 | suppressInput = false; | |
1472 | event.preventDefault(); | |
1473 | return; | |
1474 | } | |
1475 | this._searchTimeout( event ); | |
1476 | }, | |
1477 | focus: function() { | |
1478 | this.selectedItem = null; | |
1479 | this.previous = this._value(); | |
1480 | }, | |
1481 | blur: function( event ) { | |
1482 | if ( this.cancelBlur ) { | |
1483 | delete this.cancelBlur; | |
1484 | return; | |
1485 | } | |
1486 | ||
1487 | clearTimeout( this.searching ); | |
1488 | this.close( event ); | |
1489 | this._change( event ); | |
1490 | } | |
1491 | }); | |
1492 | ||
1493 | this._initSource(); | |
1494 | this.menu = $( "<ul>" ) | |
1495 | .addClass( "ui-autocomplete ui-front" ) | |
1496 | .appendTo( this._appendTo() ) | |
1497 | .menu({ | |
1498 | // disable ARIA support, the live region takes care of that | |
1499 | role: null | |
1500 | }) | |
1501 | .hide() | |
1502 | .data( "ui-menu" ); | |
1503 | ||
1504 | this._on( this.menu.element, { | |
1505 | mousedown: function( event ) { | |
1506 | // prevent moving focus out of the text field | |
1507 | event.preventDefault(); | |
1508 | ||
1509 | // IE doesn't prevent moving focus even with event.preventDefault() | |
1510 | // so we set a flag to know when we should ignore the blur event | |
1511 | this.cancelBlur = true; | |
1512 | this._delay(function() { | |
1513 | delete this.cancelBlur; | |
1514 | }); | |
1515 | ||
1516 | // clicking on the scrollbar causes focus to shift to the body | |
1517 | // but we can't detect a mouseup or a click immediately afterward | |
1518 | // so we have to track the next mousedown and close the menu if | |
1519 | // the user clicks somewhere outside of the autocomplete | |
1520 | var menuElement = this.menu.element[ 0 ]; | |
1521 | if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { | |
1522 | this._delay(function() { | |
1523 | var that = this; | |
1524 | this.document.one( "mousedown", function( event ) { | |
1525 | if ( event.target !== that.element[ 0 ] && | |
1526 | event.target !== menuElement && | |
1527 | !$.contains( menuElement, event.target ) ) { | |
1528 | that.close(); | |
1529 | } | |
1530 | }); | |
1531 | }); | |
1532 | } | |
1533 | }, | |
1534 | menufocus: function( event, ui ) { | |
1535 | // support: Firefox | |
1536 | // Prevent accidental activation of menu items in Firefox (#7024 #9118) | |
1537 | if ( this.isNewMenu ) { | |
1538 | this.isNewMenu = false; | |
1539 | if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { | |
1540 | this.menu.blur(); | |
1541 | ||
1542 | this.document.one( "mousemove", function() { | |
1543 | $( event.target ).trigger( event.originalEvent ); | |
1544 | }); | |
1545 | ||
1546 | return; | |
1547 | } | |
1548 | } | |
1549 | ||
1550 | var item = ui.item.data( "ui-autocomplete-item" ); | |
1551 | if ( false !== this._trigger( "focus", event, { item: item } ) ) { | |
1552 | // use value to match what will end up in the input, if it was a key event | |
1553 | if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { | |
1554 | this._value( item.value ); | |
1555 | } | |
1556 | } else { | |
1557 | // Normally the input is populated with the item's value as the | |
1558 | // menu is navigated, causing screen readers to notice a change and | |
1559 | // announce the item. Since the focus event was canceled, this doesn't | |
1560 | // happen, so we update the live region so that screen readers can | |
1561 | // still notice the change and announce it. | |
1562 | this.liveRegion.text( item.value ); | |
1563 | } | |
1564 | }, | |
1565 | menuselect: function( event, ui ) { | |
1566 | var item = ui.item.data( "ui-autocomplete-item" ), | |
1567 | previous = this.previous; | |
1568 | ||
1569 | // only trigger when focus was lost (click on menu) | |
1570 | if ( this.element[0] !== this.document[0].activeElement ) { | |
1571 | this.element.focus(); | |
1572 | this.previous = previous; | |
1573 | // #6109 - IE triggers two focus events and the second | |
1574 | // is asynchronous, so we need to reset the previous | |
1575 | // term synchronously and asynchronously :-( | |
1576 | this._delay(function() { | |
1577 | this.previous = previous; | |
1578 | this.selectedItem = item; | |
1579 | }); | |
1580 | } | |
1581 | ||
1582 | if ( false !== this._trigger( "select", event, { item: item } ) ) { | |
1583 | this._value( item.value ); | |
1584 | } | |
1585 | // reset the term after the select event | |
1586 | // this allows custom select handling to work properly | |
1587 | this.term = this._value(); | |
1588 | ||
1589 | this.close( event ); | |
1590 | this.selectedItem = item; | |
1591 | } | |
1592 | }); | |
1593 | ||
1594 | this.liveRegion = $( "<span>", { | |
1595 | role: "status", | |
1596 | "aria-live": "polite" | |
1597 | }) | |
1598 | .addClass( "ui-helper-hidden-accessible" ) | |
1599 | .insertBefore( this.element ); | |
1600 | ||
1601 | // turning off autocomplete prevents the browser from remembering the | |
1602 | // value when navigating through history, so we re-enable autocomplete | |
1603 | // if the page is unloaded before the widget is destroyed. #7790 | |
1604 | this._on( this.window, { | |
1605 | beforeunload: function() { | |
1606 | this.element.removeAttr( "autocomplete" ); | |
1607 | } | |
1608 | }); | |
1609 | }, | |
1610 | ||
1611 | _destroy: function() { | |
1612 | clearTimeout( this.searching ); | |
1613 | this.element | |
1614 | .removeClass( "ui-autocomplete-input" ) | |
1615 | .removeAttr( "autocomplete" ); | |
1616 | this.menu.element.remove(); | |
1617 | this.liveRegion.remove(); | |
1618 | }, | |
1619 | ||
1620 | _setOption: function( key, value ) { | |
1621 | this._super( key, value ); | |
1622 | if ( key === "source" ) { | |
1623 | this._initSource(); | |
1624 | } | |
1625 | if ( key === "appendTo" ) { | |
1626 | this.menu.element.appendTo( this._appendTo() ); | |
1627 | } | |
1628 | if ( key === "disabled" && value && this.xhr ) { | |
1629 | this.xhr.abort(); | |
1630 | } | |
1631 | }, | |
1632 | ||
1633 | _appendTo: function() { | |
1634 | var element = this.options.appendTo; | |
1635 | ||
1636 | if ( element ) { | |
1637 | element = element.jquery || element.nodeType ? | |
1638 | $( element ) : | |
1639 | this.document.find( element ).eq( 0 ); | |
1640 | } | |
1641 | ||
1642 | if ( !element ) { | |
1643 | element = this.element.closest( ".ui-front" ); | |
1644 | } | |
1645 | ||
1646 | if ( !element.length ) { | |
1647 | element = this.document[0].body; | |
1648 | } | |
1649 | ||
1650 | return element; | |
1651 | }, | |
1652 | ||
1653 | _initSource: function() { | |
1654 | var array, url, | |
1655 | that = this; | |
1656 | if ( $.isArray(this.options.source) ) { | |
1657 | array = this.options.source; | |
1658 | this.source = function( request, response ) { | |
1659 | response( $.ui.autocomplete.filter( array, request.term ) ); | |
1660 | }; | |
1661 | } else if ( typeof this.options.source === "string" ) { | |
1662 | url = this.options.source; | |
1663 | this.source = function( request, response ) { | |
1664 | if ( that.xhr ) { | |
1665 | that.xhr.abort(); | |
1666 | } | |
1667 | that.xhr = $.ajax({ | |
1668 | url: url, | |
1669 | data: request, | |
1670 | dataType: "json", | |
1671 | success: function( data ) { | |
1672 | response( data ); | |
1673 | }, | |
1674 | error: function() { | |
1675 | response( [] ); | |
1676 | } | |
1677 | }); | |
1678 | }; | |
1679 | } else { | |
1680 | this.source = this.options.source; | |
1681 | } | |
1682 | }, | |
1683 | ||
1684 | _searchTimeout: function( event ) { | |
1685 | clearTimeout( this.searching ); | |
1686 | this.searching = this._delay(function() { | |
1687 | // only search if the value has changed | |
1688 | if ( this.term !== this._value() ) { | |
1689 | this.selectedItem = null; | |
1690 | this.search( null, event ); | |
1691 | } | |
1692 | }, this.options.delay ); | |
1693 | }, | |
1694 | ||
1695 | search: function( value, event ) { | |
1696 | value = value != null ? value : this._value(); | |
1697 | ||
1698 | // always save the actual value, not the one passed as an argument | |
1699 | this.term = this._value(); | |
1700 | ||
1701 | if ( value.length < this.options.minLength ) { | |
1702 | return this.close( event ); | |
1703 | } | |
1704 | ||
1705 | if ( this._trigger( "search", event ) === false ) { | |
1706 | return; | |
1707 | } | |
1708 | ||
1709 | return this._search( value ); | |
1710 | }, | |
1711 | ||
1712 | _search: function( value ) { | |
1713 | this.pending++; | |
1714 | this.element.addClass( "ui-autocomplete-loading" ); | |
1715 | this.cancelSearch = false; | |
1716 | ||
1717 | this.source( { term: value }, this._response() ); | |
1718 | }, | |
1719 | ||
1720 | _response: function() { | |
1721 | var index = ++this.requestIndex; | |
1722 | ||
1723 | return $.proxy(function( content ) { | |
1724 | if ( index === this.requestIndex ) { | |
1725 | this.__response( content ); | |
1726 | } | |
1727 | ||
1728 | this.pending--; | |
1729 | if ( !this.pending ) { | |
1730 | this.element.removeClass( "ui-autocomplete-loading" ); | |
1731 | } | |
1732 | }, this ); | |
1733 | }, | |
1734 | ||
1735 | __response: function( content ) { | |
1736 | if ( content ) { | |
1737 | content = this._normalize( content ); | |
1738 | } | |
1739 | this._trigger( "response", null, { content: content } ); | |
1740 | if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { | |
1741 | this._suggest( content ); | |
1742 | this._trigger( "open" ); | |
1743 | } else { | |
1744 | // use ._close() instead of .close() so we don't cancel future searches | |
1745 | this._close(); | |
1746 | } | |
1747 | }, | |
1748 | ||
1749 | close: function( event ) { | |
1750 | this.cancelSearch = true; | |
1751 | this._close( event ); | |
1752 | }, | |
1753 | ||
1754 | _close: function( event ) { | |
1755 | if ( this.menu.element.is( ":visible" ) ) { | |
1756 | this.menu.element.hide(); | |
1757 | this.menu.blur(); | |
1758 | this.isNewMenu = true; | |
1759 | this._trigger( "close", event ); | |
1760 | } | |
1761 | }, | |
1762 | ||
1763 | _change: function( event ) { | |
1764 | if ( this.previous !== this._value() ) { | |
1765 | this._trigger( "change", event, { item: this.selectedItem } ); | |
1766 | } | |
1767 | }, | |
1768 | ||
1769 | _normalize: function( items ) { | |
1770 | // assume all items have the right format when the first item is complete | |
1771 | if ( items.length && items[0].label && items[0].value ) { | |
1772 | return items; | |
1773 | } | |
1774 | return $.map( items, function( item ) { | |
1775 | if ( typeof item === "string" ) { | |
1776 | return { | |
1777 | label: item, | |
1778 | value: item | |
1779 | }; | |
1780 | } | |
1781 | return $.extend({ | |
1782 | label: item.label || item.value, | |
1783 | value: item.value || item.label | |
1784 | }, item ); | |
1785 | }); | |
1786 | }, | |
1787 | ||
1788 | _suggest: function( items ) { | |
1789 | var ul = this.menu.element.empty(); | |
1790 | this._renderMenu( ul, items ); | |
1791 | this.isNewMenu = true; | |
1792 | this.menu.refresh(); | |
1793 | ||
1794 | // size and position menu | |
1795 | ul.show(); | |
1796 | this._resizeMenu(); | |
1797 | ul.position( $.extend({ | |
1798 | of: this.element | |
1799 | }, this.options.position )); | |
1800 | ||
1801 | if ( this.options.autoFocus ) { | |
1802 | this.menu.next(); | |
1803 | } | |
1804 | }, | |
1805 | ||
1806 | _resizeMenu: function() { | |
1807 | var ul = this.menu.element; | |
1808 | ul.outerWidth( Math.max( | |
1809 | // Firefox wraps long text (possibly a rounding bug) | |
1810 | // so we add 1px to avoid the wrapping (#7513) | |
1811 | ul.width( "" ).outerWidth() + 1, | |
1812 | this.element.outerWidth() | |
1813 | ) ); | |
1814 | }, | |
1815 | ||
1816 | _renderMenu: function( ul, items ) { | |
1817 | var that = this; | |
1818 | $.each( items, function( index, item ) { | |
1819 | that._renderItemData( ul, item ); | |
1820 | }); | |
1821 | }, | |
1822 | ||
1823 | _renderItemData: function( ul, item ) { | |
1824 | return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); | |
1825 | }, | |
1826 | ||
1827 | _renderItem: function( ul, item ) { | |
1828 | return $( "<li>" ) | |
1829 | .append( $( "<a>" ).text( item.label ) ) | |
1830 | .appendTo( ul ); | |
1831 | }, | |
1832 | ||
1833 | _move: function( direction, event ) { | |
1834 | if ( !this.menu.element.is( ":visible" ) ) { | |
1835 | this.search( null, event ); | |
1836 | return; | |
1837 | } | |
1838 | if ( this.menu.isFirstItem() && /^previous/.test( direction ) || | |
1839 | this.menu.isLastItem() && /^next/.test( direction ) ) { | |
1840 | this._value( this.term ); | |
1841 | this.menu.blur(); | |
1842 | return; | |
1843 | } | |
1844 | this.menu[ direction ]( event ); | |
1845 | }, | |
1846 | ||
1847 | widget: function() { | |
1848 | return this.menu.element; | |
1849 | }, | |
1850 | ||
1851 | _value: function() { | |
1852 | return this.valueMethod.apply( this.element, arguments ); | |
1853 | }, | |
1854 | ||
1855 | _keyEvent: function( keyEvent, event ) { | |
1856 | if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { | |
1857 | this._move( keyEvent, event ); | |
1858 | ||
1859 | // prevents moving cursor to beginning/end of the text field in some browsers | |
1860 | event.preventDefault(); | |
1861 | } | |
1862 | } | |
1863 | }); | |
1864 | ||
1865 | $.extend( $.ui.autocomplete, { | |
1866 | escapeRegex: function( value ) { | |
1867 | return value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&"); | |
1868 | }, | |
1869 | filter: function(array, term) { | |
1870 | var matcher = new RegExp( $.ui.autocomplete.escapeRegex(term), "i" ); | |
1871 | return $.grep( array, function(value) { | |
1872 | return matcher.test( value.label || value.value || value ); | |
1873 | }); | |
1874 | } | |
1875 | }); | |
1876 | ||
1877 | ||
1878 | // live region extension, adding a `messages` option | |
1879 | // NOTE: This is an experimental API. We are still investigating | |
1880 | // a full solution for string manipulation and internationalization. | |
1881 | $.widget( "ui.autocomplete", $.ui.autocomplete, { | |
1882 | options: { | |
1883 | messages: { | |
1884 | noResults: "No search results.", | |
1885 | results: function( amount ) { | |
1886 | return amount + ( amount > 1 ? " results are" : " result is" ) + | |
1887 | " available, use up and down arrow keys to navigate."; | |
1888 | } | |
1889 | } | |
1890 | }, | |
1891 | ||
1892 | __response: function( content ) { | |
1893 | var message; | |
1894 | this._superApply( arguments ); | |
1895 | if ( this.options.disabled || this.cancelSearch ) { | |
1896 | return; | |
1897 | } | |
1898 | if ( content && content.length ) { | |
1899 | message = this.options.messages.results( content.length ); | |
1900 | } else { | |
1901 | message = this.options.messages.noResults; | |
1902 | } | |
1903 | this.liveRegion.text( message ); | |
1904 | } | |
1905 | }); | |
1906 | ||
1907 | }( jQuery )); | |
1908 | (function( $, undefined ) { | |
1909 | ||
1910 | $.widget( "ui.menu", { | |
1911 | version: "1.10.4", | |
1912 | defaultElement: "<ul>", | |
1913 | delay: 300, | |
1914 | options: { | |
1915 | icons: { | |
1916 | submenu: "ui-icon-carat-1-e" | |
1917 | }, | |
1918 | menus: "ul", | |
1919 | position: { | |
1920 | my: "left top", | |
1921 | at: "right top" | |
1922 | }, | |
1923 | role: "menu", | |
1924 | ||
1925 | // callbacks | |
1926 | blur: null, | |
1927 | focus: null, | |
1928 | select: null | |
1929 | }, | |
1930 | ||
1931 | _create: function() { | |
1932 | this.activeMenu = this.element; | |
1933 | // flag used to prevent firing of the click handler | |
1934 | // as the event bubbles up through nested menus | |
1935 | this.mouseHandled = false; | |
1936 | this.element | |
1937 | .uniqueId() | |
1938 | .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) | |
1939 | .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) | |
1940 | .attr({ | |
1941 | role: this.options.role, | |
1942 | tabIndex: 0 | |
1943 | }) | |
1944 | // need to catch all clicks on disabled menu | |
1945 | // not possible through _on | |
1946 | .bind( "click" + this.eventNamespace, $.proxy(function( event ) { | |
1947 | if ( this.options.disabled ) { | |
1948 | event.preventDefault(); | |
1949 | } | |
1950 | }, this )); | |
1951 | ||
1952 | if ( this.options.disabled ) { | |
1953 | this.element | |
1954 | .addClass( "ui-state-disabled" ) | |
1955 | .attr( "aria-disabled", "true" ); | |
1956 | } | |
1957 | ||
1958 | this._on({ | |
1959 | // Prevent focus from sticking to links inside menu after clicking | |
1960 | // them (focus should always stay on UL during navigation). | |
1961 | "mousedown .ui-menu-item > a": function( event ) { | |
1962 | event.preventDefault(); | |
1963 | }, | |
1964 | "click .ui-state-disabled > a": function( event ) { | |
1965 | event.preventDefault(); | |
1966 | }, | |
1967 | "click .ui-menu-item:has(a)": function( event ) { | |
1968 | var target = $( event.target ).closest( ".ui-menu-item" ); | |
1969 | if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { | |
1970 | this.select( event ); | |
1971 | ||
1972 | // Only set the mouseHandled flag if the event will bubble, see #9469. | |
1973 | if ( !event.isPropagationStopped() ) { | |
1974 | this.mouseHandled = true; | |
1975 | } | |
1976 | ||
1977 | // Open submenu on click | |
1978 | if ( target.has( ".ui-menu" ).length ) { | |
1979 | this.expand( event ); | |
1980 | } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) { | |
1981 | ||
1982 | // Redirect focus to the menu | |
1983 | this.element.trigger( "focus", [ true ] ); | |
1984 | ||
1985 | // If the active item is on the top level, let it stay active. | |
1986 | // Otherwise, blur the active item since it is no longer visible. | |
1987 | if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { | |
1988 | clearTimeout( this.timer ); | |
1989 | } | |
1990 | } | |
1991 | } | |
1992 | }, | |
1993 | "mouseenter .ui-menu-item": function( event ) { | |
1994 | var target = $( event.currentTarget ); | |
1995 | // Remove ui-state-active class from siblings of the newly focused menu item | |
1996 | // to avoid a jump caused by adjacent elements both having a class with a border | |
1997 | target.siblings().children( ".ui-state-active" ).removeClass( "ui-state-active" ); | |
1998 | this.focus( event, target ); | |
1999 | }, | |
2000 | mouseleave: "collapseAll", | |
2001 | "mouseleave .ui-menu": "collapseAll", | |
2002 | focus: function( event, keepActiveItem ) { | |
2003 | // If there's already an active item, keep it active | |
2004 | // If not, activate the first item | |
2005 | var item = this.active || this.element.children( ".ui-menu-item" ).eq( 0 ); | |
2006 | ||
2007 | if ( !keepActiveItem ) { | |
2008 | this.focus( event, item ); | |
2009 | } | |
2010 | }, | |
2011 | blur: function( event ) { | |
2012 | this._delay(function() { | |
2013 | if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { | |
2014 | this.collapseAll( event ); | |
2015 | } | |
2016 | }); | |
2017 | }, | |
2018 | keydown: "_keydown" | |
2019 | }); | |
2020 | ||
2021 | this.refresh(); | |
2022 | ||
2023 | // Clicks outside of a menu collapse any open menus | |
2024 | this._on( this.document, { | |
2025 | click: function( event ) { | |
2026 | if ( !$( event.target ).closest( ".ui-menu" ).length ) { | |
2027 | this.collapseAll( event ); | |
2028 | } | |
2029 | ||
2030 | // Reset the mouseHandled flag | |
2031 | this.mouseHandled = false; | |
2032 | } | |
2033 | }); | |
2034 | }, | |
2035 | ||
2036 | _destroy: function() { | |
2037 | // Destroy (sub)menus | |
2038 | this.element | |
2039 | .removeAttr( "aria-activedescendant" ) | |
2040 | .find( ".ui-menu" ).addBack() | |
2041 | .removeClass( "ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons" ) | |
2042 | .removeAttr( "role" ) | |
2043 | .removeAttr( "tabIndex" ) | |
2044 | .removeAttr( "aria-labelledby" ) | |
2045 | .removeAttr( "aria-expanded" ) | |
2046 | .removeAttr( "aria-hidden" ) | |
2047 | .removeAttr( "aria-disabled" ) | |
2048 | .removeUniqueId() | |
2049 | .show(); | |
2050 | ||
2051 | // Destroy menu items | |
2052 | this.element.find( ".ui-menu-item" ) | |
2053 | .removeClass( "ui-menu-item" ) | |
2054 | .removeAttr( "role" ) | |
2055 | .removeAttr( "aria-disabled" ) | |
2056 | .children( "a" ) | |
2057 | .removeUniqueId() | |
2058 | .removeClass( "ui-corner-all ui-state-hover" ) | |
2059 | .removeAttr( "tabIndex" ) | |
2060 | .removeAttr( "role" ) | |
2061 | .removeAttr( "aria-haspopup" ) | |
2062 | .children().each( function() { | |
2063 | var elem = $( this ); | |
2064 | if ( elem.data( "ui-menu-submenu-carat" ) ) { | |
2065 | elem.remove(); | |
2066 | } | |
2067 | }); | |
2068 | ||
2069 | // Destroy menu dividers | |
2070 | this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); | |
2071 | }, | |
2072 | ||
2073 | _keydown: function( event ) { | |
2074 | var match, prev, character, skip, regex, | |
2075 | preventDefault = true; | |
2076 | ||
2077 | function escape( value ) { | |
2078 | return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); | |
2079 | } | |
2080 | ||
2081 | switch ( event.keyCode ) { | |
2082 | case $.ui.keyCode.PAGE_UP: | |
2083 | this.previousPage( event ); | |
2084 | break; | |
2085 | case $.ui.keyCode.PAGE_DOWN: | |
2086 | this.nextPage( event ); | |
2087 | break; | |
2088 | case $.ui.keyCode.HOME: | |
2089 | this._move( "first", "first", event ); | |
2090 | break; | |
2091 | case $.ui.keyCode.END: | |
2092 | this._move( "last", "last", event ); | |
2093 | break; | |
2094 | case $.ui.keyCode.UP: | |
2095 | this.previous( event ); | |
2096 | break; | |
2097 | case $.ui.keyCode.DOWN: | |
2098 | this.next( event ); | |
2099 | break; | |
2100 | case $.ui.keyCode.LEFT: | |
2101 | this.collapse( event ); | |
2102 | break; | |
2103 | case $.ui.keyCode.RIGHT: | |
2104 | if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { | |
2105 | this.expand( event ); | |
2106 | } | |
2107 | break; | |
2108 | case $.ui.keyCode.ENTER: | |
2109 | case $.ui.keyCode.SPACE: | |
2110 | this._activate( event ); | |
2111 | break; | |
2112 | case $.ui.keyCode.ESCAPE: | |
2113 | this.collapse( event ); | |
2114 | break; | |
2115 | default: | |
2116 | preventDefault = false; | |
2117 | prev = this.previousFilter || ""; | |
2118 | character = String.fromCharCode( event.keyCode ); | |
2119 | skip = false; | |
2120 | ||
2121 | clearTimeout( this.filterTimer ); | |
2122 | ||
2123 | if ( character === prev ) { | |
2124 | skip = true; | |
2125 | } else { | |
2126 | character = prev + character; | |
2127 | } | |
2128 | ||
2129 | regex = new RegExp( "^" + escape( character ), "i" ); | |
2130 | match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { | |
2131 | return regex.test( $( this ).children( "a" ).text() ); | |
2132 | }); | |
2133 | match = skip && match.index( this.active.next() ) !== -1 ? | |
2134 | this.active.nextAll( ".ui-menu-item" ) : | |
2135 | match; | |
2136 | ||
2137 | // If no matches on the current filter, reset to the last character pressed | |
2138 | // to move down the menu to the first item that starts with that character | |
2139 | if ( !match.length ) { | |
2140 | character = String.fromCharCode( event.keyCode ); | |
2141 | regex = new RegExp( "^" + escape( character ), "i" ); | |
2142 | match = this.activeMenu.children( ".ui-menu-item" ).filter(function() { | |
2143 | return regex.test( $( this ).children( "a" ).text() ); | |
2144 | }); | |
2145 | } | |
2146 | ||
2147 | if ( match.length ) { | |
2148 | this.focus( event, match ); | |
2149 | if ( match.length > 1 ) { | |
2150 | this.previousFilter = character; | |
2151 | this.filterTimer = this._delay(function() { | |
2152 | delete this.previousFilter; | |
2153 | }, 1000 ); | |
2154 | } else { | |
2155 | delete this.previousFilter; | |
2156 | } | |
2157 | } else { | |
2158 | delete this.previousFilter; | |
2159 | } | |
2160 | } | |
2161 | ||
2162 | if ( preventDefault ) { | |
2163 | event.preventDefault(); | |
2164 | } | |
2165 | }, | |
2166 | ||
2167 | _activate: function( event ) { | |
2168 | if ( !this.active.is( ".ui-state-disabled" ) ) { | |
2169 | if ( this.active.children( "a[aria-haspopup='true']" ).length ) { | |
2170 | this.expand( event ); | |
2171 | } else { | |
2172 | this.select( event ); | |
2173 | } | |
2174 | } | |
2175 | }, | |
2176 | ||
2177 | refresh: function() { | |
2178 | var menus, | |
2179 | icon = this.options.icons.submenu, | |
2180 | submenus = this.element.find( this.options.menus ); | |
2181 | ||
2182 | this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ); | |
2183 | ||
2184 | // Initialize nested menus | |
2185 | submenus.filter( ":not(.ui-menu)" ) | |
2186 | .addClass( "ui-menu ui-widget ui-widget-content ui-corner-all" ) | |
2187 | .hide() | |
2188 | .attr({ | |
2189 | role: this.options.role, | |
2190 | "aria-hidden": "true", | |
2191 | "aria-expanded": "false" | |
2192 | }) | |
2193 | .each(function() { | |
2194 | var menu = $( this ), | |
2195 | item = menu.prev( "a" ), | |
2196 | submenuCarat = $( "<span>" ) | |
2197 | .addClass( "ui-menu-icon ui-icon " + icon ) | |
2198 | .data( "ui-menu-submenu-carat", true ); | |
2199 | ||
2200 | item | |
2201 | .attr( "aria-haspopup", "true" ) | |
2202 | .prepend( submenuCarat ); | |
2203 | menu.attr( "aria-labelledby", item.attr( "id" ) ); | |
2204 | }); | |
2205 | ||
2206 | menus = submenus.add( this.element ); | |
2207 | ||
2208 | // Don't refresh list items that are already adapted | |
2209 | menus.children( ":not(.ui-menu-item):has(a)" ) | |
2210 | .addClass( "ui-menu-item" ) | |
2211 | .attr( "role", "presentation" ) | |
2212 | .children( "a" ) | |
2213 | .uniqueId() | |
2214 | .addClass( "ui-corner-all" ) | |
2215 | .attr({ | |
2216 | tabIndex: -1, | |
2217 | role: this._itemRole() | |
2218 | }); | |
2219 | ||
2220 | // Initialize unlinked menu-items containing spaces and/or dashes only as dividers | |
2221 | menus.children( ":not(.ui-menu-item)" ).each(function() { | |
2222 | var item = $( this ); | |
2223 | // hyphen, em dash, en dash | |
2224 | if ( !/[^\-\u2014\u2013\s]/.test( item.text() ) ) { | |
2225 | item.addClass( "ui-widget-content ui-menu-divider" ); | |
2226 | } | |
2227 | }); | |
2228 | ||
2229 | // Add aria-disabled attribute to any disabled menu item | |
2230 | menus.children( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); | |
2231 | ||
2232 | // If the active item has been removed, blur the menu | |
2233 | if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { | |
2234 | this.blur(); | |
2235 | } | |
2236 | }, | |
2237 | ||
2238 | _itemRole: function() { | |
2239 | return { | |
2240 | menu: "menuitem", | |
2241 | listbox: "option" | |
2242 | }[ this.options.role ]; | |
2243 | }, | |
2244 | ||
2245 | _setOption: function( key, value ) { | |
2246 | if ( key === "icons" ) { | |
2247 | this.element.find( ".ui-menu-icon" ) | |
2248 | .removeClass( this.options.icons.submenu ) | |
2249 | .addClass( value.submenu ); | |
2250 | } | |
2251 | this._super( key, value ); | |
2252 | }, | |
2253 | ||
2254 | focus: function( event, item ) { | |
2255 | var nested, focused; | |
2256 | this.blur( event, event && event.type === "focus" ); | |
2257 | ||
2258 | this._scrollIntoView( item ); | |
2259 | ||
2260 | this.active = item.first(); | |
2261 | focused = this.active.children( "a" ).addClass( "ui-state-focus" ); | |
2262 | // Only update aria-activedescendant if there's a role | |
2263 | // otherwise we assume focus is managed elsewhere | |
2264 | if ( this.options.role ) { | |
2265 | this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); | |
2266 | } | |
2267 | ||
2268 | // Highlight active parent menu item, if any | |
2269 | this.active | |
2270 | .parent() | |
2271 | .closest( ".ui-menu-item" ) | |
2272 | .children( "a:first" ) | |
2273 | .addClass( "ui-state-active" ); | |
2274 | ||
2275 | if ( event && event.type === "keydown" ) { | |
2276 | this._close(); | |
2277 | } else { | |
2278 | this.timer = this._delay(function() { | |
2279 | this._close(); | |
2280 | }, this.delay ); | |
2281 | } | |
2282 | ||
2283 | nested = item.children( ".ui-menu" ); | |
2284 | if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { | |
2285 | this._startOpening(nested); | |
2286 | } | |
2287 | this.activeMenu = item.parent(); | |
2288 | ||
2289 | this._trigger( "focus", event, { item: item } ); | |
2290 | }, | |
2291 | ||
2292 | _scrollIntoView: function( item ) { | |
2293 | var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; | |
2294 | if ( this._hasScroll() ) { | |
2295 | borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; | |
2296 | paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; | |
2297 | offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; | |
2298 | scroll = this.activeMenu.scrollTop(); | |
2299 | elementHeight = this.activeMenu.height(); | |
2300 | itemHeight = item.height(); | |
2301 | ||
2302 | if ( offset < 0 ) { | |
2303 | this.activeMenu.scrollTop( scroll + offset ); | |
2304 | } else if ( offset + itemHeight > elementHeight ) { | |
2305 | this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); | |
2306 | } | |
2307 | } | |
2308 | }, | |
2309 | ||
2310 | blur: function( event, fromFocus ) { | |
2311 | if ( !fromFocus ) { | |
2312 | clearTimeout( this.timer ); | |
2313 | } | |
2314 | ||
2315 | if ( !this.active ) { | |
2316 | return; | |
2317 | } | |
2318 | ||
2319 | this.active.children( "a" ).removeClass( "ui-state-focus" ); | |
2320 | this.active = null; | |
2321 | ||
2322 | this._trigger( "blur", event, { item: this.active } ); | |
2323 | }, | |
2324 | ||
2325 | _startOpening: function( submenu ) { | |
2326 | clearTimeout( this.timer ); | |
2327 | ||
2328 | // Don't open if already open fixes a Firefox bug that caused a .5 pixel | |
2329 | // shift in the submenu position when mousing over the carat icon | |
2330 | if ( submenu.attr( "aria-hidden" ) !== "true" ) { | |
2331 | return; | |
2332 | } | |
2333 | ||
2334 | this.timer = this._delay(function() { | |
2335 | this._close(); | |
2336 | this._open( submenu ); | |
2337 | }, this.delay ); | |
2338 | }, | |
2339 | ||
2340 | _open: function( submenu ) { | |
2341 | var position = $.extend({ | |
2342 | of: this.active | |
2343 | }, this.options.position ); | |
2344 | ||
2345 | clearTimeout( this.timer ); | |
2346 | this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) | |
2347 | .hide() | |
2348 | .attr( "aria-hidden", "true" ); | |
2349 | ||
2350 | submenu | |
2351 | .show() | |
2352 | .removeAttr( "aria-hidden" ) | |
2353 | .attr( "aria-expanded", "true" ) | |
2354 | .position( position ); | |
2355 | }, | |
2356 | ||
2357 | collapseAll: function( event, all ) { | |
2358 | clearTimeout( this.timer ); | |
2359 | this.timer = this._delay(function() { | |
2360 | // If we were passed an event, look for the submenu that contains the event | |
2361 | var currentMenu = all ? this.element : | |
2362 | $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); | |
2363 | ||
2364 | // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway | |
2365 | if ( !currentMenu.length ) { | |
2366 | currentMenu = this.element; | |
2367 | } | |
2368 | ||
2369 | this._close( currentMenu ); | |
2370 | ||
2371 | this.blur( event ); | |
2372 | this.activeMenu = currentMenu; | |
2373 | }, this.delay ); | |
2374 | }, | |
2375 | ||
2376 | // With no arguments, closes the currently active menu - if nothing is active | |
2377 | // it closes all menus. If passed an argument, it will search for menus BELOW | |
2378 | _close: function( startMenu ) { | |
2379 | if ( !startMenu ) { | |
2380 | startMenu = this.active ? this.active.parent() : this.element; | |
2381 | } | |
2382 | ||
2383 | startMenu | |
2384 | .find( ".ui-menu" ) | |
2385 | .hide() | |
2386 | .attr( "aria-hidden", "true" ) | |
2387 | .attr( "aria-expanded", "false" ) | |
2388 | .end() | |
2389 | .find( "a.ui-state-active" ) | |
2390 | .removeClass( "ui-state-active" ); | |
2391 | }, | |
2392 | ||
2393 | collapse: function( event ) { | |
2394 | var newItem = this.active && | |
2395 | this.active.parent().closest( ".ui-menu-item", this.element ); | |
2396 | if ( newItem && newItem.length ) { | |
2397 | this._close(); | |
2398 | this.focus( event, newItem ); | |
2399 | } | |
2400 | }, | |
2401 | ||
2402 | expand: function( event ) { | |
2403 | var newItem = this.active && | |
2404 | this.active | |
2405 | .children( ".ui-menu " ) | |
2406 | .children( ".ui-menu-item" ) | |
2407 | .first(); | |
2408 | ||
2409 | if ( newItem && newItem.length ) { | |
2410 | this._open( newItem.parent() ); | |
2411 | ||
2412 | // Delay so Firefox will not hide activedescendant change in expanding submenu from AT | |
2413 | this._delay(function() { | |
2414 | this.focus( event, newItem ); | |
2415 | }); | |
2416 | } | |
2417 | }, | |
2418 | ||
2419 | next: function( event ) { | |
2420 | this._move( "next", "first", event ); | |
2421 | }, | |
2422 | ||
2423 | previous: function( event ) { | |
2424 | this._move( "prev", "last", event ); | |
2425 | }, | |
2426 | ||
2427 | isFirstItem: function() { | |
2428 | return this.active && !this.active.prevAll( ".ui-menu-item" ).length; | |
2429 | }, | |
2430 | ||
2431 | isLastItem: function() { | |
2432 | return this.active && !this.active.nextAll( ".ui-menu-item" ).length; | |
2433 | }, | |
2434 | ||
2435 | _move: function( direction, filter, event ) { | |
2436 | var next; | |
2437 | if ( this.active ) { | |
2438 | if ( direction === "first" || direction === "last" ) { | |
2439 | next = this.active | |
2440 | [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) | |
2441 | .eq( -1 ); | |
2442 | } else { | |
2443 | next = this.active | |
2444 | [ direction + "All" ]( ".ui-menu-item" ) | |
2445 | .eq( 0 ); | |
2446 | } | |
2447 | } | |
2448 | if ( !next || !next.length || !this.active ) { | |
2449 | next = this.activeMenu.children( ".ui-menu-item" )[ filter ](); | |
2450 | } | |
2451 | ||
2452 | this.focus( event, next ); | |
2453 | }, | |
2454 | ||
2455 | nextPage: function( event ) { | |
2456 | var item, base, height; | |
2457 | ||
2458 | if ( !this.active ) { | |
2459 | this.next( event ); | |
2460 | return; | |
2461 | } | |
2462 | if ( this.isLastItem() ) { | |
2463 | return; | |
2464 | } | |
2465 | if ( this._hasScroll() ) { | |
2466 | base = this.active.offset().top; | |
2467 | height = this.element.height(); | |
2468 | this.active.nextAll( ".ui-menu-item" ).each(function() { | |
2469 | item = $( this ); | |
2470 | return item.offset().top - base - height < 0; | |
2471 | }); | |
2472 | ||
2473 | this.focus( event, item ); | |
2474 | } else { | |
2475 | this.focus( event, this.activeMenu.children( ".ui-menu-item" ) | |
2476 | [ !this.active ? "first" : "last" ]() ); | |
2477 | } | |
2478 | }, | |
2479 | ||
2480 | previousPage: function( event ) { | |
2481 | var item, base, height; | |
2482 | if ( !this.active ) { | |
2483 | this.next( event ); | |
2484 | return; | |
2485 | } | |
2486 | if ( this.isFirstItem() ) { | |
2487 | return; | |
2488 | } | |
2489 | if ( this._hasScroll() ) { | |
2490 | base = this.active.offset().top; | |
2491 | height = this.element.height(); | |
2492 | this.active.prevAll( ".ui-menu-item" ).each(function() { | |
2493 | item = $( this ); | |
2494 | return item.offset().top - base + height > 0; | |
2495 | }); | |
2496 | ||
2497 | this.focus( event, item ); | |
2498 | } else { | |
2499 | this.focus( event, this.activeMenu.children( ".ui-menu-item" ).first() ); | |
2500 | } | |
2501 | }, | |
2502 | ||
2503 | _hasScroll: function() { | |
2504 | return this.element.outerHeight() < this.element.prop( "scrollHeight" ); | |
2505 | }, | |
2506 | ||
2507 | select: function( event ) { | |
2508 | // TODO: It should never be possible to not have an active item at this | |
2509 | // point, but the tests don't trigger mouseenter before click. | |
2510 | this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); | |
2511 | var ui = { item: this.active }; | |
2512 | if ( !this.active.has( ".ui-menu" ).length ) { | |
2513 | this.collapseAll( event, true ); | |
2514 | } | |
2515 | this._trigger( "select", event, ui ); | |
2516 | } | |
2517 | }); | |
2518 | ||
2519 | }( jQuery )); |