diff options
author | Nicolas LÅ“uillet <nicolas@loeuillet.org> | 2014-03-10 18:14:43 +0100 |
---|---|---|
committer | Nicolas LÅ“uillet <nicolas@loeuillet.org> | 2014-03-10 18:14:43 +0100 |
commit | 1acd18510a8fc5b843bf793322ed79b249b195dc (patch) | |
tree | 8218a340193e2827e1c4b0a6117adf81344e7b43 /themes/default/js/jquery-ui-1.10.4.custom.js | |
parent | d47a05a9a5185e835d51341febc8257f5262ce03 (diff) | |
parent | fb26cc9375ce9ef8df748eb473eb6e58884421c6 (diff) | |
download | wallabag-1acd18510a8fc5b843bf793322ed79b249b195dc.tar.gz wallabag-1acd18510a8fc5b843bf793322ed79b249b195dc.tar.zst wallabag-1acd18510a8fc5b843bf793322ed79b249b195dc.zip |
Merge pull request #544 from mariroz/feature-tags-autocomplete
a lot of enhancements related to tags: tags list is now sorted, shows number of articles, autocomplete added according to #477, #542
Diffstat (limited to 'themes/default/js/jquery-ui-1.10.4.custom.js')
-rw-r--r-- | themes/default/js/jquery-ui-1.10.4.custom.js | 2519 |
1 files changed, 2519 insertions, 0 deletions
diff --git a/themes/default/js/jquery-ui-1.10.4.custom.js b/themes/default/js/jquery-ui-1.10.4.custom.js new file mode 100644 index 00000000..6f599fca --- /dev/null +++ b/themes/default/js/jquery-ui-1.10.4.custom.js | |||
@@ -0,0 +1,2519 @@ | |||
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 )); | ||