Modified: maven/website/components/plugins-archives/maven-clean-plugin-LATEST/testapidocs/jquery/jquery-ui.js ============================================================================== --- maven/website/components/plugins-archives/maven-clean-plugin-LATEST/testapidocs/jquery/jquery-ui.js (original) +++ maven/website/components/plugins-archives/maven-clean-plugin-LATEST/testapidocs/jquery/jquery-ui.js Fri Apr 1 21:26:51 2022 @@ -1,7 +1,7 @@ -/*! jQuery UI - v1.11.4 - 2015-05-20 +/*! jQuery UI - v1.12.1 - 2018-12-06 * http://jqueryui.com -* Includes: core.js, widget.js, position.js, autocomplete.js, menu.js -* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ +* Includes: widget.js, position.js, keycode.js, unique-id.js, widgets/autocomplete.js, widgets/menu.js +* Copyright jQuery Foundation and other contributors; Licensed MIT */ (function( factory ) { if ( typeof define === "function" && define.amd ) { @@ -14,319 +14,36 @@ factory( jQuery ); } }(function( $ ) { -/*! - * jQuery UI Core 1.11.4 - * http://jqueryui.com - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * http://api.jqueryui.com/category/ui-core/ - */ - -// $.ui might exist from components with no dependencies, e.g., $.ui.position $.ui = $.ui || {}; -$.extend( $.ui, { - version: "1.11.4", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - scrollParent: function( includeHidden ) { - var position = this.css( "position" ), - excludeStaticParent = position === "absolute", - overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, - scrollParent = this.parents().filter( function() { - var parent = $( this ); - if ( excludeStaticParent && parent.css( "position" ) === "static" ) { - return false; - } - return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); - }).eq( 0 ); - - return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; - }, - - uniqueId: (function() { - var uuid = 0; - - return function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + ( ++uuid ); - } - }); - }; - })(), - - removeUniqueId: function() { - return this.each(function() { - if ( /^ui-id-\d+$/.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap='#" + mapName + "']" )[ 0 ]; - return !!img && visible( img ); - } - return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - disableSelection: (function() { - var eventType = "onselectstart" in document.createElement( "div" ) ? - "selectstart" : - "mousedown"; - - return function() { - return this.bind( eventType + ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }; - })(), - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> - value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - } -}); - -// $.ui.plugin is deprecated. Use $.widget() extensions instead. -$.ui.plugin = { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args, allowDisconnected ) { - var i, - set = instance.plugins[ name ]; - - if ( !set ) { - return; - } - - if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } -}; +var version = $.ui.version = "1.12.1"; /*! - * jQuery UI Widget 1.11.4 + * jQuery UI Widget 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license - * - * http://api.jqueryui.com/jQuery.widget/ */ +//>>label: Widget +//>>group: Core +//>>description: Provides a factory for creating stateful widgets with a common API. +//>>docs: http://api.jqueryui.com/jQuery.widget/ +//>>demos: http://jqueryui.com/widget/ + + -var widget_uuid = 0, - widget_slice = Array.prototype.slice; +var widgetUuid = 0; +var widgetSlice = Array.prototype.slice; -$.cleanData = (function( orig ) { +$.cleanData = ( function( orig ) { return function( elems ) { var events, elem, i; - for ( i = 0; (elem = elems[i]) != null; i++ ) { + for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { try { // Only trigger remove when necessary to save time @@ -335,29 +52,34 @@ $.cleanData = (function( orig ) { $( elem ).triggerHandler( "remove" ); } - // http://bugs.jquery.com/ticket/8235 + // Http://bugs.jquery.com/ticket/8235 } catch ( e ) {} } orig( elems ); }; -})( $.cleanData ); +} )( $.cleanData ); $.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; + var existingConstructor, constructor, basePrototype; + // ProxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + var proxiedPrototype = {}; + + var namespace = name.split( "." )[ 0 ]; name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; + var fullName = namespace + "-" + name; if ( !prototype ) { prototype = base; base = $.Widget; } - // create selector for plugin + if ( $.isArray( prototype ) ) { + prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); + } + + // Create selector for plugin $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { return !!$.data( elem, fullName ); }; @@ -365,30 +87,35 @@ $.widget = function( name, base, prototy $[ namespace ] = $[ namespace ] || {}; existingConstructor = $[ namespace ][ name ]; constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword + + // Allow instantiation without "new" keyword if ( !this._createWidget ) { return new constructor( options, element ); } - // allow instantiation without initializing for simple inheritance + // Allow instantiation without initializing for simple inheritance // must use "new" keyword (the code above always passes args) if ( arguments.length ) { this._createWidget( options, element ); } }; - // extend with the existing constructor to carry over any static properties + + // Extend with the existing constructor to carry over any static properties $.extend( constructor, existingConstructor, { version: prototype.version, - // copy the object used to create the prototype in case we need to + + // Copy the object used to create the prototype in case we need to // redefine the widget later _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is + + // Track widgets that inherit from this widget in case this widget is // redefined after a widget inherits from it _childConstructors: [] - }); + } ); basePrototype = new base(); - // we need to make the options hash a property directly on the new instance + + // We need to make the options hash a property directly on the new instance // otherwise we'll modify the options hash on the prototype that we're // inheriting from basePrototype.options = $.widget.extend( {}, basePrototype.options ); @@ -397,17 +124,19 @@ $.widget = function( name, base, prototy proxiedPrototype[ prop ] = value; return; } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; + proxiedPrototype[ prop ] = ( function() { + function _super() { + return base.prototype[ prop ].apply( this, arguments ); + } + + function _superApply( args ) { + return base.prototype[ prop ].apply( this, args ); + } + return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; + var __super = this._super; + var __superApply = this._superApply; + var returnValue; this._super = _super; this._superApply = _superApply; @@ -419,19 +148,20 @@ $.widget = function( name, base, prototy return returnValue; }; - })(); - }); + } )(); + } ); constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix // always use the name + a colon as the prefix, e.g., draggable:start // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name + widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name }, proxiedPrototype, { constructor: constructor, namespace: namespace, widgetName: name, widgetFullName: fullName - }); + } ); // If this widget is being redefined then we need to find all widgets that // are inheriting from it and redefine all of them so that they inherit from @@ -441,11 +171,13 @@ $.widget = function( name, base, prototy $.each( existingConstructor._childConstructors, function( i, child ) { var childPrototype = child.prototype; - // redefine the child widget using the same prototype that was + // Redefine the child widget using the same prototype that was // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, + child._proto ); + } ); + + // Remove the list of existing child constructors from the old constructor // so the old child constructors can be garbage collected delete existingConstructor._childConstructors; } else { @@ -458,21 +190,25 @@ $.widget = function( name, base, prototy }; $.widget.extend = function( target ) { - var input = widget_slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; + var input = widgetSlice.call( arguments, 1 ); + var inputIndex = 0; + var inputLength = input.length; + var key; + var value; + for ( ; inputIndex < inputLength; inputIndex++ ) { for ( key in input[ inputIndex ] ) { value = input[ inputIndex ][ key ]; if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects if ( $.isPlainObject( value ) ) { target[ key ] = $.isPlainObject( target[ key ] ) ? $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects $.widget.extend( {}, value ); + // Copy everything else by reference } else { target[ key ] = value; @@ -486,41 +222,55 @@ $.widget.extend = function( target ) { $.widget.bridge = function( name, object ) { var fullName = object.prototype.widgetFullName || name; $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = widget_slice.call( arguments, 1 ), - returnValue = this; + var isMethodCall = typeof options === "string"; + var args = widgetSlice.call( arguments, 1 ); + var returnValue = this; if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( options === "instance" ) { - returnValue = instance; - return false; - } - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); + + // If this is an empty collection, we need to have the instance method + // return undefined instead of the jQuery instance + if ( !this.length && options === "instance" ) { + returnValue = undefined; + } else { + this.each( function() { + var methodValue; + var instance = $.data( this, fullName ); + + if ( options === "instance" ) { + returnValue = instance; + return false; + } + + if ( !instance ) { + return $.error( "cannot call methods on " + name + + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + + if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + + " widget instance" ); + } + + methodValue = instance[ options ].apply( instance, args ); + + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + } ); + } } else { // Allow multiple hashes to be passed on init if ( args.length ) { - options = $.widget.extend.apply( null, [ options ].concat(args) ); + options = $.widget.extend.apply( null, [ options ].concat( args ) ); } - this.each(function() { + this.each( function() { var instance = $.data( this, fullName ); if ( instance ) { instance.option( options || {} ); @@ -530,7 +280,7 @@ $.widget.bridge = function( name, object } else { $.data( this, fullName, new object( options, this ) ); } - }); + } ); } return returnValue; @@ -544,21 +294,25 @@ $.Widget.prototype = { widgetName: "widget", widgetEventPrefix: "", defaultElement: "<div>", + options: { + classes: {}, disabled: false, - // callbacks + // Callbacks create: null }, + _createWidget: function( options, element ) { element = $( element || this.defaultElement || this )[ 0 ]; this.element = $( element ); - this.uuid = widget_uuid++; + this.uuid = widgetUuid++; this.eventNamespace = "." + this.widgetName + this.uuid; this.bindings = $(); this.hoverable = $(); this.focusable = $(); + this.classesElementLookup = {}; if ( element !== this ) { $.data( element, this.widgetFullName, this ); @@ -568,13 +322,15 @@ $.Widget.prototype = { this.destroy(); } } - }); + } ); this.document = $( element.style ? - // element within the document + + // Element within the document element.ownerDocument : - // element is window or document + + // Element is window or document element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); } this.options = $.widget.extend( {}, @@ -583,36 +339,46 @@ $.Widget.prototype = { options ); this._create(); + + if ( this.options.disabled ) { + this._setOptionDisabled( this.options.disabled ); + } + this._trigger( "create", null, this._getCreateEventData() ); this._init(); }, - _getCreateOptions: $.noop, + + _getCreateOptions: function() { + return {}; + }, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, destroy: function() { + var that = this; + this._destroy(); - // we can probably remove the unbind calls in 2.0 + $.each( this.classesElementLookup, function( key, value ) { + that._removeClass( value, key ); + } ); + + // We can probably remove the unbind calls in 2.0 // all event bindings should go through this._on() this.element - .unbind( this.eventNamespace ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); + .off( this.eventNamespace ) + .removeData( this.widgetFullName ); this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); + .off( this.eventNamespace ) + .removeAttr( "aria-disabled" ); + + // Clean up events and states + this.bindings.off( this.eventNamespace ); }, + _destroy: $.noop, widget: function() { @@ -620,18 +386,20 @@ $.Widget.prototype = { }, option: function( key, value ) { - var options = key, - parts, - curOption, - i; + var options = key; + var parts; + var curOption; + var i; if ( arguments.length === 0 ) { - // don't return a reference to the internal hash + + // Don't return a reference to the internal hash return $.widget.extend( {}, this.options ); } if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + + // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } options = {}; parts = key.split( "." ); key = parts.shift(); @@ -658,6 +426,7 @@ $.Widget.prototype = { return this; }, + _setOptions: function( options ) { var key; @@ -667,42 +436,152 @@ $.Widget.prototype = { return this; }, + _setOption: function( key, value ) { + if ( key === "classes" ) { + this._setOptionClasses( value ); + } + this.options[ key ] = value; if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled", !!value ); - - // If the widget is becoming disabled, then nothing is interactive - if ( value ) { - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } + this._setOptionDisabled( value ); } return this; }, + _setOptionClasses: function( value ) { + var classKey, elements, currentElements; + + for ( classKey in value ) { + currentElements = this.classesElementLookup[ classKey ]; + if ( value[ classKey ] === this.options.classes[ classKey ] || + !currentElements || + !currentElements.length ) { + continue; + } + + // We are doing this to create a new jQuery object because the _removeClass() call + // on the next line is going to destroy the reference to the current elements being + // tracked. We need to save a copy of this collection so that we can add the new classes + // below. + elements = $( currentElements.get() ); + this._removeClass( currentElements, classKey ); + + // We don't use _addClass() here, because that uses this.options.classes + // for generating the string of classes. We want to use the value passed in from + // _setOption(), this is the new value of the classes option which was passed to + // _setOption(). We pass this value directly to _classes(). + elements.addClass( this._classes( { + element: elements, + keys: classKey, + classes: value, + add: true + } ) ); + } + }, + + _setOptionDisabled: function( value ) { + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this._removeClass( this.hoverable, null, "ui-state-hover" ); + this._removeClass( this.focusable, null, "ui-state-focus" ); + } + }, + enable: function() { - return this._setOptions({ disabled: false }); + return this._setOptions( { disabled: false } ); }, + disable: function() { - return this._setOptions({ disabled: true }); + return this._setOptions( { disabled: true } ); + }, + + _classes: function( options ) { + var full = []; + var that = this; + + options = $.extend( { + element: this.element, + classes: this.options.classes || {} + }, options ); + + function processClassString( classes, checkOption ) { + var current, i; + for ( i = 0; i < classes.length; i++ ) { + current = that.classesElementLookup[ classes[ i ] ] || $(); + if ( options.add ) { + current = $( $.unique( current.get().concat( options.element.get() ) ) ); + } else { + current = $( current.not( options.element ).get() ); + } + that.classesElementLookup[ classes[ i ] ] = current; + full.push( classes[ i ] ); + if ( checkOption && options.classes[ classes[ i ] ] ) { + full.push( options.classes[ classes[ i ] ] ); + } + } + } + + this._on( options.element, { + "remove": "_untrackClassesElement" + } ); + + if ( options.keys ) { + processClassString( options.keys.match( /\S+/g ) || [], true ); + } + if ( options.extra ) { + processClassString( options.extra.match( /\S+/g ) || [] ); + } + + return full.join( " " ); + }, + + _untrackClassesElement: function( event ) { + var that = this; + $.each( that.classesElementLookup, function( key, value ) { + if ( $.inArray( event.target, value ) !== -1 ) { + that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); + } + } ); + }, + + _removeClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, false ); + }, + + _addClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, true ); + }, + + _toggleClass: function( element, keys, extra, add ) { + add = ( typeof add === "boolean" ) ? add : extra; + var shift = ( typeof element === "string" || element === null ), + options = { + extra: shift ? keys : extra, + keys: shift ? element : keys, + element: shift ? this.element : element, + add: add + }; + options.element.toggleClass( this._classes( options ), add ); + return this; }, _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; + var delegateElement; + var instance = this; - // no suppressDisabledCheck flag, shuffle arguments + // No suppressDisabledCheck flag, shuffle arguments if ( typeof suppressDisabledCheck !== "boolean" ) { handlers = element; element = suppressDisabledCheck; suppressDisabledCheck = false; } - // no element argument, shuffle and use this.element + // No element argument, shuffle and use this.element if ( !handlers ) { handlers = element; element = this.element; @@ -714,39 +593,41 @@ $.Widget.prototype = { $.each( handlers, function( event, handler ) { function handlerProxy() { - // allow widgets to customize the disabled handling + + // Allow widgets to customize the disabled handling // - disabled as an array instead of boolean // - disabled class as method for disabling individual parts if ( !suppressDisabledCheck && ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { + $( this ).hasClass( "ui-state-disabled" ) ) ) { return; } return ( typeof handler === "string" ? instance[ handler ] : handler ) .apply( instance, arguments ); } - // copy the guid so direct unbinding works + // Copy the guid so direct unbinding works if ( typeof handler !== "string" ) { handlerProxy.guid = handler.guid = handler.guid || handlerProxy.guid || $.guid++; } - var match = event.match( /^([\w:-]*)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; + var match = event.match( /^([\w:-]*)\s*(.*)$/ ); + var eventName = match[ 1 ] + instance.eventNamespace; + var selector = match[ 2 ]; + if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); + delegateElement.on( eventName, selector, handlerProxy ); } else { - element.bind( eventName, handlerProxy ); + element.on( eventName, handlerProxy ); } - }); + } ); }, _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + + eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); + element.off( eventName ).off( eventName ); // Clear the stack to avoid memory leaks (#10056) this.bindings = $( this.bindings.not( element ).get() ); @@ -767,40 +648,41 @@ $.Widget.prototype = { this.hoverable = this.hoverable.add( element ); this._on( element, { mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); + this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); }, mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); + this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); } - }); + } ); }, _focusable: function( element ) { this.focusable = this.focusable.add( element ); this._on( element, { focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); + this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); }, focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); + this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); } - }); + } ); }, _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; + var prop, orig; + var callback = this.options[ type ]; data = data || {}; event = $.Event( event ); event.type = ( type === this.widgetEventPrefix ? type : this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element + + // The original event may come from any element // so we need to reset the target on the new event event.target = this.element[ 0 ]; - // copy original event properties over to the new event + // Copy original event properties over to the new event orig = event.originalEvent; if ( orig ) { for ( prop in orig ) { @@ -812,7 +694,7 @@ $.Widget.prototype = { this.element.trigger( event, data ); return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || + callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || event.isDefaultPrevented() ); } }; @@ -822,42 +704,47 @@ $.each( { show: "fadeIn", hide: "fadeOut if ( typeof options === "string" ) { options = { effect: options }; } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; + + var hasOptions; + var effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; if ( typeof options === "number" ) { options = { duration: options }; } + hasOptions = !$.isEmptyObject( options ); options.complete = callback; + if ( options.delay ) { element.delay( options.delay ); } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { element[ method ]( options ); } else if ( effectName !== method && element[ effectName ] ) { element[ effectName ]( options.duration, options.easing, callback ); } else { - element.queue(function( next ) { + element.queue( function( next ) { $( this )[ method ](); if ( callback ) { callback.call( element[ 0 ] ); } next(); - }); + } ); } }; -}); +} ); var widget = $.widget; /*! - * jQuery UI Position 1.11.4 + * jQuery UI Position 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors @@ -867,14 +754,17 @@ var widget = $.widget; * http://api.jqueryui.com/position/ */ -(function() { +//>>label: Position +//>>group: Core +//>>description: Positions elements relative to other elements. +//>>docs: http://api.jqueryui.com/position/ +//>>demos: http://jqueryui.com/position/ -$.ui = $.ui || {}; -var cachedScrollbarWidth, supportsOffsetFractions, +( function() { +var cachedScrollbarWidth, max = Math.max, abs = Math.abs, - round = Math.round, rhorizontal = /left|center|right/, rvertical = /top|center|bottom/, roffset = /[\+\-]\d+(\.[\d]+)?%?/, @@ -894,7 +784,7 @@ function parseCss( element, property ) { } function getDimensions( elem ) { - var raw = elem[0]; + var raw = elem[ 0 ]; if ( raw.nodeType === 9 ) { return { width: elem.width(), @@ -929,8 +819,10 @@ $.position = { return cachedScrollbarWidth; } var w1, w2, - div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), - innerDiv = div.children()[0]; + div = $( "<div " + + "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" + + "<div style='height:100px;width:auto;'></div></div>" ), + innerDiv = div.children()[ 0 ]; $( "body" ).append( div ); w1 = innerDiv.offsetWidth; @@ -939,12 +831,12 @@ $.position = { w2 = innerDiv.offsetWidth; if ( w1 === w2 ) { - w2 = div[0].clientWidth; + w2 = div[ 0 ].clientWidth; } div.remove(); - return (cachedScrollbarWidth = w1 - w2); + return ( cachedScrollbarWidth = w1 - w2 ); }, getScrollInfo: function( within ) { var overflowX = within.isWindow || within.isDocument ? "" : @@ -952,9 +844,9 @@ $.position = { overflowY = within.isWindow || within.isDocument ? "" : within.element.css( "overflow-y" ), hasOverflowX = overflowX === "scroll" || - ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), + ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), hasOverflowY = overflowY === "scroll" || - ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); + ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); return { width: hasOverflowY ? $.position.scrollbarWidth() : 0, height: hasOverflowX ? $.position.scrollbarWidth() : 0 @@ -962,20 +854,18 @@ $.position = { }, getWithinInfo: function( element ) { var withinElement = $( element || window ), - isWindow = $.isWindow( withinElement[0] ), - isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; + isWindow = $.isWindow( withinElement[ 0 ] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, + hasOffset = !isWindow && !isDocument; return { element: withinElement, isWindow: isWindow, isDocument: isDocument, - offset: withinElement.offset() || { left: 0, top: 0 }, + offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, scrollLeft: withinElement.scrollLeft(), scrollTop: withinElement.scrollTop(), - - // support: jQuery 1.6.x - // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows - width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), - height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() + width: withinElement.outerWidth(), + height: withinElement.outerHeight() }; } }; @@ -985,7 +875,7 @@ $.fn.position = function( options ) { return _position.apply( this, arguments ); } - // make a copy, we don't want to modify arguments + // Make a copy, we don't want to modify arguments options = $.extend( {}, options ); var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, @@ -996,24 +886,26 @@ $.fn.position = function( options ) { offsets = {}; dimensions = getDimensions( target ); - if ( target[0].preventDefault ) { - // force left top to allow flipping + if ( target[ 0 ].preventDefault ) { + + // Force left top to allow flipping options.at = "left top"; } targetWidth = dimensions.width; targetHeight = dimensions.height; targetOffset = dimensions.offset; - // clone to reuse original targetOffset later + + // Clone to reuse original targetOffset later basePosition = $.extend( {}, targetOffset ); - // force my and at to have valid horizontal and vertical positions + // Force my and at to have valid horizontal and vertical positions // if a value is missing or invalid, it will be converted to center $.each( [ "my", "at" ], function() { var pos = ( options[ this ] || "" ).split( " " ), horizontalOffset, verticalOffset; - if ( pos.length === 1) { + if ( pos.length === 1 ) { pos = rhorizontal.test( pos[ 0 ] ) ? pos.concat( [ "center" ] ) : rvertical.test( pos[ 0 ] ) ? @@ -1023,7 +915,7 @@ $.fn.position = function( options ) { pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; - // calculate offsets + // Calculate offsets horizontalOffset = roffset.exec( pos[ 0 ] ); verticalOffset = roffset.exec( pos[ 1 ] ); offsets[ this ] = [ @@ -1031,14 +923,14 @@ $.fn.position = function( options ) { verticalOffset ? verticalOffset[ 0 ] : 0 ]; - // reduce to just the positions without the offsets + // Reduce to just the positions without the offsets options[ this ] = [ rposition.exec( pos[ 0 ] )[ 0 ], rposition.exec( pos[ 1 ] )[ 0 ] ]; - }); + } ); - // normalize collision option + // Normalize collision option if ( collision.length === 1 ) { collision[ 1 ] = collision[ 0 ]; } @@ -1059,15 +951,17 @@ $.fn.position = function( options ) { basePosition.left += atOffset[ 0 ]; basePosition.top += atOffset[ 1 ]; - return this.each(function() { + return this.each( function() { var collisionPosition, using, elem = $( this ), elemWidth = elem.outerWidth(), elemHeight = elem.outerHeight(), marginLeft = parseCss( this, "marginLeft" ), marginTop = parseCss( this, "marginTop" ), - collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, - collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + + scrollInfo.height, position = $.extend( {}, basePosition ), myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); @@ -1086,12 +980,6 @@ $.fn.position = function( options ) { position.left += myOffset[ 0 ]; position.top += myOffset[ 1 ]; - // if the browser doesn't support fractions, then round for consistent results - if ( !supportsOffsetFractions ) { - position.left = round( position.left ); - position.top = round( position.top ); - } - collisionPosition = { marginLeft: marginLeft, marginTop: marginTop @@ -1112,12 +1000,13 @@ $.fn.position = function( options ) { at: options.at, within: within, elem: elem - }); + } ); } - }); + } ); if ( options.using ) { - // adds feedback as second argument to using callback, if present + + // Adds feedback as second argument to using callback, if present using = function( props ) { var left = targetOffset.left - position.left, right = left + targetWidth - elemWidth, @@ -1157,7 +1046,7 @@ $.fn.position = function( options ) { } elem.offset( $.extend( position, { using: using } ) ); - }); + } ); }; $.ui.position = { @@ -1171,16 +1060,20 @@ $.ui.position = { overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, newOverRight; - // element is wider than within + // Element is wider than within if ( data.collisionWidth > outerWidth ) { - // element is initially over the left side of within + + // Element is initially over the left side of within if ( overLeft > 0 && overRight <= 0 ) { - newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - + withinOffset; position.left += overLeft - newOverRight; - // element is initially over right side of within + + // Element is initially over right side of within } else if ( overRight > 0 && overLeft <= 0 ) { position.left = withinOffset; - // element is initially over both left and right sides of within + + // Element is initially over both left and right sides of within } else { if ( overLeft > overRight ) { position.left = withinOffset + outerWidth - data.collisionWidth; @@ -1188,13 +1081,16 @@ $.ui.position = { position.left = withinOffset; } } - // too far left -> align with left edge + + // Too far left -> align with left edge } else if ( overLeft > 0 ) { position.left += overLeft; - // too far right -> align with right edge + + // Too far right -> align with right edge } else if ( overRight > 0 ) { position.left -= overRight; - // adjust based on position and margin + + // Adjust based on position and margin } else { position.left = max( position.left - collisionPosLeft, position.left ); } @@ -1208,16 +1104,20 @@ $.ui.position = { overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, newOverBottom; - // element is taller than within + // Element is taller than within if ( data.collisionHeight > outerHeight ) { - // element is initially over the top of within + + // Element is initially over the top of within if ( overTop > 0 && overBottom <= 0 ) { - newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - + withinOffset; position.top += overTop - newOverBottom; - // element is initially over bottom of within + + // Element is initially over bottom of within } else if ( overBottom > 0 && overTop <= 0 ) { position.top = withinOffset; - // element is initially over both top and bottom of within + + // Element is initially over both top and bottom of within } else { if ( overTop > overBottom ) { position.top = withinOffset + outerHeight - data.collisionHeight; @@ -1225,13 +1125,16 @@ $.ui.position = { position.top = withinOffset; } } - // too far up -> align with top + + // Too far up -> align with top } else if ( overTop > 0 ) { position.top += overTop; - // too far down -> align with bottom edge + + // Too far down -> align with bottom edge } else if ( overBottom > 0 ) { position.top -= overBottom; - // adjust based on position and margin + + // Adjust based on position and margin } else { position.top = max( position.top - collisionPosTop, position.top ); } @@ -1261,12 +1164,14 @@ $.ui.position = { newOverLeft; if ( overLeft < 0 ) { - newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - + outerWidth - withinOffset; if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { position.left += myOffset + atOffset + offset; } } else if ( overRight > 0 ) { - newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + + atOffset + offset - offsetLeft; if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { position.left += myOffset + atOffset + offset; } @@ -1295,12 +1200,14 @@ $.ui.position = { newOverTop, newOverBottom; if ( overTop < 0 ) { - newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - + outerHeight - withinOffset; if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { position.top += myOffset + atOffset + offset; } } else if ( overBottom > 0 ) { - newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + + offset - offsetTop; if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { position.top += myOffset + atOffset + offset; } @@ -1319,79 +1226,152 @@ $.ui.position = { } }; -// fraction support test -(function() { - var testElement, testElementParent, testElementStyle, offsetLeft, i, - body = document.getElementsByTagName( "body" )[ 0 ], - div = document.createElement( "div" ); - - //Create a "fake body" for testing based on method used in jQuery.support - testElement = document.createElement( body ? "div" : "body" ); - testElementStyle = { - visibility: "hidden", - width: 0, - height: 0, - border: 0, - margin: 0, - background: "none" - }; - if ( body ) { - $.extend( testElementStyle, { - position: "absolute", - left: "-1000px", - top: "-1000px" - }); - } - for ( i in testElementStyle ) { - testElement.style[ i ] = testElementStyle[ i ]; - } - testElement.appendChild( div ); - testElementParent = body || document.documentElement; - testElementParent.insertBefore( testElement, testElementParent.firstChild ); - - div.style.cssText = "position: absolute; left: 10.7432222px;"; - - offsetLeft = $( div ).offset().left; - supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; - - testElement.innerHTML = ""; - testElementParent.removeChild( testElement ); -})(); - -})(); +} )(); var position = $.ui.position; /*! - * jQuery UI Menu 1.11.4 + * jQuery UI Keycode 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license + */ + +//>>label: Keycode +//>>group: Core +//>>description: Provide keycodes as keynames +//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ + + +var keycode = $.ui.keyCode = { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 +}; + + +/*! + * jQuery UI Unique ID 1.12.1 + * http://jqueryui.com + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + */ + +//>>label: uniqueId +//>>group: Core +//>>description: Functions to generate and remove uniqueId's +//>>docs: http://api.jqueryui.com/uniqueId/ + + + +var uniqueId = $.fn.extend( { + uniqueId: ( function() { + var uuid = 0; + + return function() { + return this.each( function() { + if ( !this.id ) { + this.id = "ui-id-" + ( ++uuid ); + } + } ); + }; + } )(), + + removeUniqueId: function() { + return this.each( function() { + if ( /^ui-id-\d+$/.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + } ); + } +} ); + + + +var safeActiveElement = $.ui.safeActiveElement = function( document ) { + var activeElement; + + // Support: IE 9 only + // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> + try { + activeElement = document.activeElement; + } catch ( error ) { + activeElement = document.body; + } + + // Support: IE 9 - 11 only + // IE may return null instead of an element + // Interestingly, this only seems to occur when NOT in an iframe + if ( !activeElement ) { + activeElement = document.body; + } + + // Support: IE 11 only + // IE11 returns a seemingly empty object in some cases when accessing + // document.activeElement from an <iframe> + if ( !activeElement.nodeName ) { + activeElement = document.body; + } + + return activeElement; +}; + + +/*! + * jQuery UI Menu 1.12.1 + * http://jqueryui.com * - * http://api.jqueryui.com/menu/ + * Copyright jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license */ +//>>label: Menu +//>>group: Widgets +//>>description: Creates nestable menus. +//>>docs: http://api.jqueryui.com/menu/ +//>>demos: http://jqueryui.com/menu/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/menu.css +//>>css.theme: ../../themes/base/theme.css + + -var menu = $.widget( "ui.menu", { - version: "1.11.4", +var widgetsMenu = $.widget( "ui.menu", { + version: "1.12.1", defaultElement: "<ul>", delay: 300, options: { icons: { - submenu: "ui-icon-carat-1-e" + submenu: "ui-icon-caret-1-e" }, items: "> *", menus: "ul", position: { - my: "left-1 top", + my: "left top", at: "right top" }, role: "menu", - // callbacks + // Callbacks blur: null, focus: null, select: null @@ -1405,20 +1385,14 @@ var menu = $.widget( "ui.menu", { this.mouseHandled = false; this.element .uniqueId() - .addClass( "ui-menu ui-widget ui-widget-content" ) - .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) - .attr({ + .attr( { role: this.options.role, tabIndex: 0 - }); + } ); - if ( this.options.disabled ) { - this.element - .addClass( "ui-state-disabled" ) - .attr( "aria-disabled", "true" ); - } + this._addClass( "ui-menu", "ui-widget ui-widget-content" ); + this._on( { - this._on({ // Prevent focus from sticking to links inside menu after clicking // them (focus should always stay on UL during navigation). "mousedown .ui-menu-item": function( event ) { @@ -1426,6 +1400,7 @@ var menu = $.widget( "ui.menu", { }, "click .ui-menu-item": function( event ) { var target = $( event.target ); + var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { this.select( event ); @@ -1437,7 +1412,8 @@ var menu = $.widget( "ui.menu", { // Open submenu on click if ( target.has( ".ui-menu" ).length ) { this.expand( event ); - } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) { + } else if ( !this.element.is( ":focus" ) && + active.closest( ".ui-menu" ).length ) { // Redirect focus to the menu this.element.trigger( "focus", [ true ] ); @@ -1451,21 +1427,32 @@ var menu = $.widget( "ui.menu", { } }, "mouseenter .ui-menu-item": function( event ) { + // Ignore mouse events while typeahead is active, see #10458. // Prevents focusing the wrong item when typeahead causes a scroll while the mouse // is over an item in the menu if ( this.previousFilter ) { return; } - var target = $( event.currentTarget ); + + var actualTarget = $( event.target ).closest( ".ui-menu-item" ), + target = $( event.currentTarget ); + + // Ignore bubbled events on parent items, see #11641 + if ( actualTarget[ 0 ] !== target[ 0 ] ) { + return; + } + // Remove ui-state-active class from siblings of the newly focused menu item // to avoid a jump caused by adjacent elements both having a class with a border - target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" ); + this._removeClass( target.siblings().children( ".ui-state-active" ), + null, "ui-state-active" ); this.focus( event, target ); }, mouseleave: "collapseAll", "mouseleave .ui-menu": "collapseAll", focus: function( event, keepActiveItem ) { + // If there's already an active item, keep it active // If not, activate the first item var item = this.active || this.element.find( this.options.items ).eq( 0 ); @@ -1475,14 +1462,18 @@ var menu = $.widget( "ui.menu", { } }, blur: function( event ) { - this._delay(function() { - if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { + this._delay( function() { + var notContained = !$.contains( + this.element[ 0 ], + $.ui.safeActiveElement( this.document[ 0 ] ) + ); + if ( notContained ) { this.collapseAll( event ); } - }); + } ); }, keydown: "_keydown" - }); + } ); this.refresh(); @@ -1496,43 +1487,31 @@ var menu = $.widget( "ui.menu", { // Reset the mouseHandled flag this.mouseHandled = false; } - }); + } ); }, _destroy: function() { + var items = this.element.find( ".ui-menu-item" ) + .removeAttr( "role aria-disabled" ), + submenus = items.children( ".ui-menu-item-wrapper" ) + .removeUniqueId() + .removeAttr( "tabIndex role aria-haspopup" ); + // Destroy (sub)menus this.element .removeAttr( "aria-activedescendant" ) .find( ".ui-menu" ).addBack() - .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" ) - .removeAttr( "role" ) - .removeAttr( "tabIndex" ) - .removeAttr( "aria-labelledby" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-disabled" ) + .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " + + "tabIndex" ) .removeUniqueId() .show(); - // Destroy menu items - this.element.find( ".ui-menu-item" ) - .removeClass( "ui-menu-item" ) - .removeAttr( "role" ) - .removeAttr( "aria-disabled" ) - .removeUniqueId() - .removeClass( "ui-state-hover" ) - .removeAttr( "tabIndex" ) - .removeAttr( "role" ) - .removeAttr( "aria-haspopup" ) - .children().each( function() { - var elem = $( this ); - if ( elem.data( "ui-menu-submenu-carat" ) ) { - elem.remove(); - } - }); - - // Destroy menu dividers - this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); + submenus.children().each( function() { + var elem = $( this ); + if ( elem.data( "ui-menu-submenu-caret" ) ) { + elem.remove(); + } + } ); }, _keydown: function( event ) { @@ -1576,9 +1555,12 @@ var menu = $.widget( "ui.menu", { default: preventDefault = false; prev = this.previousFilter || ""; - character = String.fromCharCode( event.keyCode ); skip = false; + // Support number pad values + character = event.keyCode >= 96 && event.keyCode <= 105 ? + ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode ); + clearTimeout( this.filterTimer ); if ( character === prev ) { @@ -1602,7 +1584,7 @@ var menu = $.widget( "ui.menu", { if ( match.length ) { this.focus( event, match ); this.previousFilter = character; - this.filterTimer = this._delay(function() { + this.filterTimer = this._delay( function() { delete this.previousFilter; }, 1000 ); } else { @@ -1616,8 +1598,8 @@ var menu = $.widget( "ui.menu", { }, _activate: function( event ) { - if ( !this.active.is( ".ui-state-disabled" ) ) { - if ( this.active.is( "[aria-haspopup='true']" ) ) { + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + if ( this.active.children( "[aria-haspopup='true']" ).length ) { this.expand( event ); } else { this.select( event ); @@ -1626,54 +1608,57 @@ var menu = $.widget( "ui.menu", { }, refresh: function() { - var menus, items, + var menus, items, newSubmenus, newItems, newWrappers, that = this, icon = this.options.icons.submenu, submenus = this.element.find( this.options.menus ); - this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ); + this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length ); // Initialize nested menus - submenus.filter( ":not(.ui-menu)" ) - .addClass( "ui-menu ui-widget ui-widget-content ui-front" ) + newSubmenus = submenus.filter( ":not(.ui-menu)" ) .hide() - .attr({ + .attr( { role: this.options.role, "aria-hidden": "true", "aria-expanded": "false" - }) - .each(function() { + } ) + .each( function() { var menu = $( this ), - item = menu.parent(), - submenuCarat = $( "<span>" ) - .addClass( "ui-menu-icon ui-icon " + icon ) - .data( "ui-menu-submenu-carat", true ); + item = menu.prev(), + submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true ); + that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon ); item .attr( "aria-haspopup", "true" ) - .prepend( submenuCarat ); + .prepend( submenuCaret ); menu.attr( "aria-labelledby", item.attr( "id" ) ); - }); + } ); + + this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" ); menus = submenus.add( this.element ); items = menus.find( this.options.items ); // Initialize menu-items containing spaces and/or dashes only as dividers - items.not( ".ui-menu-item" ).each(function() { + items.not( ".ui-menu-item" ).each( function() { var item = $( this ); if ( that._isDivider( item ) ) { - item.addClass( "ui-widget-content ui-menu-divider" ); + that._addClass( item, "ui-menu-divider", "ui-widget-content" ); } - }); + } ); // Don't refresh list items that are already adapted - items.not( ".ui-menu-item, .ui-menu-divider" ) - .addClass( "ui-menu-item" ) - .uniqueId() - .attr({ - tabIndex: -1, - role: this._itemRole() - }); + newItems = items.not( ".ui-menu-item, .ui-menu-divider" ); + newWrappers = newItems.children() + .not( ".ui-menu" ) + .uniqueId() + .attr( { + tabIndex: -1, + role: this._itemRole() + } ); + this._addClass( newItems, "ui-menu-item" ) + ._addClass( newWrappers, "ui-menu-item-wrapper" ); // Add aria-disabled attribute to any disabled menu item items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); @@ -1693,26 +1678,31 @@ var menu = $.widget( "ui.menu", { _setOption: function( key, value ) { if ( key === "icons" ) { - this.element.find( ".ui-menu-icon" ) - .removeClass( this.options.icons.submenu ) - .addClass( value.submenu ); - } - if ( key === "disabled" ) { - this.element - .toggleClass( "ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); + var icons = this.element.find( ".ui-menu-icon" ); + this._removeClass( icons, null, this.options.icons.submenu ) + ._addClass( icons, null, value.submenu ); } this._super( key, value ); }, + _setOptionDisabled: function( value ) { + this._super( value ); + + this.element.attr( "aria-disabled", String( value ) ); + this._toggleClass( null, "ui-state-disabled", !!value ); + }, + focus: function( event, item ) { - var nested, focused; + var nested, focused, activeParent; this.blur( event, event && event.type === "focus" ); this._scrollIntoView( item ); this.active = item.first(); - focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" ); + + focused = this.active.children( ".ui-menu-item-wrapper" ); + this._addClass( focused, null, "ui-state-active" ); + // Only update aria-activedescendant if there's a role // otherwise we assume focus is managed elsewhere if ( this.options.role ) { @@ -1720,22 +1710,23 @@ var menu = $.widget( "ui.menu", { } // Highlight active parent menu item, if any - this.active + activeParent = this.active .parent() - .closest( ".ui-menu-item" ) - .addClass( "ui-state-active" ); + .closest( ".ui-menu-item" ) + .children( ".ui-menu-item-wrapper" ); + this._addClass( activeParent, null, "ui-state-active" ); if ( event && event.type === "keydown" ) { this._close(); } else { - this.timer = this._delay(function() { + this.timer = this._delay( function() { this._close(); }, this.delay ); } nested = item.children( ".ui-menu" ); if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { - this._startOpening(nested); + this._startOpening( nested ); } this.activeMenu = item.parent(); @@ -1745,8 +1736,8 @@ var menu = $.widget( "ui.menu", { _scrollIntoView: function( item ) { var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; if ( this._hasScroll() ) { - borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; - paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; + borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0; + paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0; offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; scroll = this.activeMenu.scrollTop(); elementHeight = this.activeMenu.height(); @@ -1769,29 +1760,30 @@ var menu = $.widget( "ui.menu", { return; } - this.active.removeClass( "ui-state-focus" ); - this.active = null; + this._removeClass( this.active.children( ".ui-menu-item-wrapper" ), + null, "ui-state-active" ); this._trigger( "blur", event, { item: this.active } ); + this.active = null; }, _startOpening: function( submenu ) { clearTimeout( this.timer ); // Don't open if already open fixes a Firefox bug that caused a .5 pixel - // shift in the submenu position when mousing over the carat icon + // shift in the submenu position when mousing over the caret icon if ( submenu.attr( "aria-hidden" ) !== "true" ) { return; } - this.timer = this._delay(function() { + this.timer = this._delay( function() { this._close(); this._open( submenu ); }, this.delay ); }, _open: function( submenu ) { - var position = $.extend({ + var position = $.extend( { of: this.active }, this.options.position ); @@ -1809,12 +1801,14 @@ var menu = $.widget( "ui.menu", { collapseAll: function( event, all ) { clearTimeout( this.timer ); - this.timer = this._delay(function() { + this.timer = this._delay( function() { + // If we were passed an event, look for the submenu that contains the event var currentMenu = all ? this.element : $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); - // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway + // If we found no valid submenu ancestor, use the main menu to close all + // sub menus anyway if ( !currentMenu.length ) { currentMenu = this.element; } @@ -1822,6 +1816,10 @@ var menu = $.widget( "ui.menu", { this._close( currentMenu ); this.blur( event ); + + // Work around active item staying active after menu is blurred + this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" ); + this.activeMenu = currentMenu; }, this.delay ); }, @@ -1833,14 +1831,10 @@ var menu = $.widget( "ui.menu", { startMenu = this.active ? this.active.parent() : this.element; } - startMenu - .find( ".ui-menu" ) - .hide() - .attr( "aria-hidden", "true" ) - .attr( "aria-expanded", "false" ) - .end() - .find( ".ui-state-active" ).not( ".ui-state-focus" ) - .removeClass( "ui-state-active" ); + startMenu.find( ".ui-menu" ) + .hide() + .attr( "aria-hidden", "true" ) + .attr( "aria-expanded", "false" ); }, _closeOnDocumentClick: function( event ) { @@ -1866,16 +1860,16 @@ var menu = $.widget( "ui.menu", { var newItem = this.active && this.active .children( ".ui-menu " ) - .find( this.options.items ) - .first(); + .find( this.options.items ) + .first(); if ( newItem && newItem.length ) { this._open( newItem.parent() ); // Delay so Firefox will not hide activedescendant change in expanding submenu from AT - this._delay(function() { + this._delay( function() { this.focus( event, newItem ); - }); + } ); } }, @@ -1928,10 +1922,10 @@ var menu = $.widget( "ui.menu", { if ( this._hasScroll() ) { base = this.active.offset().top; height = this.element.height(); - this.active.nextAll( ".ui-menu-item" ).each(function() { + this.active.nextAll( ".ui-menu-item" ).each( function() { item = $( this ); return item.offset().top - base - height < 0; - }); + } ); this.focus( event, item ); } else { @@ -1952,10 +1946,10 @@ var menu = $.widget( "ui.menu", { if ( this._hasScroll() ) { base = this.active.offset().top; height = this.element.height(); - this.active.prevAll( ".ui-menu-item" ).each(function() { + this.active.prevAll( ".ui-menu-item" ).each( function() { item = $( this ); return item.offset().top - base + height > 0; - }); + } ); this.focus( event, item ); } else { @@ -1968,6 +1962,7 @@ var menu = $.widget( "ui.menu", { }, select: function( event ) { + // TODO: It should never be possible to not have an active item at this // point, but the tests don't trigger mouseenter before click. this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); @@ -1978,36 +1973,45 @@ var menu = $.widget( "ui.menu", { this._trigger( "select", event, ui ); }, - _filterMenuItems: function(character) { + _filterMenuItems: function( character ) { var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), regex = new RegExp( "^" + escapedCharacter, "i" ); return this.activeMenu .find( this.options.items ) - // Only match on items, not dividers or other content (#10571) - .filter( ".ui-menu-item" ) - .filter(function() { - return regex.test( $.trim( $( this ).text() ) ); - }); + // Only match on items, not dividers or other content (#10571) + .filter( ".ui-menu-item" ) + .filter( function() { + return regex.test( + $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) ); + } ); } -}); +} ); /*! - * jQuery UI Autocomplete 1.11.4 + * jQuery UI Autocomplete 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license - * - * http://api.jqueryui.com/autocomplete/ */ +//>>label: Autocomplete +//>>group: Widgets +//>>description: Lists suggested words as the user is typing. +//>>docs: http://api.jqueryui.com/autocomplete/ +//>>demos: http://jqueryui.com/autocomplete/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/autocomplete.css +//>>css.theme: ../../themes/base/theme.css + + $.widget( "ui.autocomplete", { - version: "1.11.4", + version: "1.12.1", defaultElement: "<input>", options: { appendTo: null, @@ -2021,7 +2025,7 @@ $.widget( "ui.autocomplete", { }, source: null, - // callbacks + // Callbacks change: null, close: null, focus: null, @@ -2035,6 +2039,7 @@ $.widget( "ui.autocomplete", { pending: 0, _create: function() { + // Some browsers only repeat keydown events, not keypress events, // so we use the suppressKeyPress flag to determine if we've already // handled the keydown event. #7269 @@ -2047,21 +2052,17 @@ $.widget( "ui.autocomplete", { isTextarea = nodeName === "textarea", isInput = nodeName === "input"; - this.isMultiLine = - // Textareas are always multi-line - isTextarea ? true : - // Inputs are always single-line, even if inside a contentEditable element - // IE also treats inputs as contentEditable - isInput ? false : - // All other element types are determined by whether or not they're contentEditable - this.element.prop( "isContentEditable" ); + // Textareas are always multi-line + // Inputs are always single-line, even if inside a contentEditable element + // IE also treats inputs as contentEditable + // All other element types are determined by whether or not they're contentEditable + this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element ); this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; this.isNewMenu = true; - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ); + this._addClass( "ui-autocomplete-input" ); + this.element.attr( "autocomplete", "off" ); this._on( this.element, { keydown: function( event ) { @@ -2094,8 +2095,10 @@ $.widget( "ui.autocomplete", { this._keyEvent( "next", event ); break; case keyCode.ENTER: + // when menu is open and has focus if ( this.menu.active ) { + // #6055 - Opera still allows the keypress to occur // which causes forms to submit suppressKeyPress = true; @@ -2114,6 +2117,7 @@ $.widget( "ui.autocomplete", { this._value( this.term ); } this.close( event ); + // Different browsers have different default behavior for escape // Single press can mean undo or clear // Double press in IE means clear the whole form @@ -2122,6 +2126,7 @@ $.widget( "ui.autocomplete", { break; default: suppressKeyPressRepeat = true; + // search timeout should be triggered before the input value is changed this._searchTimeout( event ); break; @@ -2139,7 +2144,7 @@ $.widget( "ui.autocomplete", { return; } - // replicate some key handlers to allow them to repeat in Firefox and Opera + // Replicate some key handlers to allow them to repeat in Firefox and Opera var keyCode = $.ui.keyCode; switch ( event.keyCode ) { case keyCode.PAGE_UP: @@ -2178,51 +2183,46 @@ $.widget( "ui.autocomplete", { this.close( event ); this._change( event ); } - }); + } ); this._initSource(); this.menu = $( "<ul>" ) - .addClass( "ui-autocomplete ui-front" ) .appendTo( this._appendTo() ) - .menu({ + .menu( { + // disable ARIA support, the live region takes care of that role: null - }) + } ) .hide() .menu( "instance" ); + this._addClass( this.menu.element, "ui-autocomplete", "ui-front" ); this._on( this.menu.element, { mousedown: function( event ) { + // prevent moving focus out of the text field event.preventDefault(); // IE doesn't prevent moving focus even with event.preventDefault() // so we set a flag to know when we should ignore the blur event this.cancelBlur = true; - this._delay(function() { + this._delay( function() { delete this.cancelBlur; - }); - // clicking on the scrollbar causes focus to shift to the body - // but we can't detect a mouseup or a click immediately afterward - // so we have to track the next mousedown and close the menu if - // the user clicks somewhere outside of the autocomplete - var menuElement = this.menu.element[ 0 ]; - if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { - this._delay(function() { - var that = this; - this.document.one( "mousedown", function( event ) { - if ( event.target !== that.element[ 0 ] && - event.target !== menuElement && - !$.contains( menuElement, event.target ) ) { - that.close(); - } - }); - }); - } + // Support: IE 8 only + // Right clicking a menu item or selecting text from the menu items will + // result in focus moving out of the input. However, we've already received + // and ignored the blur event because of the cancelBlur flag set above. So + // we restore focus to ensure that the menu closes properly based on the user's + // next actions. + if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { + this.element.trigger( "focus" ); + } + } ); }, menufocus: function( event, ui ) { var label, item; + // support: Firefox // Prevent accidental activation of menu items in Firefox (#7024 #9118) if ( this.isNewMenu ) { @@ -2232,7 +2232,7 @@ $.widget( "ui.autocomplete", { this.document.one( "mousemove", function() { $( event.target ).trigger( event.originalEvent ); - }); + } ); return; } @@ -2240,6 +2240,7 @@ $.widget( "ui.autocomplete", { item = ui.item.data( "ui-autocomplete-item" ); if ( false !== this._trigger( "focus", event, { item: item } ) ) { + // use value to match what will end up in the input, if it was a key event if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { this._value( item.value ); @@ -2257,22 +2258,24 @@ $.widget( "ui.autocomplete", { var item = ui.item.data( "ui-autocomplete-item" ), previous = this.previous; - // only trigger when focus was lost (click on menu) - if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { - this.element.focus(); + // Only trigger when focus was lost (click on menu) + if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { + this.element.trigger( "focus" ); this.previous = previous; + // #6109 - IE triggers two focus events and the second // is asynchronous, so we need to reset the previous // term synchronously and asynchronously :-( - this._delay(function() { + this._delay( function() { this.previous = previous; this.selectedItem = item; - }); + } ); } if ( false !== this._trigger( "select", event, { item: item } ) ) { this._value( item.value ); } + // reset the term after the select event // this allows custom select handling to work properly this.term = this._value(); @@ -2280,31 +2283,30 @@ $.widget( "ui.autocomplete", { this.close( event ); this.selectedItem = item; } - }); + } ); - this.liveRegion = $( "<span>", { - role: "status", - "aria-live": "assertive", - "aria-relevant": "additions" - }) - .addClass( "ui-helper-hidden-accessible" ) + this.liveRegion = $( "<div>", { + role: "status", + "aria-live": "assertive", + "aria-relevant": "additions" + } ) .appendTo( this.document[ 0 ].body ); - // turning off autocomplete prevents the browser from remembering the + this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); + + // Turning off autocomplete prevents the browser from remembering the // value when navigating through history, so we re-enable autocomplete // if the page is unloaded before the widget is destroyed. #7790 this._on( this.window, { beforeunload: function() { this.element.removeAttr( "autocomplete" ); } - }); + } ); }, _destroy: function() { clearTimeout( this.searching ); - this.element - .removeClass( "ui-autocomplete-input" ) - .removeAttr( "autocomplete" ); + this.element.removeAttr( "autocomplete" ); this.menu.element.remove(); this.liveRegion.remove(); }, @@ -2322,6 +2324,20 @@ $.widget( "ui.autocomplete", { } }, + _isEventTargetInWidget: function( event ) { + var menuElement = this.menu.element[ 0 ]; + + return event.target === this.element[ 0 ] || + event.target === menuElement || + $.contains( menuElement, event.target ); + }, + + _closeOnClickOutside: function( event ) { + if ( !this._isEventTargetInWidget( event ) ) { + this.close(); + } + }, + _appendTo: function() { var element = this.options.appendTo; @@ -2332,7 +2348,7 @@ $.widget( "ui.autocomplete", { } if ( !element || !element[ 0 ] ) { - element = this.element.closest( ".ui-front" ); + element = this.element.closest( ".ui-front, dialog" ); } if ( !element.length ) { @@ -2356,7 +2372,7 @@ $.widget( "ui.autocomplete", { if ( that.xhr ) { that.xhr.abort(); } - that.xhr = $.ajax({ + that.xhr = $.ajax( { url: url, data: request, dataType: "json", @@ -2364,9 +2380,9 @@ $.widget( "ui.autocomplete", { response( data ); }, error: function() { - response([]); + response( [] ); } - }); + } ); }; } else { this.source = this.options.source; @@ -2375,7 +2391,7 @@ $.widget( "ui.autocomplete", { _searchTimeout: function( event ) { clearTimeout( this.searching ); - this.searching = this._delay(function() { + this.searching = this._delay( function() { // Search if the value has changed, or if the user retypes the same value (see #7434) var equalValues = this.term === this._value(), @@ -2392,7 +2408,7 @@ $.widget( "ui.autocomplete", { search: function( value, event ) { value = value != null ? value : this._value(); - // always save the actual value, not the one passed as an argument + // Always save the actual value, not the one passed as an argument this.term = this._value(); if ( value.length < this.options.minLength ) { @@ -2408,7 +2424,7 @@ $.widget( "ui.autocomplete", { _search: function( value ) { this.pending++; - this.element.addClass( "ui-autocomplete-loading" ); + this._addClass( "ui-autocomplete-loading" ); this.cancelSearch = false; this.source( { term: value }, this._response() ); @@ -2417,14 +2433,14 @@ $.widget( "ui.autocomplete", { _response: function() { var index = ++this.requestIndex; - return $.proxy(function( content ) { + return $.proxy( function( content ) { if ( index === this.requestIndex ) { this.__response( content ); } this.pending--; if ( !this.pending ) { - this.element.removeClass( "ui-autocomplete-loading" ); + this._removeClass( "ui-autocomplete-loading" ); } }, this ); }, @@ -2438,6 +2454,7 @@ $.widget( "ui.autocomplete", { this._suggest( content ); this._trigger( "open" ); } else { + // use ._close() instead of .close() so we don't cancel future searches this._close(); } @@ -2449,6 +2466,10 @@ $.widget( "ui.autocomplete", { }, _close: function( event ) { + + // Remove the handler that closes the menu on outside clicks + this._off( this.document, "mousedown" ); + if ( this.menu.element.is( ":visible" ) ) { this.menu.element.hide(); this.menu.blur(); @@ -2464,6 +2485,7 @@ $.widget( "ui.autocomplete", { }, _normalize: function( items ) { + // assume all items have the right format when the first item is complete if ( items.length && items[ 0 ].label && items[ 0 ].value ) { return items; @@ -2478,8 +2500,8 @@ $.widget( "ui.autocomplete", { return $.extend( {}, item, { label: item.label || item.value, value: item.value || item.label - }); - }); + } ); + } ); }, _suggest: function( items ) { @@ -2488,21 +2510,27 @@ $.widget( "ui.autocomplete", { this.isNewMenu = true; this.menu.refresh(); - // size and position menu + // Size and position menu ul.show(); this._resizeMenu(); - ul.position( $.extend({ + ul.position( $.extend( { of: this.element }, this.options.position ) ); if ( this.options.autoFocus ) { this.menu.next(); } + + // Listen for interactions outside of the widget (#6642) + this._on( this.document, { + mousedown: "_closeOnClickOutside" + } ); }, _resizeMenu: function() { var ul = this.menu.element; ul.outerWidth( Math.max( + // Firefox wraps long text (possibly a rounding bug) // so we add 1px to avoid the wrapping (#7513) ul.width( "" ).outerWidth() + 1, @@ -2514,7 +2542,7 @@ $.widget( "ui.autocomplete", { var that = this; $.each( items, function( index, item ) { that._renderItemData( ul, item ); - }); + } ); }, _renderItemData: function( ul, item ) { @@ -2522,7 +2550,9 @@ $.widget( "ui.autocomplete", { }, _renderItem: function( ul, item ) { - return $( "<li>" ).text( item.label ).appendTo( ul ); + return $( "<li>" ) + .append( $( "<div>" ).text( item.label ) ) + .appendTo( ul ); }, _move: function( direction, event ) { @@ -2555,11 +2585,29 @@ $.widget( "ui.autocomplete", { if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { this._move( keyEvent, event ); - // prevents moving cursor to beginning/end of the text field in some browsers + // Prevents moving cursor to beginning/end of the text field in some browsers event.preventDefault(); } + }, + + // Support: Chrome <=50 + // We should be able to just use this.element.prop( "isContentEditable" ) + // but hidden elements always report false in Chrome. + // https://code.google.com/p/chromium/issues/detail?id=313082 + _isContentEditable: function( element ) { + if ( !element.length ) { + return false; + } + + var editable = element.prop( "contentEditable" ); + + if ( editable === "inherit" ) { + return this._isContentEditable( element.parent() ); + } + + return editable === "true"; } -}); +} ); $.extend( $.ui.autocomplete, { escapeRegex: function( value ) { @@ -2569,11 +2617,11 @@ $.extend( $.ui.autocomplete, { var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); return $.grep( array, function( value ) { return matcher.test( value.label || value.value || value ); - }); + } ); } -}); +} ); -// live region extension, adding a `messages` option +// Live region extension, adding a `messages` option // NOTE: This is an experimental API. We are still investigating // a full solution for string manipulation and internationalization. $.widget( "ui.autocomplete", $.ui.autocomplete, { @@ -2601,9 +2649,10 @@ $.widget( "ui.autocomplete", $.ui.autoco this.liveRegion.children().hide(); $( "<div>" ).text( message ).appendTo( this.liveRegion ); } -}); +} ); + +var widgetsAutocomplete = $.ui.autocomplete; -var autocomplete = $.ui.autocomplete;