var widgetUuid = 0; var widgetSlice = Array.prototype.slice;
$.cleanData = ( function( orig ) { returnfunction( elems ) { var events, elem, i; for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { try {
// Only trigger remove when necessary to save time
events = $._data( elem, "events" ); if ( events && events.remove ) {
$( elem ).triggerHandler( "remove" );
}
// 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 ]; var fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
$[ namespace ] = $[ namespace ] || {};
existingConstructor = $[ namespace ][ name ];
constructor = $[ namespace ][ name ] = function( options, element ) {
// Allow instantiation without "new" keyword if ( !this._createWidget ) { returnnew constructor( options, element );
}
// 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( constructor, existingConstructor, {
version: prototype.version,
// 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 // 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 // otherwise we'll modify the options hash on the prototype that we're // inheriting from
basePrototype.options = $.widget.extend( {}, basePrototype.options );
$.each( prototype, function( prop, value ) { if ( !$.isFunction( value ) ) {
proxiedPrototype[ prop ] = value; return;
}
proxiedPrototype[ prop ] = ( function() { function _super() { return base.prototype[ prop ].apply( this, arguments );
}
// 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
}, 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 // the new version of this widget. We're essentially trying to replace one // level in the prototype chain. if ( existingConstructor ) {
$.each( existingConstructor._childConstructors, function( i, child ) { var childPrototype = child.prototype;
// 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 // so the old child constructors can be garbage collected delete existingConstructor._childConstructors;
} else {
base._childConstructors.push( constructor );
}
$.widget.bridge( name, constructor );
return constructor;
};
$.widget.extend = function( target ) { 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 );
$.widget.bridge = function( name, object ) { var fullName = object.prototype.widgetFullName || name;
$.fn[ name ] = function( options ) { var isMethodCall = typeof options === "string"; var args = widgetSlice.call( arguments, 1 ); var returnValue = this;
if ( isMethodCall ) {
// 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 );
// We can probably remove the unbind calls in 2.0 // all event bindings should go through this._on() this.element
.off( this.eventNamespace )
.removeData( this.widgetFullName ); this.widget()
.off( this.eventNamespace )
.removeAttr( "aria-disabled" );
// Clean up events and states this.bindings.off( this.eventNamespace );
},
_destroy: $.noop,
widget: function() { returnthis.element;
},
option: function( key, value ) { var options = key; var parts; var curOption; var i;
if ( arguments.length === 0 ) {
// Don't return a reference to the internal hash return $.widget.extend( {}, this.options );
}
for ( key in options ) { this._setOption( key, options[ key ] );
}
returnthis;
},
_setOption: function( key, value ) { if ( key === "classes" ) { this._setOptionClasses( value );
}
this.options[ key ] = value;
if ( key === "disabled" ) { this._setOptionDisabled( value );
}
returnthis;
},
_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
} ) );
}
},
// 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" );
}
},
_on: function( suppressDisabledCheck, element, handlers ) { var delegateElement; var instance = this;
// No suppressDisabledCheck flag, shuffle arguments if ( typeof suppressDisabledCheck !== "boolean" ) {
handlers = element;
element = suppressDisabledCheck;
suppressDisabledCheck = false;
}
// No element argument, shuffle and use this.element if ( !handlers ) {
handlers = element;
element = this.element;
delegateElement = this.widget();
} else {
element = delegateElement = $( element ); this.bindings = this.bindings.add( element );
}
$.each( handlers, function( event, handler ) { function handlerProxy() {
// 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" ) ) ) { return;
} return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
// 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*(.*)$/ ); var eventName = match[ 1 ] + instance.eventNamespace; var selector = match[ 2 ];
_trigger: function( type, event, data ) { 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 // 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
orig = event.originalEvent; if ( orig ) { for ( prop in orig ) { if ( !( prop in event ) ) {
event[ prop ] = orig[ prop ];
}
}
}
// 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
basePosition = $.extend( {}, targetOffset );
// 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;
// Element is wider than within if ( data.collisionWidth > outerWidth ) {
// Element is initially over the left side of within if ( overLeft > 0 && overRight <= 0 ) {
newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
withinOffset;
position.left += overLeft - newOverRight;
// Element is initially over right side of within
} elseif ( overRight > 0 && overLeft <= 0 ) {
position.left = withinOffset;
// Element is initially over both left and right sides of within
} else { if ( overLeft > overRight ) {
position.left = withinOffset + outerWidth - data.collisionWidth;
} else {
position.left = withinOffset;
}
}
// Too far left -> align with left edge
} elseif ( overLeft > 0 ) {
position.left += overLeft;
// Too far right -> align with right edge
} elseif ( overRight > 0 ) {
position.left -= overRight;
// Adjust based on position and margin
} else {
position.left = max( position.left - collisionPosLeft, position.left );
}
},
top: function( position, data ) { var within = data.within,
withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
outerHeight = data.within.height,
collisionPosTop = position.top - data.collisionPosition.marginTop,
overTop = withinOffset - collisionPosTop,
overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
newOverBottom;
// Element is taller than within if ( data.collisionHeight > outerHeight ) {
// Element is initially over the top of within if ( overTop > 0 && overBottom <= 0 ) {
newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
withinOffset;
position.top += overTop - newOverBottom;
// Element is initially over bottom of within
} elseif ( overBottom > 0 && overTop <= 0 ) {
position.top = withinOffset;
// Element is initially over both top and bottom of within
} else { if ( overTop > overBottom ) {
position.top = withinOffset + outerHeight - data.collisionHeight;
} else {
position.top = withinOffset;
}
}
// Too far up -> align with top
} elseif ( overTop > 0 ) {
position.top += overTop;
// Too far down -> align with bottom edge
} elseif ( overBottom > 0 ) {
position.top -= overBottom;
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;
}
// Flag used to prevent firing of the click handler // as the event bubbles up through nested menus this.mouseHandled = false; this.element
.uniqueId()
.attr( {
role: this.options.role,
tabIndex: 0
} );
// 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 ) {
event.preventDefault();
}, "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 );
// Only set the mouseHandled flag if the event will bubble, see #9469. if ( !event.isPropagationStopped() ) { this.mouseHandled = true;
}
// Open submenu on click if ( target.has( ".ui-menu" ).length ) { this.expand( event );
} elseif ( !this.element.is( ":focus" ) &&
active.closest( ".ui-menu" ).length ) {
// Redirect focus to the menu this.element.trigger( "focus", [ true ] );
// If the active item is on the top level, let it stay active. // Otherwise, blur the active item since it is no longer visible. if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
clearTimeout( this.timer );
}
}
}
}, "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;
}
// 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 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 );
// Clicks outside of a menu collapse any open menus this._on( this.document, {
click: function( event ) { if ( this._closeOnDocumentClick( event ) ) { this.collapseAll( event );
}
// Reset the mouseHandled flag this.mouseHandled = false;
}
} );
},
switch ( event.keyCode ) { case $.ui.keyCode.PAGE_UP: this.previousPage( event ); break; case $.ui.keyCode.PAGE_DOWN: this.nextPage( event ); break; case $.ui.keyCode.HOME: this._move( "first", "first", event ); break; case $.ui.keyCode.END: this._move( "last", "last", event ); break; case $.ui.keyCode.UP: this.previous( event ); break; case $.ui.keyCode.DOWN: this.next( event ); break; case $.ui.keyCode.LEFT: this.collapse( event ); break; case $.ui.keyCode.RIGHT: if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { this.expand( event );
} break; case $.ui.keyCode.ENTER: case $.ui.keyCode.SPACE: this._activate( event ); break; case $.ui.keyCode.ESCAPE: this.collapse( event ); break; default:
preventDefault = false;
prev = this.previousFilter || "";
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 ) {
skip = true;
} else {
character = prev + character;
}
match = this._filterMenuItems( character );
match = skip && match.index( this.active.next() ) !== -1 ? this.active.nextAll( ".ui-menu-item" ) :
match;
// If no matches on the current filter, reset to the last character pressed // to move down the menu to the first item that starts with that character if ( !match.length ) {
character = String.fromCharCode( event.keyCode );
match = this._filterMenuItems( character );
}
// Only update aria-activedescendant if there's a role // otherwise we assume focus is managed elsewhere if ( this.options.role ) { this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
}
// Highlight active parent menu item, if any
activeParent = this.active
.parent()
.closest( ".ui-menu-item" )
.children( ".ui-menu-item-wrapper" ); this._addClass( activeParent, null, "ui-state-active" );
// Don't open if already open fixes a Firefox bug that caused a .5 pixel // shift in the submenu position when mousing over the caret icon if ( submenu.attr( "aria-hidden" ) !== "true" ) { return;
}
// 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 ( !currentMenu.length ) {
currentMenu = this.element;
}
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" );
// With no arguments, closes the currently active menu - if nothing is active // it closes all menus. If passed an argument, it will search for menus BELOW
_close: function( startMenu ) { if ( !startMenu ) {
startMenu = this.active ? this.active.parent() : this.element;
}
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.focus( event, newItem );
} );
}
},
// 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" ); var ui = { item: this.active }; if ( !this.active.has( ".ui-menu" ).length ) { this.collapseAll( event, true );
} this._trigger( "select", event, ui );
},
_filterMenuItems: function( character ) { var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
regex = new RegExp( "^" + escapedCharacter, "i" );
returnthis.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 ).children( ".ui-menu-item-wrapper" ).text() ) );
} );
}
} );
/*! * jQuery UI Autocomplete 1.12.1 * http://jqueryui.com * * Copyright jQuery Foundation and other contributors * Released under the MIT license. * http://jquery.org/license
*/
//>>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
// 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 // Unfortunately the code for & in keypress is the same as the up arrow, // so we use the suppressKeyPressRepeat flag to avoid handling keypress // events when we know the keydown event was used to modify the // search term. #7799 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
nodeName = this.element[ 0 ].nodeName.toLowerCase(),
isTextarea = nodeName === "textarea",
isInput = nodeName === "input";
// 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 );
suppressKeyPress = false;
suppressInput = false;
suppressKeyPressRepeat = false; var keyCode = $.ui.keyCode; switch ( event.keyCode ) { case keyCode.PAGE_UP:
suppressKeyPress = true; this._move( "previousPage", event ); break; case keyCode.PAGE_DOWN:
suppressKeyPress = true; this._move( "nextPage", event ); break; case keyCode.UP:
suppressKeyPress = true; this._keyEvent( "previous", event ); break; case keyCode.DOWN:
suppressKeyPress = true; 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;
event.preventDefault(); this.menu.select( event );
} break; case keyCode.TAB: if ( this.menu.active ) { this.menu.select( event );
} break; case keyCode.ESCAPE: if ( this.menu.element.is( ":visible" ) ) { if ( !this.isMultiLine ) { 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
event.preventDefault();
} break; default:
suppressKeyPressRepeat = true;
// search timeout should be triggered before the input value is changed this._searchTimeout( event ); break;
}
},
keypress: function( event ) { if ( suppressKeyPress ) {
suppressKeyPress = false; if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
event.preventDefault();
} return;
} if ( suppressKeyPressRepeat ) { return;
}
// Replicate some key handlers to allow them to repeat in Firefox and Opera var keyCode = $.ui.keyCode; switch ( event.keyCode ) { case keyCode.PAGE_UP: this._move( "previousPage", event ); break; case keyCode.PAGE_DOWN: this._move( "nextPage", event ); break; case keyCode.UP: this._keyEvent( "previous", event ); break; case keyCode.DOWN: this._keyEvent( "next", event ); break;
}
},
input: function( event ) { if ( suppressInput ) {
suppressInput = false;
event.preventDefault(); return;
} this._searchTimeout( event );
},
focus: function() { this.selectedItem = null; this.previous = this._value();
},
blur: function( event ) { if ( this.cancelBlur ) { deletethis.cancelBlur; return;
}
// 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() { deletethis.cancelBlur;
// 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 ) { this.isNewMenu = false; if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { this.menu.blur();
// 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 );
}
}
// Announce the value in the liveRegion
label = ui.item.attr( "aria-label" ) || item.value; if ( label && $.trim( label ).length ) { this.liveRegion.children().hide();
$( "
// 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.previous = previous; this.selectedItem = item;
} );
}
// 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" );
}
} );
},
// Search if the value has changed, or if the user retypes the same value (see #7434) var equalValues = this.term === this._value(),
menuVisible = this.menu.element.is( ":visible" ),
modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;