File indexing completed on 2025-05-04 05:29:38
0001 /*! jQuery UI - v1.12.1 - 2016-09-14 0002 * http://jqueryui.com 0003 * Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js 0004 * Copyright jQuery Foundation and other contributors; Licensed MIT */ 0005 0006 (function( factory ) { 0007 if ( typeof define === "function" && define.amd ) { 0008 0009 // AMD. Register as an anonymous module. 0010 define([ "jquery" ], factory ); 0011 } else { 0012 0013 // Browser globals 0014 factory( jQuery ); 0015 } 0016 }(function( $ ) { 0017 0018 $.ui = $.ui || {}; 0019 0020 var version = $.ui.version = "1.12.1"; 0021 0022 0023 /*! 0024 * jQuery UI Widget 1.12.1 0025 * http://jqueryui.com 0026 * 0027 * Copyright jQuery Foundation and other contributors 0028 * Released under the MIT license. 0029 * http://jquery.org/license 0030 */ 0031 0032 //>>label: Widget 0033 //>>group: Core 0034 //>>description: Provides a factory for creating stateful widgets with a common API. 0035 //>>docs: http://api.jqueryui.com/jQuery.widget/ 0036 //>>demos: http://jqueryui.com/widget/ 0037 0038 0039 0040 var widgetUuid = 0; 0041 var widgetSlice = Array.prototype.slice; 0042 0043 $.cleanData = ( function( orig ) { 0044 return function( elems ) { 0045 var events, elem, i; 0046 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { 0047 try { 0048 0049 // Only trigger remove when necessary to save time 0050 events = $._data( elem, "events" ); 0051 if ( events && events.remove ) { 0052 $( elem ).triggerHandler( "remove" ); 0053 } 0054 0055 // Http://bugs.jquery.com/ticket/8235 0056 } catch ( e ) {} 0057 } 0058 orig( elems ); 0059 }; 0060 } )( $.cleanData ); 0061 0062 $.widget = function( name, base, prototype ) { 0063 var existingConstructor, constructor, basePrototype; 0064 0065 // ProxiedPrototype allows the provided prototype to remain unmodified 0066 // so that it can be used as a mixin for multiple widgets (#8876) 0067 var proxiedPrototype = {}; 0068 0069 var namespace = name.split( "." )[ 0 ]; 0070 name = name.split( "." )[ 1 ]; 0071 var fullName = namespace + "-" + name; 0072 0073 if ( !prototype ) { 0074 prototype = base; 0075 base = $.Widget; 0076 } 0077 0078 if ( $.isArray( prototype ) ) { 0079 prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); 0080 } 0081 0082 // Create selector for plugin 0083 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 0084 return !!$.data( elem, fullName ); 0085 }; 0086 0087 $[ namespace ] = $[ namespace ] || {}; 0088 existingConstructor = $[ namespace ][ name ]; 0089 constructor = $[ namespace ][ name ] = function( options, element ) { 0090 0091 // Allow instantiation without "new" keyword 0092 if ( !this._createWidget ) { 0093 return new constructor( options, element ); 0094 } 0095 0096 // Allow instantiation without initializing for simple inheritance 0097 // must use "new" keyword (the code above always passes args) 0098 if ( arguments.length ) { 0099 this._createWidget( options, element ); 0100 } 0101 }; 0102 0103 // Extend with the existing constructor to carry over any static properties 0104 $.extend( constructor, existingConstructor, { 0105 version: prototype.version, 0106 0107 // Copy the object used to create the prototype in case we need to 0108 // redefine the widget later 0109 _proto: $.extend( {}, prototype ), 0110 0111 // Track widgets that inherit from this widget in case this widget is 0112 // redefined after a widget inherits from it 0113 _childConstructors: [] 0114 } ); 0115 0116 basePrototype = new base(); 0117 0118 // We need to make the options hash a property directly on the new instance 0119 // otherwise we'll modify the options hash on the prototype that we're 0120 // inheriting from 0121 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 0122 $.each( prototype, function( prop, value ) { 0123 if ( !$.isFunction( value ) ) { 0124 proxiedPrototype[ prop ] = value; 0125 return; 0126 } 0127 proxiedPrototype[ prop ] = ( function() { 0128 function _super() { 0129 return base.prototype[ prop ].apply( this, arguments ); 0130 } 0131 0132 function _superApply( args ) { 0133 return base.prototype[ prop ].apply( this, args ); 0134 } 0135 0136 return function() { 0137 var __super = this._super; 0138 var __superApply = this._superApply; 0139 var returnValue; 0140 0141 this._super = _super; 0142 this._superApply = _superApply; 0143 0144 returnValue = value.apply( this, arguments ); 0145 0146 this._super = __super; 0147 this._superApply = __superApply; 0148 0149 return returnValue; 0150 }; 0151 } )(); 0152 } ); 0153 constructor.prototype = $.widget.extend( basePrototype, { 0154 0155 // TODO: remove support for widgetEventPrefix 0156 // always use the name + a colon as the prefix, e.g., draggable:start 0157 // don't prefix for widgets that aren't DOM-based 0158 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name 0159 }, proxiedPrototype, { 0160 constructor: constructor, 0161 namespace: namespace, 0162 widgetName: name, 0163 widgetFullName: fullName 0164 } ); 0165 0166 // If this widget is being redefined then we need to find all widgets that 0167 // are inheriting from it and redefine all of them so that they inherit from 0168 // the new version of this widget. We're essentially trying to replace one 0169 // level in the prototype chain. 0170 if ( existingConstructor ) { 0171 $.each( existingConstructor._childConstructors, function( i, child ) { 0172 var childPrototype = child.prototype; 0173 0174 // Redefine the child widget using the same prototype that was 0175 // originally used, but inherit from the new version of the base 0176 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, 0177 child._proto ); 0178 } ); 0179 0180 // Remove the list of existing child constructors from the old constructor 0181 // so the old child constructors can be garbage collected 0182 delete existingConstructor._childConstructors; 0183 } else { 0184 base._childConstructors.push( constructor ); 0185 } 0186 0187 $.widget.bridge( name, constructor ); 0188 0189 return constructor; 0190 }; 0191 0192 $.widget.extend = function( target ) { 0193 var input = widgetSlice.call( arguments, 1 ); 0194 var inputIndex = 0; 0195 var inputLength = input.length; 0196 var key; 0197 var value; 0198 0199 for ( ; inputIndex < inputLength; inputIndex++ ) { 0200 for ( key in input[ inputIndex ] ) { 0201 value = input[ inputIndex ][ key ]; 0202 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 0203 0204 // Clone objects 0205 if ( $.isPlainObject( value ) ) { 0206 target[ key ] = $.isPlainObject( target[ key ] ) ? 0207 $.widget.extend( {}, target[ key ], value ) : 0208 0209 // Don't extend strings, arrays, etc. with objects 0210 $.widget.extend( {}, value ); 0211 0212 // Copy everything else by reference 0213 } else { 0214 target[ key ] = value; 0215 } 0216 } 0217 } 0218 } 0219 return target; 0220 }; 0221 0222 $.widget.bridge = function( name, object ) { 0223 var fullName = object.prototype.widgetFullName || name; 0224 $.fn[ name ] = function( options ) { 0225 var isMethodCall = typeof options === "string"; 0226 var args = widgetSlice.call( arguments, 1 ); 0227 var returnValue = this; 0228 0229 if ( isMethodCall ) { 0230 0231 // If this is an empty collection, we need to have the instance method 0232 // return undefined instead of the jQuery instance 0233 if ( !this.length && options === "instance" ) { 0234 returnValue = undefined; 0235 } else { 0236 this.each( function() { 0237 var methodValue; 0238 var instance = $.data( this, fullName ); 0239 0240 if ( options === "instance" ) { 0241 returnValue = instance; 0242 return false; 0243 } 0244 0245 if ( !instance ) { 0246 return $.error( "cannot call methods on " + name + 0247 " prior to initialization; " + 0248 "attempted to call method '" + options + "'" ); 0249 } 0250 0251 if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { 0252 return $.error( "no such method '" + options + "' for " + name + 0253 " widget instance" ); 0254 } 0255 0256 methodValue = instance[ options ].apply( instance, args ); 0257 0258 if ( methodValue !== instance && methodValue !== undefined ) { 0259 returnValue = methodValue && methodValue.jquery ? 0260 returnValue.pushStack( methodValue.get() ) : 0261 methodValue; 0262 return false; 0263 } 0264 } ); 0265 } 0266 } else { 0267 0268 // Allow multiple hashes to be passed on init 0269 if ( args.length ) { 0270 options = $.widget.extend.apply( null, [ options ].concat( args ) ); 0271 } 0272 0273 this.each( function() { 0274 var instance = $.data( this, fullName ); 0275 if ( instance ) { 0276 instance.option( options || {} ); 0277 if ( instance._init ) { 0278 instance._init(); 0279 } 0280 } else { 0281 $.data( this, fullName, new object( options, this ) ); 0282 } 0283 } ); 0284 } 0285 0286 return returnValue; 0287 }; 0288 }; 0289 0290 $.Widget = function( /* options, element */ ) {}; 0291 $.Widget._childConstructors = []; 0292 0293 $.Widget.prototype = { 0294 widgetName: "widget", 0295 widgetEventPrefix: "", 0296 defaultElement: "<div>", 0297 0298 options: { 0299 classes: {}, 0300 disabled: false, 0301 0302 // Callbacks 0303 create: null 0304 }, 0305 0306 _createWidget: function( options, element ) { 0307 element = $( element || this.defaultElement || this )[ 0 ]; 0308 this.element = $( element ); 0309 this.uuid = widgetUuid++; 0310 this.eventNamespace = "." + this.widgetName + this.uuid; 0311 0312 this.bindings = $(); 0313 this.hoverable = $(); 0314 this.focusable = $(); 0315 this.classesElementLookup = {}; 0316 0317 if ( element !== this ) { 0318 $.data( element, this.widgetFullName, this ); 0319 this._on( true, this.element, { 0320 remove: function( event ) { 0321 if ( event.target === element ) { 0322 this.destroy(); 0323 } 0324 } 0325 } ); 0326 this.document = $( element.style ? 0327 0328 // Element within the document 0329 element.ownerDocument : 0330 0331 // Element is window or document 0332 element.document || element ); 0333 this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); 0334 } 0335 0336 this.options = $.widget.extend( {}, 0337 this.options, 0338 this._getCreateOptions(), 0339 options ); 0340 0341 this._create(); 0342 0343 if ( this.options.disabled ) { 0344 this._setOptionDisabled( this.options.disabled ); 0345 } 0346 0347 this._trigger( "create", null, this._getCreateEventData() ); 0348 this._init(); 0349 }, 0350 0351 _getCreateOptions: function() { 0352 return {}; 0353 }, 0354 0355 _getCreateEventData: $.noop, 0356 0357 _create: $.noop, 0358 0359 _init: $.noop, 0360 0361 destroy: function() { 0362 var that = this; 0363 0364 this._destroy(); 0365 $.each( this.classesElementLookup, function( key, value ) { 0366 that._removeClass( value, key ); 0367 } ); 0368 0369 // We can probably remove the unbind calls in 2.0 0370 // all event bindings should go through this._on() 0371 this.element 0372 .off( this.eventNamespace ) 0373 .removeData( this.widgetFullName ); 0374 this.widget() 0375 .off( this.eventNamespace ) 0376 .removeAttr( "aria-disabled" ); 0377 0378 // Clean up events and states 0379 this.bindings.off( this.eventNamespace ); 0380 }, 0381 0382 _destroy: $.noop, 0383 0384 widget: function() { 0385 return this.element; 0386 }, 0387 0388 option: function( key, value ) { 0389 var options = key; 0390 var parts; 0391 var curOption; 0392 var i; 0393 0394 if ( arguments.length === 0 ) { 0395 0396 // Don't return a reference to the internal hash 0397 return $.widget.extend( {}, this.options ); 0398 } 0399 0400 if ( typeof key === "string" ) { 0401 0402 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 0403 options = {}; 0404 parts = key.split( "." ); 0405 key = parts.shift(); 0406 if ( parts.length ) { 0407 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 0408 for ( i = 0; i < parts.length - 1; i++ ) { 0409 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 0410 curOption = curOption[ parts[ i ] ]; 0411 } 0412 key = parts.pop(); 0413 if ( arguments.length === 1 ) { 0414 return curOption[ key ] === undefined ? null : curOption[ key ]; 0415 } 0416 curOption[ key ] = value; 0417 } else { 0418 if ( arguments.length === 1 ) { 0419 return this.options[ key ] === undefined ? null : this.options[ key ]; 0420 } 0421 options[ key ] = value; 0422 } 0423 } 0424 0425 this._setOptions( options ); 0426 0427 return this; 0428 }, 0429 0430 _setOptions: function( options ) { 0431 var key; 0432 0433 for ( key in options ) { 0434 this._setOption( key, options[ key ] ); 0435 } 0436 0437 return this; 0438 }, 0439 0440 _setOption: function( key, value ) { 0441 if ( key === "classes" ) { 0442 this._setOptionClasses( value ); 0443 } 0444 0445 this.options[ key ] = value; 0446 0447 if ( key === "disabled" ) { 0448 this._setOptionDisabled( value ); 0449 } 0450 0451 return this; 0452 }, 0453 0454 _setOptionClasses: function( value ) { 0455 var classKey, elements, currentElements; 0456 0457 for ( classKey in value ) { 0458 currentElements = this.classesElementLookup[ classKey ]; 0459 if ( value[ classKey ] === this.options.classes[ classKey ] || 0460 !currentElements || 0461 !currentElements.length ) { 0462 continue; 0463 } 0464 0465 // We are doing this to create a new jQuery object because the _removeClass() call 0466 // on the next line is going to destroy the reference to the current elements being 0467 // tracked. We need to save a copy of this collection so that we can add the new classes 0468 // below. 0469 elements = $( currentElements.get() ); 0470 this._removeClass( currentElements, classKey ); 0471 0472 // We don't use _addClass() here, because that uses this.options.classes 0473 // for generating the string of classes. We want to use the value passed in from 0474 // _setOption(), this is the new value of the classes option which was passed to 0475 // _setOption(). We pass this value directly to _classes(). 0476 elements.addClass( this._classes( { 0477 element: elements, 0478 keys: classKey, 0479 classes: value, 0480 add: true 0481 } ) ); 0482 } 0483 }, 0484 0485 _setOptionDisabled: function( value ) { 0486 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); 0487 0488 // If the widget is becoming disabled, then nothing is interactive 0489 if ( value ) { 0490 this._removeClass( this.hoverable, null, "ui-state-hover" ); 0491 this._removeClass( this.focusable, null, "ui-state-focus" ); 0492 } 0493 }, 0494 0495 enable: function() { 0496 return this._setOptions( { disabled: false } ); 0497 }, 0498 0499 disable: function() { 0500 return this._setOptions( { disabled: true } ); 0501 }, 0502 0503 _classes: function( options ) { 0504 var full = []; 0505 var that = this; 0506 0507 options = $.extend( { 0508 element: this.element, 0509 classes: this.options.classes || {} 0510 }, options ); 0511 0512 function processClassString( classes, checkOption ) { 0513 var current, i; 0514 for ( i = 0; i < classes.length; i++ ) { 0515 current = that.classesElementLookup[ classes[ i ] ] || $(); 0516 if ( options.add ) { 0517 current = $( $.unique( current.get().concat( options.element.get() ) ) ); 0518 } else { 0519 current = $( current.not( options.element ).get() ); 0520 } 0521 that.classesElementLookup[ classes[ i ] ] = current; 0522 full.push( classes[ i ] ); 0523 if ( checkOption && options.classes[ classes[ i ] ] ) { 0524 full.push( options.classes[ classes[ i ] ] ); 0525 } 0526 } 0527 } 0528 0529 this._on( options.element, { 0530 "remove": "_untrackClassesElement" 0531 } ); 0532 0533 if ( options.keys ) { 0534 processClassString( options.keys.match( /\S+/g ) || [], true ); 0535 } 0536 if ( options.extra ) { 0537 processClassString( options.extra.match( /\S+/g ) || [] ); 0538 } 0539 0540 return full.join( " " ); 0541 }, 0542 0543 _untrackClassesElement: function( event ) { 0544 var that = this; 0545 $.each( that.classesElementLookup, function( key, value ) { 0546 if ( $.inArray( event.target, value ) !== -1 ) { 0547 that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); 0548 } 0549 } ); 0550 }, 0551 0552 _removeClass: function( element, keys, extra ) { 0553 return this._toggleClass( element, keys, extra, false ); 0554 }, 0555 0556 _addClass: function( element, keys, extra ) { 0557 return this._toggleClass( element, keys, extra, true ); 0558 }, 0559 0560 _toggleClass: function( element, keys, extra, add ) { 0561 add = ( typeof add === "boolean" ) ? add : extra; 0562 var shift = ( typeof element === "string" || element === null ), 0563 options = { 0564 extra: shift ? keys : extra, 0565 keys: shift ? element : keys, 0566 element: shift ? this.element : element, 0567 add: add 0568 }; 0569 options.element.toggleClass( this._classes( options ), add ); 0570 return this; 0571 }, 0572 0573 _on: function( suppressDisabledCheck, element, handlers ) { 0574 var delegateElement; 0575 var instance = this; 0576 0577 // No suppressDisabledCheck flag, shuffle arguments 0578 if ( typeof suppressDisabledCheck !== "boolean" ) { 0579 handlers = element; 0580 element = suppressDisabledCheck; 0581 suppressDisabledCheck = false; 0582 } 0583 0584 // No element argument, shuffle and use this.element 0585 if ( !handlers ) { 0586 handlers = element; 0587 element = this.element; 0588 delegateElement = this.widget(); 0589 } else { 0590 element = delegateElement = $( element ); 0591 this.bindings = this.bindings.add( element ); 0592 } 0593 0594 $.each( handlers, function( event, handler ) { 0595 function handlerProxy() { 0596 0597 // Allow widgets to customize the disabled handling 0598 // - disabled as an array instead of boolean 0599 // - disabled class as method for disabling individual parts 0600 if ( !suppressDisabledCheck && 0601 ( instance.options.disabled === true || 0602 $( this ).hasClass( "ui-state-disabled" ) ) ) { 0603 return; 0604 } 0605 return ( typeof handler === "string" ? instance[ handler ] : handler ) 0606 .apply( instance, arguments ); 0607 } 0608 0609 // Copy the guid so direct unbinding works 0610 if ( typeof handler !== "string" ) { 0611 handlerProxy.guid = handler.guid = 0612 handler.guid || handlerProxy.guid || $.guid++; 0613 } 0614 0615 var match = event.match( /^([\w:-]*)\s*(.*)$/ ); 0616 var eventName = match[ 1 ] + instance.eventNamespace; 0617 var selector = match[ 2 ]; 0618 0619 if ( selector ) { 0620 delegateElement.on( eventName, selector, handlerProxy ); 0621 } else { 0622 element.on( eventName, handlerProxy ); 0623 } 0624 } ); 0625 }, 0626 0627 _off: function( element, eventName ) { 0628 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + 0629 this.eventNamespace; 0630 element.off( eventName ).off( eventName ); 0631 0632 // Clear the stack to avoid memory leaks (#10056) 0633 this.bindings = $( this.bindings.not( element ).get() ); 0634 this.focusable = $( this.focusable.not( element ).get() ); 0635 this.hoverable = $( this.hoverable.not( element ).get() ); 0636 }, 0637 0638 _delay: function( handler, delay ) { 0639 function handlerProxy() { 0640 return ( typeof handler === "string" ? instance[ handler ] : handler ) 0641 .apply( instance, arguments ); 0642 } 0643 var instance = this; 0644 return setTimeout( handlerProxy, delay || 0 ); 0645 }, 0646 0647 _hoverable: function( element ) { 0648 this.hoverable = this.hoverable.add( element ); 0649 this._on( element, { 0650 mouseenter: function( event ) { 0651 this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); 0652 }, 0653 mouseleave: function( event ) { 0654 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); 0655 } 0656 } ); 0657 }, 0658 0659 _focusable: function( element ) { 0660 this.focusable = this.focusable.add( element ); 0661 this._on( element, { 0662 focusin: function( event ) { 0663 this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); 0664 }, 0665 focusout: function( event ) { 0666 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); 0667 } 0668 } ); 0669 }, 0670 0671 _trigger: function( type, event, data ) { 0672 var prop, orig; 0673 var callback = this.options[ type ]; 0674 0675 data = data || {}; 0676 event = $.Event( event ); 0677 event.type = ( type === this.widgetEventPrefix ? 0678 type : 0679 this.widgetEventPrefix + type ).toLowerCase(); 0680 0681 // The original event may come from any element 0682 // so we need to reset the target on the new event 0683 event.target = this.element[ 0 ]; 0684 0685 // Copy original event properties over to the new event 0686 orig = event.originalEvent; 0687 if ( orig ) { 0688 for ( prop in orig ) { 0689 if ( !( prop in event ) ) { 0690 event[ prop ] = orig[ prop ]; 0691 } 0692 } 0693 } 0694 0695 this.element.trigger( event, data ); 0696 return !( $.isFunction( callback ) && 0697 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || 0698 event.isDefaultPrevented() ); 0699 } 0700 }; 0701 0702 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 0703 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 0704 if ( typeof options === "string" ) { 0705 options = { effect: options }; 0706 } 0707 0708 var hasOptions; 0709 var effectName = !options ? 0710 method : 0711 options === true || typeof options === "number" ? 0712 defaultEffect : 0713 options.effect || defaultEffect; 0714 0715 options = options || {}; 0716 if ( typeof options === "number" ) { 0717 options = { duration: options }; 0718 } 0719 0720 hasOptions = !$.isEmptyObject( options ); 0721 options.complete = callback; 0722 0723 if ( options.delay ) { 0724 element.delay( options.delay ); 0725 } 0726 0727 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 0728 element[ method ]( options ); 0729 } else if ( effectName !== method && element[ effectName ] ) { 0730 element[ effectName ]( options.duration, options.easing, callback ); 0731 } else { 0732 element.queue( function( next ) { 0733 $( this )[ method ](); 0734 if ( callback ) { 0735 callback.call( element[ 0 ] ); 0736 } 0737 next(); 0738 } ); 0739 } 0740 }; 0741 } ); 0742 0743 var widget = $.widget; 0744 0745 0746 /*! 0747 * jQuery UI Position 1.12.1 0748 * http://jqueryui.com 0749 * 0750 * Copyright jQuery Foundation and other contributors 0751 * Released under the MIT license. 0752 * http://jquery.org/license 0753 * 0754 * http://api.jqueryui.com/position/ 0755 */ 0756 0757 //>>label: Position 0758 //>>group: Core 0759 //>>description: Positions elements relative to other elements. 0760 //>>docs: http://api.jqueryui.com/position/ 0761 //>>demos: http://jqueryui.com/position/ 0762 0763 0764 ( function() { 0765 var cachedScrollbarWidth, 0766 max = Math.max, 0767 abs = Math.abs, 0768 rhorizontal = /left|center|right/, 0769 rvertical = /top|center|bottom/, 0770 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 0771 rposition = /^\w+/, 0772 rpercent = /%$/, 0773 _position = $.fn.position; 0774 0775 function getOffsets( offsets, width, height ) { 0776 return [ 0777 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 0778 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 0779 ]; 0780 } 0781 0782 function parseCss( element, property ) { 0783 return parseInt( $.css( element, property ), 10 ) || 0; 0784 } 0785 0786 function getDimensions( elem ) { 0787 var raw = elem[ 0 ]; 0788 if ( raw.nodeType === 9 ) { 0789 return { 0790 width: elem.width(), 0791 height: elem.height(), 0792 offset: { top: 0, left: 0 } 0793 }; 0794 } 0795 if ( $.isWindow( raw ) ) { 0796 return { 0797 width: elem.width(), 0798 height: elem.height(), 0799 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 0800 }; 0801 } 0802 if ( raw.preventDefault ) { 0803 return { 0804 width: 0, 0805 height: 0, 0806 offset: { top: raw.pageY, left: raw.pageX } 0807 }; 0808 } 0809 return { 0810 width: elem.outerWidth(), 0811 height: elem.outerHeight(), 0812 offset: elem.offset() 0813 }; 0814 } 0815 0816 $.position = { 0817 scrollbarWidth: function() { 0818 if ( cachedScrollbarWidth !== undefined ) { 0819 return cachedScrollbarWidth; 0820 } 0821 var w1, w2, 0822 div = $( "<div " + 0823 "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" + 0824 "<div style='height:100px;width:auto;'></div></div>" ), 0825 innerDiv = div.children()[ 0 ]; 0826 0827 $( "body" ).append( div ); 0828 w1 = innerDiv.offsetWidth; 0829 div.css( "overflow", "scroll" ); 0830 0831 w2 = innerDiv.offsetWidth; 0832 0833 if ( w1 === w2 ) { 0834 w2 = div[ 0 ].clientWidth; 0835 } 0836 0837 div.remove(); 0838 0839 return ( cachedScrollbarWidth = w1 - w2 ); 0840 }, 0841 getScrollInfo: function( within ) { 0842 var overflowX = within.isWindow || within.isDocument ? "" : 0843 within.element.css( "overflow-x" ), 0844 overflowY = within.isWindow || within.isDocument ? "" : 0845 within.element.css( "overflow-y" ), 0846 hasOverflowX = overflowX === "scroll" || 0847 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), 0848 hasOverflowY = overflowY === "scroll" || 0849 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); 0850 return { 0851 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 0852 height: hasOverflowX ? $.position.scrollbarWidth() : 0 0853 }; 0854 }, 0855 getWithinInfo: function( element ) { 0856 var withinElement = $( element || window ), 0857 isWindow = $.isWindow( withinElement[ 0 ] ), 0858 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, 0859 hasOffset = !isWindow && !isDocument; 0860 return { 0861 element: withinElement, 0862 isWindow: isWindow, 0863 isDocument: isDocument, 0864 offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, 0865 scrollLeft: withinElement.scrollLeft(), 0866 scrollTop: withinElement.scrollTop(), 0867 width: withinElement.outerWidth(), 0868 height: withinElement.outerHeight() 0869 }; 0870 } 0871 }; 0872 0873 $.fn.position = function( options ) { 0874 if ( !options || !options.of ) { 0875 return _position.apply( this, arguments ); 0876 } 0877 0878 // Make a copy, we don't want to modify arguments 0879 options = $.extend( {}, options ); 0880 0881 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 0882 target = $( options.of ), 0883 within = $.position.getWithinInfo( options.within ), 0884 scrollInfo = $.position.getScrollInfo( within ), 0885 collision = ( options.collision || "flip" ).split( " " ), 0886 offsets = {}; 0887 0888 dimensions = getDimensions( target ); 0889 if ( target[ 0 ].preventDefault ) { 0890 0891 // Force left top to allow flipping 0892 options.at = "left top"; 0893 } 0894 targetWidth = dimensions.width; 0895 targetHeight = dimensions.height; 0896 targetOffset = dimensions.offset; 0897 0898 // Clone to reuse original targetOffset later 0899 basePosition = $.extend( {}, targetOffset ); 0900 0901 // Force my and at to have valid horizontal and vertical positions 0902 // if a value is missing or invalid, it will be converted to center 0903 $.each( [ "my", "at" ], function() { 0904 var pos = ( options[ this ] || "" ).split( " " ), 0905 horizontalOffset, 0906 verticalOffset; 0907 0908 if ( pos.length === 1 ) { 0909 pos = rhorizontal.test( pos[ 0 ] ) ? 0910 pos.concat( [ "center" ] ) : 0911 rvertical.test( pos[ 0 ] ) ? 0912 [ "center" ].concat( pos ) : 0913 [ "center", "center" ]; 0914 } 0915 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 0916 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 0917 0918 // Calculate offsets 0919 horizontalOffset = roffset.exec( pos[ 0 ] ); 0920 verticalOffset = roffset.exec( pos[ 1 ] ); 0921 offsets[ this ] = [ 0922 horizontalOffset ? horizontalOffset[ 0 ] : 0, 0923 verticalOffset ? verticalOffset[ 0 ] : 0 0924 ]; 0925 0926 // Reduce to just the positions without the offsets 0927 options[ this ] = [ 0928 rposition.exec( pos[ 0 ] )[ 0 ], 0929 rposition.exec( pos[ 1 ] )[ 0 ] 0930 ]; 0931 } ); 0932 0933 // Normalize collision option 0934 if ( collision.length === 1 ) { 0935 collision[ 1 ] = collision[ 0 ]; 0936 } 0937 0938 if ( options.at[ 0 ] === "right" ) { 0939 basePosition.left += targetWidth; 0940 } else if ( options.at[ 0 ] === "center" ) { 0941 basePosition.left += targetWidth / 2; 0942 } 0943 0944 if ( options.at[ 1 ] === "bottom" ) { 0945 basePosition.top += targetHeight; 0946 } else if ( options.at[ 1 ] === "center" ) { 0947 basePosition.top += targetHeight / 2; 0948 } 0949 0950 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 0951 basePosition.left += atOffset[ 0 ]; 0952 basePosition.top += atOffset[ 1 ]; 0953 0954 return this.each( function() { 0955 var collisionPosition, using, 0956 elem = $( this ), 0957 elemWidth = elem.outerWidth(), 0958 elemHeight = elem.outerHeight(), 0959 marginLeft = parseCss( this, "marginLeft" ), 0960 marginTop = parseCss( this, "marginTop" ), 0961 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + 0962 scrollInfo.width, 0963 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + 0964 scrollInfo.height, 0965 position = $.extend( {}, basePosition ), 0966 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 0967 0968 if ( options.my[ 0 ] === "right" ) { 0969 position.left -= elemWidth; 0970 } else if ( options.my[ 0 ] === "center" ) { 0971 position.left -= elemWidth / 2; 0972 } 0973 0974 if ( options.my[ 1 ] === "bottom" ) { 0975 position.top -= elemHeight; 0976 } else if ( options.my[ 1 ] === "center" ) { 0977 position.top -= elemHeight / 2; 0978 } 0979 0980 position.left += myOffset[ 0 ]; 0981 position.top += myOffset[ 1 ]; 0982 0983 collisionPosition = { 0984 marginLeft: marginLeft, 0985 marginTop: marginTop 0986 }; 0987 0988 $.each( [ "left", "top" ], function( i, dir ) { 0989 if ( $.ui.position[ collision[ i ] ] ) { 0990 $.ui.position[ collision[ i ] ][ dir ]( position, { 0991 targetWidth: targetWidth, 0992 targetHeight: targetHeight, 0993 elemWidth: elemWidth, 0994 elemHeight: elemHeight, 0995 collisionPosition: collisionPosition, 0996 collisionWidth: collisionWidth, 0997 collisionHeight: collisionHeight, 0998 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 0999 my: options.my, 1000 at: options.at, 1001 within: within, 1002 elem: elem 1003 } ); 1004 } 1005 } ); 1006 1007 if ( options.using ) { 1008 1009 // Adds feedback as second argument to using callback, if present 1010 using = function( props ) { 1011 var left = targetOffset.left - position.left, 1012 right = left + targetWidth - elemWidth, 1013 top = targetOffset.top - position.top, 1014 bottom = top + targetHeight - elemHeight, 1015 feedback = { 1016 target: { 1017 element: target, 1018 left: targetOffset.left, 1019 top: targetOffset.top, 1020 width: targetWidth, 1021 height: targetHeight 1022 }, 1023 element: { 1024 element: elem, 1025 left: position.left, 1026 top: position.top, 1027 width: elemWidth, 1028 height: elemHeight 1029 }, 1030 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", 1031 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" 1032 }; 1033 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { 1034 feedback.horizontal = "center"; 1035 } 1036 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { 1037 feedback.vertical = "middle"; 1038 } 1039 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { 1040 feedback.important = "horizontal"; 1041 } else { 1042 feedback.important = "vertical"; 1043 } 1044 options.using.call( this, props, feedback ); 1045 }; 1046 } 1047 1048 elem.offset( $.extend( position, { using: using } ) ); 1049 } ); 1050 }; 1051 1052 $.ui.position = { 1053 fit: { 1054 left: function( position, data ) { 1055 var within = data.within, 1056 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, 1057 outerWidth = within.width, 1058 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1059 overLeft = withinOffset - collisionPosLeft, 1060 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, 1061 newOverRight; 1062 1063 // Element is wider than within 1064 if ( data.collisionWidth > outerWidth ) { 1065 1066 // Element is initially over the left side of within 1067 if ( overLeft > 0 && overRight <= 0 ) { 1068 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - 1069 withinOffset; 1070 position.left += overLeft - newOverRight; 1071 1072 // Element is initially over right side of within 1073 } else if ( overRight > 0 && overLeft <= 0 ) { 1074 position.left = withinOffset; 1075 1076 // Element is initially over both left and right sides of within 1077 } else { 1078 if ( overLeft > overRight ) { 1079 position.left = withinOffset + outerWidth - data.collisionWidth; 1080 } else { 1081 position.left = withinOffset; 1082 } 1083 } 1084 1085 // Too far left -> align with left edge 1086 } else if ( overLeft > 0 ) { 1087 position.left += overLeft; 1088 1089 // Too far right -> align with right edge 1090 } else if ( overRight > 0 ) { 1091 position.left -= overRight; 1092 1093 // Adjust based on position and margin 1094 } else { 1095 position.left = max( position.left - collisionPosLeft, position.left ); 1096 } 1097 }, 1098 top: function( position, data ) { 1099 var within = data.within, 1100 withinOffset = within.isWindow ? within.scrollTop : within.offset.top, 1101 outerHeight = data.within.height, 1102 collisionPosTop = position.top - data.collisionPosition.marginTop, 1103 overTop = withinOffset - collisionPosTop, 1104 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, 1105 newOverBottom; 1106 1107 // Element is taller than within 1108 if ( data.collisionHeight > outerHeight ) { 1109 1110 // Element is initially over the top of within 1111 if ( overTop > 0 && overBottom <= 0 ) { 1112 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - 1113 withinOffset; 1114 position.top += overTop - newOverBottom; 1115 1116 // Element is initially over bottom of within 1117 } else if ( overBottom > 0 && overTop <= 0 ) { 1118 position.top = withinOffset; 1119 1120 // Element is initially over both top and bottom of within 1121 } else { 1122 if ( overTop > overBottom ) { 1123 position.top = withinOffset + outerHeight - data.collisionHeight; 1124 } else { 1125 position.top = withinOffset; 1126 } 1127 } 1128 1129 // Too far up -> align with top 1130 } else if ( overTop > 0 ) { 1131 position.top += overTop; 1132 1133 // Too far down -> align with bottom edge 1134 } else if ( overBottom > 0 ) { 1135 position.top -= overBottom; 1136 1137 // Adjust based on position and margin 1138 } else { 1139 position.top = max( position.top - collisionPosTop, position.top ); 1140 } 1141 } 1142 }, 1143 flip: { 1144 left: function( position, data ) { 1145 var within = data.within, 1146 withinOffset = within.offset.left + within.scrollLeft, 1147 outerWidth = within.width, 1148 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, 1149 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1150 overLeft = collisionPosLeft - offsetLeft, 1151 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, 1152 myOffset = data.my[ 0 ] === "left" ? 1153 -data.elemWidth : 1154 data.my[ 0 ] === "right" ? 1155 data.elemWidth : 1156 0, 1157 atOffset = data.at[ 0 ] === "left" ? 1158 data.targetWidth : 1159 data.at[ 0 ] === "right" ? 1160 -data.targetWidth : 1161 0, 1162 offset = -2 * data.offset[ 0 ], 1163 newOverRight, 1164 newOverLeft; 1165 1166 if ( overLeft < 0 ) { 1167 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - 1168 outerWidth - withinOffset; 1169 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { 1170 position.left += myOffset + atOffset + offset; 1171 } 1172 } else if ( overRight > 0 ) { 1173 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + 1174 atOffset + offset - offsetLeft; 1175 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { 1176 position.left += myOffset + atOffset + offset; 1177 } 1178 } 1179 }, 1180 top: function( position, data ) { 1181 var within = data.within, 1182 withinOffset = within.offset.top + within.scrollTop, 1183 outerHeight = within.height, 1184 offsetTop = within.isWindow ? within.scrollTop : within.offset.top, 1185 collisionPosTop = position.top - data.collisionPosition.marginTop, 1186 overTop = collisionPosTop - offsetTop, 1187 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, 1188 top = data.my[ 1 ] === "top", 1189 myOffset = top ? 1190 -data.elemHeight : 1191 data.my[ 1 ] === "bottom" ? 1192 data.elemHeight : 1193 0, 1194 atOffset = data.at[ 1 ] === "top" ? 1195 data.targetHeight : 1196 data.at[ 1 ] === "bottom" ? 1197 -data.targetHeight : 1198 0, 1199 offset = -2 * data.offset[ 1 ], 1200 newOverTop, 1201 newOverBottom; 1202 if ( overTop < 0 ) { 1203 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - 1204 outerHeight - withinOffset; 1205 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { 1206 position.top += myOffset + atOffset + offset; 1207 } 1208 } else if ( overBottom > 0 ) { 1209 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + 1210 offset - offsetTop; 1211 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { 1212 position.top += myOffset + atOffset + offset; 1213 } 1214 } 1215 } 1216 }, 1217 flipfit: { 1218 left: function() { 1219 $.ui.position.flip.left.apply( this, arguments ); 1220 $.ui.position.fit.left.apply( this, arguments ); 1221 }, 1222 top: function() { 1223 $.ui.position.flip.top.apply( this, arguments ); 1224 $.ui.position.fit.top.apply( this, arguments ); 1225 } 1226 } 1227 }; 1228 1229 } )(); 1230 1231 var position = $.ui.position; 1232 1233 1234 /*! 1235 * jQuery UI :data 1.12.1 1236 * http://jqueryui.com 1237 * 1238 * Copyright jQuery Foundation and other contributors 1239 * Released under the MIT license. 1240 * http://jquery.org/license 1241 */ 1242 1243 //>>label: :data Selector 1244 //>>group: Core 1245 //>>description: Selects elements which have data stored under the specified key. 1246 //>>docs: http://api.jqueryui.com/data-selector/ 1247 1248 1249 var data = $.extend( $.expr[ ":" ], { 1250 data: $.expr.createPseudo ? 1251 $.expr.createPseudo( function( dataName ) { 1252 return function( elem ) { 1253 return !!$.data( elem, dataName ); 1254 }; 1255 } ) : 1256 1257 // Support: jQuery <1.8 1258 function( elem, i, match ) { 1259 return !!$.data( elem, match[ 3 ] ); 1260 } 1261 } ); 1262 1263 /*! 1264 * jQuery UI Disable Selection 1.12.1 1265 * http://jqueryui.com 1266 * 1267 * Copyright jQuery Foundation and other contributors 1268 * Released under the MIT license. 1269 * http://jquery.org/license 1270 */ 1271 1272 //>>label: disableSelection 1273 //>>group: Core 1274 //>>description: Disable selection of text content within the set of matched elements. 1275 //>>docs: http://api.jqueryui.com/disableSelection/ 1276 1277 // This file is deprecated 1278 1279 1280 var disableSelection = $.fn.extend( { 1281 disableSelection: ( function() { 1282 var eventType = "onselectstart" in document.createElement( "div" ) ? 1283 "selectstart" : 1284 "mousedown"; 1285 1286 return function() { 1287 return this.on( eventType + ".ui-disableSelection", function( event ) { 1288 event.preventDefault(); 1289 } ); 1290 }; 1291 } )(), 1292 1293 enableSelection: function() { 1294 return this.off( ".ui-disableSelection" ); 1295 } 1296 } ); 1297 1298 1299 /*! 1300 * jQuery UI Effects 1.12.1 1301 * http://jqueryui.com 1302 * 1303 * Copyright jQuery Foundation and other contributors 1304 * Released under the MIT license. 1305 * http://jquery.org/license 1306 */ 1307 1308 //>>label: Effects Core 1309 //>>group: Effects 1310 // jscs:disable maximumLineLength 1311 //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects. 1312 // jscs:enable maximumLineLength 1313 //>>docs: http://api.jqueryui.com/category/effects-core/ 1314 //>>demos: http://jqueryui.com/effect/ 1315 1316 1317 1318 var dataSpace = "ui-effects-", 1319 dataSpaceStyle = "ui-effects-style", 1320 dataSpaceAnimated = "ui-effects-animated", 1321 1322 // Create a local jQuery because jQuery Color relies on it and the 1323 // global may not exist with AMD and a custom build (#10199) 1324 jQuery = $; 1325 1326 $.effects = { 1327 effect: {} 1328 }; 1329 1330 /*! 1331 * jQuery Color Animations v2.1.2 1332 * https://github.com/jquery/jquery-color 1333 * 1334 * Copyright 2014 jQuery Foundation and other contributors 1335 * Released under the MIT license. 1336 * http://jquery.org/license 1337 * 1338 * Date: Wed Jan 16 08:47:09 2013 -0600 1339 */ 1340 ( function( jQuery, undefined ) { 1341 1342 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + 1343 "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", 1344 1345 // Plusequals test for += 100 -= 100 1346 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, 1347 1348 // A set of RE's that can match strings and generate color tuples. 1349 stringParsers = [ { 1350 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 1351 parse: function( execResult ) { 1352 return [ 1353 execResult[ 1 ], 1354 execResult[ 2 ], 1355 execResult[ 3 ], 1356 execResult[ 4 ] 1357 ]; 1358 } 1359 }, { 1360 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 1361 parse: function( execResult ) { 1362 return [ 1363 execResult[ 1 ] * 2.55, 1364 execResult[ 2 ] * 2.55, 1365 execResult[ 3 ] * 2.55, 1366 execResult[ 4 ] 1367 ]; 1368 } 1369 }, { 1370 1371 // This regex ignores A-F because it's compared against an already lowercased string 1372 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, 1373 parse: function( execResult ) { 1374 return [ 1375 parseInt( execResult[ 1 ], 16 ), 1376 parseInt( execResult[ 2 ], 16 ), 1377 parseInt( execResult[ 3 ], 16 ) 1378 ]; 1379 } 1380 }, { 1381 1382 // This regex ignores A-F because it's compared against an already lowercased string 1383 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, 1384 parse: function( execResult ) { 1385 return [ 1386 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 1387 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 1388 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) 1389 ]; 1390 } 1391 }, { 1392 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 1393 space: "hsla", 1394 parse: function( execResult ) { 1395 return [ 1396 execResult[ 1 ], 1397 execResult[ 2 ] / 100, 1398 execResult[ 3 ] / 100, 1399 execResult[ 4 ] 1400 ]; 1401 } 1402 } ], 1403 1404 // JQuery.Color( ) 1405 color = jQuery.Color = function( color, green, blue, alpha ) { 1406 return new jQuery.Color.fn.parse( color, green, blue, alpha ); 1407 }, 1408 spaces = { 1409 rgba: { 1410 props: { 1411 red: { 1412 idx: 0, 1413 type: "byte" 1414 }, 1415 green: { 1416 idx: 1, 1417 type: "byte" 1418 }, 1419 blue: { 1420 idx: 2, 1421 type: "byte" 1422 } 1423 } 1424 }, 1425 1426 hsla: { 1427 props: { 1428 hue: { 1429 idx: 0, 1430 type: "degrees" 1431 }, 1432 saturation: { 1433 idx: 1, 1434 type: "percent" 1435 }, 1436 lightness: { 1437 idx: 2, 1438 type: "percent" 1439 } 1440 } 1441 } 1442 }, 1443 propTypes = { 1444 "byte": { 1445 floor: true, 1446 max: 255 1447 }, 1448 "percent": { 1449 max: 1 1450 }, 1451 "degrees": { 1452 mod: 360, 1453 floor: true 1454 } 1455 }, 1456 support = color.support = {}, 1457 1458 // Element for support tests 1459 supportElem = jQuery( "<p>" )[ 0 ], 1460 1461 // Colors = jQuery.Color.names 1462 colors, 1463 1464 // Local aliases of functions called often 1465 each = jQuery.each; 1466 1467 // Determine rgba support immediately 1468 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; 1469 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; 1470 1471 // Define cache name and alpha properties 1472 // for rgba and hsla spaces 1473 each( spaces, function( spaceName, space ) { 1474 space.cache = "_" + spaceName; 1475 space.props.alpha = { 1476 idx: 3, 1477 type: "percent", 1478 def: 1 1479 }; 1480 } ); 1481 1482 function clamp( value, prop, allowEmpty ) { 1483 var type = propTypes[ prop.type ] || {}; 1484 1485 if ( value == null ) { 1486 return ( allowEmpty || !prop.def ) ? null : prop.def; 1487 } 1488 1489 // ~~ is an short way of doing floor for positive numbers 1490 value = type.floor ? ~~value : parseFloat( value ); 1491 1492 // IE will pass in empty strings as value for alpha, 1493 // which will hit this case 1494 if ( isNaN( value ) ) { 1495 return prop.def; 1496 } 1497 1498 if ( type.mod ) { 1499 1500 // We add mod before modding to make sure that negatives values 1501 // get converted properly: -10 -> 350 1502 return ( value + type.mod ) % type.mod; 1503 } 1504 1505 // For now all property types without mod have min and max 1506 return 0 > value ? 0 : type.max < value ? type.max : value; 1507 } 1508 1509 function stringParse( string ) { 1510 var inst = color(), 1511 rgba = inst._rgba = []; 1512 1513 string = string.toLowerCase(); 1514 1515 each( stringParsers, function( i, parser ) { 1516 var parsed, 1517 match = parser.re.exec( string ), 1518 values = match && parser.parse( match ), 1519 spaceName = parser.space || "rgba"; 1520 1521 if ( values ) { 1522 parsed = inst[ spaceName ]( values ); 1523 1524 // If this was an rgba parse the assignment might happen twice 1525 // oh well.... 1526 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; 1527 rgba = inst._rgba = parsed._rgba; 1528 1529 // Exit each( stringParsers ) here because we matched 1530 return false; 1531 } 1532 } ); 1533 1534 // Found a stringParser that handled it 1535 if ( rgba.length ) { 1536 1537 // If this came from a parsed string, force "transparent" when alpha is 0 1538 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) 1539 if ( rgba.join() === "0,0,0,0" ) { 1540 jQuery.extend( rgba, colors.transparent ); 1541 } 1542 return inst; 1543 } 1544 1545 // Named colors 1546 return colors[ string ]; 1547 } 1548 1549 color.fn = jQuery.extend( color.prototype, { 1550 parse: function( red, green, blue, alpha ) { 1551 if ( red === undefined ) { 1552 this._rgba = [ null, null, null, null ]; 1553 return this; 1554 } 1555 if ( red.jquery || red.nodeType ) { 1556 red = jQuery( red ).css( green ); 1557 green = undefined; 1558 } 1559 1560 var inst = this, 1561 type = jQuery.type( red ), 1562 rgba = this._rgba = []; 1563 1564 // More than 1 argument specified - assume ( red, green, blue, alpha ) 1565 if ( green !== undefined ) { 1566 red = [ red, green, blue, alpha ]; 1567 type = "array"; 1568 } 1569 1570 if ( type === "string" ) { 1571 return this.parse( stringParse( red ) || colors._default ); 1572 } 1573 1574 if ( type === "array" ) { 1575 each( spaces.rgba.props, function( key, prop ) { 1576 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); 1577 } ); 1578 return this; 1579 } 1580 1581 if ( type === "object" ) { 1582 if ( red instanceof color ) { 1583 each( spaces, function( spaceName, space ) { 1584 if ( red[ space.cache ] ) { 1585 inst[ space.cache ] = red[ space.cache ].slice(); 1586 } 1587 } ); 1588 } else { 1589 each( spaces, function( spaceName, space ) { 1590 var cache = space.cache; 1591 each( space.props, function( key, prop ) { 1592 1593 // If the cache doesn't exist, and we know how to convert 1594 if ( !inst[ cache ] && space.to ) { 1595 1596 // If the value was null, we don't need to copy it 1597 // if the key was alpha, we don't need to copy it either 1598 if ( key === "alpha" || red[ key ] == null ) { 1599 return; 1600 } 1601 inst[ cache ] = space.to( inst._rgba ); 1602 } 1603 1604 // This is the only case where we allow nulls for ALL properties. 1605 // call clamp with alwaysAllowEmpty 1606 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); 1607 } ); 1608 1609 // Everything defined but alpha? 1610 if ( inst[ cache ] && 1611 jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { 1612 1613 // Use the default of 1 1614 inst[ cache ][ 3 ] = 1; 1615 if ( space.from ) { 1616 inst._rgba = space.from( inst[ cache ] ); 1617 } 1618 } 1619 } ); 1620 } 1621 return this; 1622 } 1623 }, 1624 is: function( compare ) { 1625 var is = color( compare ), 1626 same = true, 1627 inst = this; 1628 1629 each( spaces, function( _, space ) { 1630 var localCache, 1631 isCache = is[ space.cache ]; 1632 if ( isCache ) { 1633 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; 1634 each( space.props, function( _, prop ) { 1635 if ( isCache[ prop.idx ] != null ) { 1636 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); 1637 return same; 1638 } 1639 } ); 1640 } 1641 return same; 1642 } ); 1643 return same; 1644 }, 1645 _space: function() { 1646 var used = [], 1647 inst = this; 1648 each( spaces, function( spaceName, space ) { 1649 if ( inst[ space.cache ] ) { 1650 used.push( spaceName ); 1651 } 1652 } ); 1653 return used.pop(); 1654 }, 1655 transition: function( other, distance ) { 1656 var end = color( other ), 1657 spaceName = end._space(), 1658 space = spaces[ spaceName ], 1659 startColor = this.alpha() === 0 ? color( "transparent" ) : this, 1660 start = startColor[ space.cache ] || space.to( startColor._rgba ), 1661 result = start.slice(); 1662 1663 end = end[ space.cache ]; 1664 each( space.props, function( key, prop ) { 1665 var index = prop.idx, 1666 startValue = start[ index ], 1667 endValue = end[ index ], 1668 type = propTypes[ prop.type ] || {}; 1669 1670 // If null, don't override start value 1671 if ( endValue === null ) { 1672 return; 1673 } 1674 1675 // If null - use end 1676 if ( startValue === null ) { 1677 result[ index ] = endValue; 1678 } else { 1679 if ( type.mod ) { 1680 if ( endValue - startValue > type.mod / 2 ) { 1681 startValue += type.mod; 1682 } else if ( startValue - endValue > type.mod / 2 ) { 1683 startValue -= type.mod; 1684 } 1685 } 1686 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); 1687 } 1688 } ); 1689 return this[ spaceName ]( result ); 1690 }, 1691 blend: function( opaque ) { 1692 1693 // If we are already opaque - return ourself 1694 if ( this._rgba[ 3 ] === 1 ) { 1695 return this; 1696 } 1697 1698 var rgb = this._rgba.slice(), 1699 a = rgb.pop(), 1700 blend = color( opaque )._rgba; 1701 1702 return color( jQuery.map( rgb, function( v, i ) { 1703 return ( 1 - a ) * blend[ i ] + a * v; 1704 } ) ); 1705 }, 1706 toRgbaString: function() { 1707 var prefix = "rgba(", 1708 rgba = jQuery.map( this._rgba, function( v, i ) { 1709 return v == null ? ( i > 2 ? 1 : 0 ) : v; 1710 } ); 1711 1712 if ( rgba[ 3 ] === 1 ) { 1713 rgba.pop(); 1714 prefix = "rgb("; 1715 } 1716 1717 return prefix + rgba.join() + ")"; 1718 }, 1719 toHslaString: function() { 1720 var prefix = "hsla(", 1721 hsla = jQuery.map( this.hsla(), function( v, i ) { 1722 if ( v == null ) { 1723 v = i > 2 ? 1 : 0; 1724 } 1725 1726 // Catch 1 and 2 1727 if ( i && i < 3 ) { 1728 v = Math.round( v * 100 ) + "%"; 1729 } 1730 return v; 1731 } ); 1732 1733 if ( hsla[ 3 ] === 1 ) { 1734 hsla.pop(); 1735 prefix = "hsl("; 1736 } 1737 return prefix + hsla.join() + ")"; 1738 }, 1739 toHexString: function( includeAlpha ) { 1740 var rgba = this._rgba.slice(), 1741 alpha = rgba.pop(); 1742 1743 if ( includeAlpha ) { 1744 rgba.push( ~~( alpha * 255 ) ); 1745 } 1746 1747 return "#" + jQuery.map( rgba, function( v ) { 1748 1749 // Default to 0 when nulls exist 1750 v = ( v || 0 ).toString( 16 ); 1751 return v.length === 1 ? "0" + v : v; 1752 } ).join( "" ); 1753 }, 1754 toString: function() { 1755 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); 1756 } 1757 } ); 1758 color.fn.parse.prototype = color.fn; 1759 1760 // Hsla conversions adapted from: 1761 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 1762 1763 function hue2rgb( p, q, h ) { 1764 h = ( h + 1 ) % 1; 1765 if ( h * 6 < 1 ) { 1766 return p + ( q - p ) * h * 6; 1767 } 1768 if ( h * 2 < 1 ) { 1769 return q; 1770 } 1771 if ( h * 3 < 2 ) { 1772 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; 1773 } 1774 return p; 1775 } 1776 1777 spaces.hsla.to = function( rgba ) { 1778 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { 1779 return [ null, null, null, rgba[ 3 ] ]; 1780 } 1781 var r = rgba[ 0 ] / 255, 1782 g = rgba[ 1 ] / 255, 1783 b = rgba[ 2 ] / 255, 1784 a = rgba[ 3 ], 1785 max = Math.max( r, g, b ), 1786 min = Math.min( r, g, b ), 1787 diff = max - min, 1788 add = max + min, 1789 l = add * 0.5, 1790 h, s; 1791 1792 if ( min === max ) { 1793 h = 0; 1794 } else if ( r === max ) { 1795 h = ( 60 * ( g - b ) / diff ) + 360; 1796 } else if ( g === max ) { 1797 h = ( 60 * ( b - r ) / diff ) + 120; 1798 } else { 1799 h = ( 60 * ( r - g ) / diff ) + 240; 1800 } 1801 1802 // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0% 1803 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) 1804 if ( diff === 0 ) { 1805 s = 0; 1806 } else if ( l <= 0.5 ) { 1807 s = diff / add; 1808 } else { 1809 s = diff / ( 2 - add ); 1810 } 1811 return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; 1812 }; 1813 1814 spaces.hsla.from = function( hsla ) { 1815 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { 1816 return [ null, null, null, hsla[ 3 ] ]; 1817 } 1818 var h = hsla[ 0 ] / 360, 1819 s = hsla[ 1 ], 1820 l = hsla[ 2 ], 1821 a = hsla[ 3 ], 1822 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, 1823 p = 2 * l - q; 1824 1825 return [ 1826 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), 1827 Math.round( hue2rgb( p, q, h ) * 255 ), 1828 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), 1829 a 1830 ]; 1831 }; 1832 1833 each( spaces, function( spaceName, space ) { 1834 var props = space.props, 1835 cache = space.cache, 1836 to = space.to, 1837 from = space.from; 1838 1839 // Makes rgba() and hsla() 1840 color.fn[ spaceName ] = function( value ) { 1841 1842 // Generate a cache for this space if it doesn't exist 1843 if ( to && !this[ cache ] ) { 1844 this[ cache ] = to( this._rgba ); 1845 } 1846 if ( value === undefined ) { 1847 return this[ cache ].slice(); 1848 } 1849 1850 var ret, 1851 type = jQuery.type( value ), 1852 arr = ( type === "array" || type === "object" ) ? value : arguments, 1853 local = this[ cache ].slice(); 1854 1855 each( props, function( key, prop ) { 1856 var val = arr[ type === "object" ? key : prop.idx ]; 1857 if ( val == null ) { 1858 val = local[ prop.idx ]; 1859 } 1860 local[ prop.idx ] = clamp( val, prop ); 1861 } ); 1862 1863 if ( from ) { 1864 ret = color( from( local ) ); 1865 ret[ cache ] = local; 1866 return ret; 1867 } else { 1868 return color( local ); 1869 } 1870 }; 1871 1872 // Makes red() green() blue() alpha() hue() saturation() lightness() 1873 each( props, function( key, prop ) { 1874 1875 // Alpha is included in more than one space 1876 if ( color.fn[ key ] ) { 1877 return; 1878 } 1879 color.fn[ key ] = function( value ) { 1880 var vtype = jQuery.type( value ), 1881 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), 1882 local = this[ fn ](), 1883 cur = local[ prop.idx ], 1884 match; 1885 1886 if ( vtype === "undefined" ) { 1887 return cur; 1888 } 1889 1890 if ( vtype === "function" ) { 1891 value = value.call( this, cur ); 1892 vtype = jQuery.type( value ); 1893 } 1894 if ( value == null && prop.empty ) { 1895 return this; 1896 } 1897 if ( vtype === "string" ) { 1898 match = rplusequals.exec( value ); 1899 if ( match ) { 1900 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); 1901 } 1902 } 1903 local[ prop.idx ] = value; 1904 return this[ fn ]( local ); 1905 }; 1906 } ); 1907 } ); 1908 1909 // Add cssHook and .fx.step function for each named hook. 1910 // accept a space separated string of properties 1911 color.hook = function( hook ) { 1912 var hooks = hook.split( " " ); 1913 each( hooks, function( i, hook ) { 1914 jQuery.cssHooks[ hook ] = { 1915 set: function( elem, value ) { 1916 var parsed, curElem, 1917 backgroundColor = ""; 1918 1919 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || 1920 ( parsed = stringParse( value ) ) ) ) { 1921 value = color( parsed || value ); 1922 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { 1923 curElem = hook === "backgroundColor" ? elem.parentNode : elem; 1924 while ( 1925 ( backgroundColor === "" || backgroundColor === "transparent" ) && 1926 curElem && curElem.style 1927 ) { 1928 try { 1929 backgroundColor = jQuery.css( curElem, "backgroundColor" ); 1930 curElem = curElem.parentNode; 1931 } catch ( e ) { 1932 } 1933 } 1934 1935 value = value.blend( backgroundColor && backgroundColor !== "transparent" ? 1936 backgroundColor : 1937 "_default" ); 1938 } 1939 1940 value = value.toRgbaString(); 1941 } 1942 try { 1943 elem.style[ hook ] = value; 1944 } catch ( e ) { 1945 1946 // Wrapped to prevent IE from throwing errors on "invalid" values like 1947 // 'auto' or 'inherit' 1948 } 1949 } 1950 }; 1951 jQuery.fx.step[ hook ] = function( fx ) { 1952 if ( !fx.colorInit ) { 1953 fx.start = color( fx.elem, hook ); 1954 fx.end = color( fx.end ); 1955 fx.colorInit = true; 1956 } 1957 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); 1958 }; 1959 } ); 1960 1961 }; 1962 1963 color.hook( stepHooks ); 1964 1965 jQuery.cssHooks.borderColor = { 1966 expand: function( value ) { 1967 var expanded = {}; 1968 1969 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { 1970 expanded[ "border" + part + "Color" ] = value; 1971 } ); 1972 return expanded; 1973 } 1974 }; 1975 1976 // Basic color names only. 1977 // Usage of any of the other color names requires adding yourself or including 1978 // jquery.color.svg-names.js. 1979 colors = jQuery.Color.names = { 1980 1981 // 4.1. Basic color keywords 1982 aqua: "#00ffff", 1983 black: "#000000", 1984 blue: "#0000ff", 1985 fuchsia: "#ff00ff", 1986 gray: "#808080", 1987 green: "#008000", 1988 lime: "#00ff00", 1989 maroon: "#800000", 1990 navy: "#000080", 1991 olive: "#808000", 1992 purple: "#800080", 1993 red: "#ff0000", 1994 silver: "#c0c0c0", 1995 teal: "#008080", 1996 white: "#ffffff", 1997 yellow: "#ffff00", 1998 1999 // 4.2.3. "transparent" color keyword 2000 transparent: [ null, null, null, 0 ], 2001 2002 _default: "#ffffff" 2003 }; 2004 2005 } )( jQuery ); 2006 2007 /******************************************************************************/ 2008 /****************************** CLASS ANIMATIONS ******************************/ 2009 /******************************************************************************/ 2010 ( function() { 2011 2012 var classAnimationActions = [ "add", "remove", "toggle" ], 2013 shorthandStyles = { 2014 border: 1, 2015 borderBottom: 1, 2016 borderColor: 1, 2017 borderLeft: 1, 2018 borderRight: 1, 2019 borderTop: 1, 2020 borderWidth: 1, 2021 margin: 1, 2022 padding: 1 2023 }; 2024 2025 $.each( 2026 [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], 2027 function( _, prop ) { 2028 $.fx.step[ prop ] = function( fx ) { 2029 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { 2030 jQuery.style( fx.elem, prop, fx.end ); 2031 fx.setAttr = true; 2032 } 2033 }; 2034 } 2035 ); 2036 2037 function getElementStyles( elem ) { 2038 var key, len, 2039 style = elem.ownerDocument.defaultView ? 2040 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : 2041 elem.currentStyle, 2042 styles = {}; 2043 2044 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { 2045 len = style.length; 2046 while ( len-- ) { 2047 key = style[ len ]; 2048 if ( typeof style[ key ] === "string" ) { 2049 styles[ $.camelCase( key ) ] = style[ key ]; 2050 } 2051 } 2052 2053 // Support: Opera, IE <9 2054 } else { 2055 for ( key in style ) { 2056 if ( typeof style[ key ] === "string" ) { 2057 styles[ key ] = style[ key ]; 2058 } 2059 } 2060 } 2061 2062 return styles; 2063 } 2064 2065 function styleDifference( oldStyle, newStyle ) { 2066 var diff = {}, 2067 name, value; 2068 2069 for ( name in newStyle ) { 2070 value = newStyle[ name ]; 2071 if ( oldStyle[ name ] !== value ) { 2072 if ( !shorthandStyles[ name ] ) { 2073 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { 2074 diff[ name ] = value; 2075 } 2076 } 2077 } 2078 } 2079 2080 return diff; 2081 } 2082 2083 // Support: jQuery <1.8 2084 if ( !$.fn.addBack ) { 2085 $.fn.addBack = function( selector ) { 2086 return this.add( selector == null ? 2087 this.prevObject : this.prevObject.filter( selector ) 2088 ); 2089 }; 2090 } 2091 2092 $.effects.animateClass = function( value, duration, easing, callback ) { 2093 var o = $.speed( duration, easing, callback ); 2094 2095 return this.queue( function() { 2096 var animated = $( this ), 2097 baseClass = animated.attr( "class" ) || "", 2098 applyClassChange, 2099 allAnimations = o.children ? animated.find( "*" ).addBack() : animated; 2100 2101 // Map the animated objects to store the original styles. 2102 allAnimations = allAnimations.map( function() { 2103 var el = $( this ); 2104 return { 2105 el: el, 2106 start: getElementStyles( this ) 2107 }; 2108 } ); 2109 2110 // Apply class change 2111 applyClassChange = function() { 2112 $.each( classAnimationActions, function( i, action ) { 2113 if ( value[ action ] ) { 2114 animated[ action + "Class" ]( value[ action ] ); 2115 } 2116 } ); 2117 }; 2118 applyClassChange(); 2119 2120 // Map all animated objects again - calculate new styles and diff 2121 allAnimations = allAnimations.map( function() { 2122 this.end = getElementStyles( this.el[ 0 ] ); 2123 this.diff = styleDifference( this.start, this.end ); 2124 return this; 2125 } ); 2126 2127 // Apply original class 2128 animated.attr( "class", baseClass ); 2129 2130 // Map all animated objects again - this time collecting a promise 2131 allAnimations = allAnimations.map( function() { 2132 var styleInfo = this, 2133 dfd = $.Deferred(), 2134 opts = $.extend( {}, o, { 2135 queue: false, 2136 complete: function() { 2137 dfd.resolve( styleInfo ); 2138 } 2139 } ); 2140 2141 this.el.animate( this.diff, opts ); 2142 return dfd.promise(); 2143 } ); 2144 2145 // Once all animations have completed: 2146 $.when.apply( $, allAnimations.get() ).done( function() { 2147 2148 // Set the final class 2149 applyClassChange(); 2150 2151 // For each animated element, 2152 // clear all css properties that were animated 2153 $.each( arguments, function() { 2154 var el = this.el; 2155 $.each( this.diff, function( key ) { 2156 el.css( key, "" ); 2157 } ); 2158 } ); 2159 2160 // This is guarnteed to be there if you use jQuery.speed() 2161 // it also handles dequeuing the next anim... 2162 o.complete.call( animated[ 0 ] ); 2163 } ); 2164 } ); 2165 }; 2166 2167 $.fn.extend( { 2168 addClass: ( function( orig ) { 2169 return function( classNames, speed, easing, callback ) { 2170 return speed ? 2171 $.effects.animateClass.call( this, 2172 { add: classNames }, speed, easing, callback ) : 2173 orig.apply( this, arguments ); 2174 }; 2175 } )( $.fn.addClass ), 2176 2177 removeClass: ( function( orig ) { 2178 return function( classNames, speed, easing, callback ) { 2179 return arguments.length > 1 ? 2180 $.effects.animateClass.call( this, 2181 { remove: classNames }, speed, easing, callback ) : 2182 orig.apply( this, arguments ); 2183 }; 2184 } )( $.fn.removeClass ), 2185 2186 toggleClass: ( function( orig ) { 2187 return function( classNames, force, speed, easing, callback ) { 2188 if ( typeof force === "boolean" || force === undefined ) { 2189 if ( !speed ) { 2190 2191 // Without speed parameter 2192 return orig.apply( this, arguments ); 2193 } else { 2194 return $.effects.animateClass.call( this, 2195 ( force ? { add: classNames } : { remove: classNames } ), 2196 speed, easing, callback ); 2197 } 2198 } else { 2199 2200 // Without force parameter 2201 return $.effects.animateClass.call( this, 2202 { toggle: classNames }, force, speed, easing ); 2203 } 2204 }; 2205 } )( $.fn.toggleClass ), 2206 2207 switchClass: function( remove, add, speed, easing, callback ) { 2208 return $.effects.animateClass.call( this, { 2209 add: add, 2210 remove: remove 2211 }, speed, easing, callback ); 2212 } 2213 } ); 2214 2215 } )(); 2216 2217 /******************************************************************************/ 2218 /*********************************** EFFECTS **********************************/ 2219 /******************************************************************************/ 2220 2221 ( function() { 2222 2223 if ( $.expr && $.expr.filters && $.expr.filters.animated ) { 2224 $.expr.filters.animated = ( function( orig ) { 2225 return function( elem ) { 2226 return !!$( elem ).data( dataSpaceAnimated ) || orig( elem ); 2227 }; 2228 } )( $.expr.filters.animated ); 2229 } 2230 2231 if ( $.uiBackCompat !== false ) { 2232 $.extend( $.effects, { 2233 2234 // Saves a set of properties in a data storage 2235 save: function( element, set ) { 2236 var i = 0, length = set.length; 2237 for ( ; i < length; i++ ) { 2238 if ( set[ i ] !== null ) { 2239 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); 2240 } 2241 } 2242 }, 2243 2244 // Restores a set of previously saved properties from a data storage 2245 restore: function( element, set ) { 2246 var val, i = 0, length = set.length; 2247 for ( ; i < length; i++ ) { 2248 if ( set[ i ] !== null ) { 2249 val = element.data( dataSpace + set[ i ] ); 2250 element.css( set[ i ], val ); 2251 } 2252 } 2253 }, 2254 2255 setMode: function( el, mode ) { 2256 if ( mode === "toggle" ) { 2257 mode = el.is( ":hidden" ) ? "show" : "hide"; 2258 } 2259 return mode; 2260 }, 2261 2262 // Wraps the element around a wrapper that copies position properties 2263 createWrapper: function( element ) { 2264 2265 // If the element is already wrapped, return it 2266 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 2267 return element.parent(); 2268 } 2269 2270 // Wrap the element 2271 var props = { 2272 width: element.outerWidth( true ), 2273 height: element.outerHeight( true ), 2274 "float": element.css( "float" ) 2275 }, 2276 wrapper = $( "<div></div>" ) 2277 .addClass( "ui-effects-wrapper" ) 2278 .css( { 2279 fontSize: "100%", 2280 background: "transparent", 2281 border: "none", 2282 margin: 0, 2283 padding: 0 2284 } ), 2285 2286 // Store the size in case width/height are defined in % - Fixes #5245 2287 size = { 2288 width: element.width(), 2289 height: element.height() 2290 }, 2291 active = document.activeElement; 2292 2293 // Support: Firefox 2294 // Firefox incorrectly exposes anonymous content 2295 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 2296 try { 2297 active.id; 2298 } catch ( e ) { 2299 active = document.body; 2300 } 2301 2302 element.wrap( wrapper ); 2303 2304 // Fixes #7595 - Elements lose focus when wrapped. 2305 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 2306 $( active ).trigger( "focus" ); 2307 } 2308 2309 // Hotfix for jQuery 1.4 since some change in wrap() seems to actually 2310 // lose the reference to the wrapped element 2311 wrapper = element.parent(); 2312 2313 // Transfer positioning properties to the wrapper 2314 if ( element.css( "position" ) === "static" ) { 2315 wrapper.css( { position: "relative" } ); 2316 element.css( { position: "relative" } ); 2317 } else { 2318 $.extend( props, { 2319 position: element.css( "position" ), 2320 zIndex: element.css( "z-index" ) 2321 } ); 2322 $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) { 2323 props[ pos ] = element.css( pos ); 2324 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { 2325 props[ pos ] = "auto"; 2326 } 2327 } ); 2328 element.css( { 2329 position: "relative", 2330 top: 0, 2331 left: 0, 2332 right: "auto", 2333 bottom: "auto" 2334 } ); 2335 } 2336 element.css( size ); 2337 2338 return wrapper.css( props ).show(); 2339 }, 2340 2341 removeWrapper: function( element ) { 2342 var active = document.activeElement; 2343 2344 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 2345 element.parent().replaceWith( element ); 2346 2347 // Fixes #7595 - Elements lose focus when wrapped. 2348 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 2349 $( active ).trigger( "focus" ); 2350 } 2351 } 2352 2353 return element; 2354 } 2355 } ); 2356 } 2357 2358 $.extend( $.effects, { 2359 version: "1.12.1", 2360 2361 define: function( name, mode, effect ) { 2362 if ( !effect ) { 2363 effect = mode; 2364 mode = "effect"; 2365 } 2366 2367 $.effects.effect[ name ] = effect; 2368 $.effects.effect[ name ].mode = mode; 2369 2370 return effect; 2371 }, 2372 2373 scaledDimensions: function( element, percent, direction ) { 2374 if ( percent === 0 ) { 2375 return { 2376 height: 0, 2377 width: 0, 2378 outerHeight: 0, 2379 outerWidth: 0 2380 }; 2381 } 2382 2383 var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1, 2384 y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1; 2385 2386 return { 2387 height: element.height() * y, 2388 width: element.width() * x, 2389 outerHeight: element.outerHeight() * y, 2390 outerWidth: element.outerWidth() * x 2391 }; 2392 2393 }, 2394 2395 clipToBox: function( animation ) { 2396 return { 2397 width: animation.clip.right - animation.clip.left, 2398 height: animation.clip.bottom - animation.clip.top, 2399 left: animation.clip.left, 2400 top: animation.clip.top 2401 }; 2402 }, 2403 2404 // Injects recently queued functions to be first in line (after "inprogress") 2405 unshift: function( element, queueLength, count ) { 2406 var queue = element.queue(); 2407 2408 if ( queueLength > 1 ) { 2409 queue.splice.apply( queue, 2410 [ 1, 0 ].concat( queue.splice( queueLength, count ) ) ); 2411 } 2412 element.dequeue(); 2413 }, 2414 2415 saveStyle: function( element ) { 2416 element.data( dataSpaceStyle, element[ 0 ].style.cssText ); 2417 }, 2418 2419 restoreStyle: function( element ) { 2420 element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || ""; 2421 element.removeData( dataSpaceStyle ); 2422 }, 2423 2424 mode: function( element, mode ) { 2425 var hidden = element.is( ":hidden" ); 2426 2427 if ( mode === "toggle" ) { 2428 mode = hidden ? "show" : "hide"; 2429 } 2430 if ( hidden ? mode === "hide" : mode === "show" ) { 2431 mode = "none"; 2432 } 2433 return mode; 2434 }, 2435 2436 // Translates a [top,left] array into a baseline value 2437 getBaseline: function( origin, original ) { 2438 var y, x; 2439 2440 switch ( origin[ 0 ] ) { 2441 case "top": 2442 y = 0; 2443 break; 2444 case "middle": 2445 y = 0.5; 2446 break; 2447 case "bottom": 2448 y = 1; 2449 break; 2450 default: 2451 y = origin[ 0 ] / original.height; 2452 } 2453 2454 switch ( origin[ 1 ] ) { 2455 case "left": 2456 x = 0; 2457 break; 2458 case "center": 2459 x = 0.5; 2460 break; 2461 case "right": 2462 x = 1; 2463 break; 2464 default: 2465 x = origin[ 1 ] / original.width; 2466 } 2467 2468 return { 2469 x: x, 2470 y: y 2471 }; 2472 }, 2473 2474 // Creates a placeholder element so that the original element can be made absolute 2475 createPlaceholder: function( element ) { 2476 var placeholder, 2477 cssPosition = element.css( "position" ), 2478 position = element.position(); 2479 2480 // Lock in margins first to account for form elements, which 2481 // will change margin if you explicitly set height 2482 // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380 2483 // Support: Safari 2484 element.css( { 2485 marginTop: element.css( "marginTop" ), 2486 marginBottom: element.css( "marginBottom" ), 2487 marginLeft: element.css( "marginLeft" ), 2488 marginRight: element.css( "marginRight" ) 2489 } ) 2490 .outerWidth( element.outerWidth() ) 2491 .outerHeight( element.outerHeight() ); 2492 2493 if ( /^(static|relative)/.test( cssPosition ) ) { 2494 cssPosition = "absolute"; 2495 2496 placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( { 2497 2498 // Convert inline to inline block to account for inline elements 2499 // that turn to inline block based on content (like img) 2500 display: /^(inline|ruby)/.test( element.css( "display" ) ) ? 2501 "inline-block" : 2502 "block", 2503 visibility: "hidden", 2504 2505 // Margins need to be set to account for margin collapse 2506 marginTop: element.css( "marginTop" ), 2507 marginBottom: element.css( "marginBottom" ), 2508 marginLeft: element.css( "marginLeft" ), 2509 marginRight: element.css( "marginRight" ), 2510 "float": element.css( "float" ) 2511 } ) 2512 .outerWidth( element.outerWidth() ) 2513 .outerHeight( element.outerHeight() ) 2514 .addClass( "ui-effects-placeholder" ); 2515 2516 element.data( dataSpace + "placeholder", placeholder ); 2517 } 2518 2519 element.css( { 2520 position: cssPosition, 2521 left: position.left, 2522 top: position.top 2523 } ); 2524 2525 return placeholder; 2526 }, 2527 2528 removePlaceholder: function( element ) { 2529 var dataKey = dataSpace + "placeholder", 2530 placeholder = element.data( dataKey ); 2531 2532 if ( placeholder ) { 2533 placeholder.remove(); 2534 element.removeData( dataKey ); 2535 } 2536 }, 2537 2538 // Removes a placeholder if it exists and restores 2539 // properties that were modified during placeholder creation 2540 cleanUp: function( element ) { 2541 $.effects.restoreStyle( element ); 2542 $.effects.removePlaceholder( element ); 2543 }, 2544 2545 setTransition: function( element, list, factor, value ) { 2546 value = value || {}; 2547 $.each( list, function( i, x ) { 2548 var unit = element.cssUnit( x ); 2549 if ( unit[ 0 ] > 0 ) { 2550 value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; 2551 } 2552 } ); 2553 return value; 2554 } 2555 } ); 2556 2557 // Return an effect options object for the given parameters: 2558 function _normalizeArguments( effect, options, speed, callback ) { 2559 2560 // Allow passing all options as the first parameter 2561 if ( $.isPlainObject( effect ) ) { 2562 options = effect; 2563 effect = effect.effect; 2564 } 2565 2566 // Convert to an object 2567 effect = { effect: effect }; 2568 2569 // Catch (effect, null, ...) 2570 if ( options == null ) { 2571 options = {}; 2572 } 2573 2574 // Catch (effect, callback) 2575 if ( $.isFunction( options ) ) { 2576 callback = options; 2577 speed = null; 2578 options = {}; 2579 } 2580 2581 // Catch (effect, speed, ?) 2582 if ( typeof options === "number" || $.fx.speeds[ options ] ) { 2583 callback = speed; 2584 speed = options; 2585 options = {}; 2586 } 2587 2588 // Catch (effect, options, callback) 2589 if ( $.isFunction( speed ) ) { 2590 callback = speed; 2591 speed = null; 2592 } 2593 2594 // Add options to effect 2595 if ( options ) { 2596 $.extend( effect, options ); 2597 } 2598 2599 speed = speed || options.duration; 2600 effect.duration = $.fx.off ? 0 : 2601 typeof speed === "number" ? speed : 2602 speed in $.fx.speeds ? $.fx.speeds[ speed ] : 2603 $.fx.speeds._default; 2604 2605 effect.complete = callback || options.complete; 2606 2607 return effect; 2608 } 2609 2610 function standardAnimationOption( option ) { 2611 2612 // Valid standard speeds (nothing, number, named speed) 2613 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { 2614 return true; 2615 } 2616 2617 // Invalid strings - treat as "normal" speed 2618 if ( typeof option === "string" && !$.effects.effect[ option ] ) { 2619 return true; 2620 } 2621 2622 // Complete callback 2623 if ( $.isFunction( option ) ) { 2624 return true; 2625 } 2626 2627 // Options hash (but not naming an effect) 2628 if ( typeof option === "object" && !option.effect ) { 2629 return true; 2630 } 2631 2632 // Didn't match any standard API 2633 return false; 2634 } 2635 2636 $.fn.extend( { 2637 effect: function( /* effect, options, speed, callback */ ) { 2638 var args = _normalizeArguments.apply( this, arguments ), 2639 effectMethod = $.effects.effect[ args.effect ], 2640 defaultMode = effectMethod.mode, 2641 queue = args.queue, 2642 queueName = queue || "fx", 2643 complete = args.complete, 2644 mode = args.mode, 2645 modes = [], 2646 prefilter = function( next ) { 2647 var el = $( this ), 2648 normalizedMode = $.effects.mode( el, mode ) || defaultMode; 2649 2650 // Sentinel for duck-punching the :animated psuedo-selector 2651 el.data( dataSpaceAnimated, true ); 2652 2653 // Save effect mode for later use, 2654 // we can't just call $.effects.mode again later, 2655 // as the .show() below destroys the initial state 2656 modes.push( normalizedMode ); 2657 2658 // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13 2659 if ( defaultMode && ( normalizedMode === "show" || 2660 ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) { 2661 el.show(); 2662 } 2663 2664 if ( !defaultMode || normalizedMode !== "none" ) { 2665 $.effects.saveStyle( el ); 2666 } 2667 2668 if ( $.isFunction( next ) ) { 2669 next(); 2670 } 2671 }; 2672 2673 if ( $.fx.off || !effectMethod ) { 2674 2675 // Delegate to the original method (e.g., .show()) if possible 2676 if ( mode ) { 2677 return this[ mode ]( args.duration, complete ); 2678 } else { 2679 return this.each( function() { 2680 if ( complete ) { 2681 complete.call( this ); 2682 } 2683 } ); 2684 } 2685 } 2686 2687 function run( next ) { 2688 var elem = $( this ); 2689 2690 function cleanup() { 2691 elem.removeData( dataSpaceAnimated ); 2692 2693 $.effects.cleanUp( elem ); 2694 2695 if ( args.mode === "hide" ) { 2696 elem.hide(); 2697 } 2698 2699 done(); 2700 } 2701 2702 function done() { 2703 if ( $.isFunction( complete ) ) { 2704 complete.call( elem[ 0 ] ); 2705 } 2706 2707 if ( $.isFunction( next ) ) { 2708 next(); 2709 } 2710 } 2711 2712 // Override mode option on a per element basis, 2713 // as toggle can be either show or hide depending on element state 2714 args.mode = modes.shift(); 2715 2716 if ( $.uiBackCompat !== false && !defaultMode ) { 2717 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { 2718 2719 // Call the core method to track "olddisplay" properly 2720 elem[ mode ](); 2721 done(); 2722 } else { 2723 effectMethod.call( elem[ 0 ], args, done ); 2724 } 2725 } else { 2726 if ( args.mode === "none" ) { 2727 2728 // Call the core method to track "olddisplay" properly 2729 elem[ mode ](); 2730 done(); 2731 } else { 2732 effectMethod.call( elem[ 0 ], args, cleanup ); 2733 } 2734 } 2735 } 2736 2737 // Run prefilter on all elements first to ensure that 2738 // any showing or hiding happens before placeholder creation, 2739 // which ensures that any layout changes are correctly captured. 2740 return queue === false ? 2741 this.each( prefilter ).each( run ) : 2742 this.queue( queueName, prefilter ).queue( queueName, run ); 2743 }, 2744 2745 show: ( function( orig ) { 2746 return function( option ) { 2747 if ( standardAnimationOption( option ) ) { 2748 return orig.apply( this, arguments ); 2749 } else { 2750 var args = _normalizeArguments.apply( this, arguments ); 2751 args.mode = "show"; 2752 return this.effect.call( this, args ); 2753 } 2754 }; 2755 } )( $.fn.show ), 2756 2757 hide: ( function( orig ) { 2758 return function( option ) { 2759 if ( standardAnimationOption( option ) ) { 2760 return orig.apply( this, arguments ); 2761 } else { 2762 var args = _normalizeArguments.apply( this, arguments ); 2763 args.mode = "hide"; 2764 return this.effect.call( this, args ); 2765 } 2766 }; 2767 } )( $.fn.hide ), 2768 2769 toggle: ( function( orig ) { 2770 return function( option ) { 2771 if ( standardAnimationOption( option ) || typeof option === "boolean" ) { 2772 return orig.apply( this, arguments ); 2773 } else { 2774 var args = _normalizeArguments.apply( this, arguments ); 2775 args.mode = "toggle"; 2776 return this.effect.call( this, args ); 2777 } 2778 }; 2779 } )( $.fn.toggle ), 2780 2781 cssUnit: function( key ) { 2782 var style = this.css( key ), 2783 val = []; 2784 2785 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { 2786 if ( style.indexOf( unit ) > 0 ) { 2787 val = [ parseFloat( style ), unit ]; 2788 } 2789 } ); 2790 return val; 2791 }, 2792 2793 cssClip: function( clipObj ) { 2794 if ( clipObj ) { 2795 return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " + 2796 clipObj.bottom + "px " + clipObj.left + "px)" ); 2797 } 2798 return parseClip( this.css( "clip" ), this ); 2799 }, 2800 2801 transfer: function( options, done ) { 2802 var element = $( this ), 2803 target = $( options.to ), 2804 targetFixed = target.css( "position" ) === "fixed", 2805 body = $( "body" ), 2806 fixTop = targetFixed ? body.scrollTop() : 0, 2807 fixLeft = targetFixed ? body.scrollLeft() : 0, 2808 endPosition = target.offset(), 2809 animation = { 2810 top: endPosition.top - fixTop, 2811 left: endPosition.left - fixLeft, 2812 height: target.innerHeight(), 2813 width: target.innerWidth() 2814 }, 2815 startPosition = element.offset(), 2816 transfer = $( "<div class='ui-effects-transfer'></div>" ) 2817 .appendTo( "body" ) 2818 .addClass( options.className ) 2819 .css( { 2820 top: startPosition.top - fixTop, 2821 left: startPosition.left - fixLeft, 2822 height: element.innerHeight(), 2823 width: element.innerWidth(), 2824 position: targetFixed ? "fixed" : "absolute" 2825 } ) 2826 .animate( animation, options.duration, options.easing, function() { 2827 transfer.remove(); 2828 if ( $.isFunction( done ) ) { 2829 done(); 2830 } 2831 } ); 2832 } 2833 } ); 2834 2835 function parseClip( str, element ) { 2836 var outerWidth = element.outerWidth(), 2837 outerHeight = element.outerHeight(), 2838 clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/, 2839 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ]; 2840 2841 return { 2842 top: parseFloat( values[ 1 ] ) || 0, 2843 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ), 2844 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ), 2845 left: parseFloat( values[ 4 ] ) || 0 2846 }; 2847 } 2848 2849 $.fx.step.clip = function( fx ) { 2850 if ( !fx.clipInit ) { 2851 fx.start = $( fx.elem ).cssClip(); 2852 if ( typeof fx.end === "string" ) { 2853 fx.end = parseClip( fx.end, fx.elem ); 2854 } 2855 fx.clipInit = true; 2856 } 2857 2858 $( fx.elem ).cssClip( { 2859 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top, 2860 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right, 2861 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom, 2862 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left 2863 } ); 2864 }; 2865 2866 } )(); 2867 2868 /******************************************************************************/ 2869 /*********************************** EASING ***********************************/ 2870 /******************************************************************************/ 2871 2872 ( function() { 2873 2874 // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing) 2875 2876 var baseEasings = {}; 2877 2878 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { 2879 baseEasings[ name ] = function( p ) { 2880 return Math.pow( p, i + 2 ); 2881 }; 2882 } ); 2883 2884 $.extend( baseEasings, { 2885 Sine: function( p ) { 2886 return 1 - Math.cos( p * Math.PI / 2 ); 2887 }, 2888 Circ: function( p ) { 2889 return 1 - Math.sqrt( 1 - p * p ); 2890 }, 2891 Elastic: function( p ) { 2892 return p === 0 || p === 1 ? p : 2893 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 ); 2894 }, 2895 Back: function( p ) { 2896 return p * p * ( 3 * p - 2 ); 2897 }, 2898 Bounce: function( p ) { 2899 var pow2, 2900 bounce = 4; 2901 2902 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} 2903 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); 2904 } 2905 } ); 2906 2907 $.each( baseEasings, function( name, easeIn ) { 2908 $.easing[ "easeIn" + name ] = easeIn; 2909 $.easing[ "easeOut" + name ] = function( p ) { 2910 return 1 - easeIn( 1 - p ); 2911 }; 2912 $.easing[ "easeInOut" + name ] = function( p ) { 2913 return p < 0.5 ? 2914 easeIn( p * 2 ) / 2 : 2915 1 - easeIn( p * -2 + 2 ) / 2; 2916 }; 2917 } ); 2918 2919 } )(); 2920 2921 var effect = $.effects; 2922 2923 2924 /*! 2925 * jQuery UI Effects Blind 1.12.1 2926 * http://jqueryui.com 2927 * 2928 * Copyright jQuery Foundation and other contributors 2929 * Released under the MIT license. 2930 * http://jquery.org/license 2931 */ 2932 2933 //>>label: Blind Effect 2934 //>>group: Effects 2935 //>>description: Blinds the element. 2936 //>>docs: http://api.jqueryui.com/blind-effect/ 2937 //>>demos: http://jqueryui.com/effect/ 2938 2939 2940 2941 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) { 2942 var map = { 2943 up: [ "bottom", "top" ], 2944 vertical: [ "bottom", "top" ], 2945 down: [ "top", "bottom" ], 2946 left: [ "right", "left" ], 2947 horizontal: [ "right", "left" ], 2948 right: [ "left", "right" ] 2949 }, 2950 element = $( this ), 2951 direction = options.direction || "up", 2952 start = element.cssClip(), 2953 animate = { clip: $.extend( {}, start ) }, 2954 placeholder = $.effects.createPlaceholder( element ); 2955 2956 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ]; 2957 2958 if ( options.mode === "show" ) { 2959 element.cssClip( animate.clip ); 2960 if ( placeholder ) { 2961 placeholder.css( $.effects.clipToBox( animate ) ); 2962 } 2963 2964 animate.clip = start; 2965 } 2966 2967 if ( placeholder ) { 2968 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing ); 2969 } 2970 2971 element.animate( animate, { 2972 queue: false, 2973 duration: options.duration, 2974 easing: options.easing, 2975 complete: done 2976 } ); 2977 } ); 2978 2979 2980 /*! 2981 * jQuery UI Effects Bounce 1.12.1 2982 * http://jqueryui.com 2983 * 2984 * Copyright jQuery Foundation and other contributors 2985 * Released under the MIT license. 2986 * http://jquery.org/license 2987 */ 2988 2989 //>>label: Bounce Effect 2990 //>>group: Effects 2991 //>>description: Bounces an element horizontally or vertically n times. 2992 //>>docs: http://api.jqueryui.com/bounce-effect/ 2993 //>>demos: http://jqueryui.com/effect/ 2994 2995 2996 2997 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) { 2998 var upAnim, downAnim, refValue, 2999 element = $( this ), 3000 3001 // Defaults: 3002 mode = options.mode, 3003 hide = mode === "hide", 3004 show = mode === "show", 3005 direction = options.direction || "up", 3006 distance = options.distance, 3007 times = options.times || 5, 3008 3009 // Number of internal animations 3010 anims = times * 2 + ( show || hide ? 1 : 0 ), 3011 speed = options.duration / anims, 3012 easing = options.easing, 3013 3014 // Utility: 3015 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3016 motion = ( direction === "up" || direction === "left" ), 3017 i = 0, 3018 3019 queuelen = element.queue().length; 3020 3021 $.effects.createPlaceholder( element ); 3022 3023 refValue = element.css( ref ); 3024 3025 // Default distance for the BIGGEST bounce is the outer Distance / 3 3026 if ( !distance ) { 3027 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; 3028 } 3029 3030 if ( show ) { 3031 downAnim = { opacity: 1 }; 3032 downAnim[ ref ] = refValue; 3033 3034 // If we are showing, force opacity 0 and set the initial position 3035 // then do the "first" animation 3036 element 3037 .css( "opacity", 0 ) 3038 .css( ref, motion ? -distance * 2 : distance * 2 ) 3039 .animate( downAnim, speed, easing ); 3040 } 3041 3042 // Start at the smallest distance if we are hiding 3043 if ( hide ) { 3044 distance = distance / Math.pow( 2, times - 1 ); 3045 } 3046 3047 downAnim = {}; 3048 downAnim[ ref ] = refValue; 3049 3050 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here 3051 for ( ; i < times; i++ ) { 3052 upAnim = {}; 3053 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 3054 3055 element 3056 .animate( upAnim, speed, easing ) 3057 .animate( downAnim, speed, easing ); 3058 3059 distance = hide ? distance * 2 : distance / 2; 3060 } 3061 3062 // Last Bounce when Hiding 3063 if ( hide ) { 3064 upAnim = { opacity: 0 }; 3065 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 3066 3067 element.animate( upAnim, speed, easing ); 3068 } 3069 3070 element.queue( done ); 3071 3072 $.effects.unshift( element, queuelen, anims + 1 ); 3073 } ); 3074 3075 3076 /*! 3077 * jQuery UI Effects Clip 1.12.1 3078 * http://jqueryui.com 3079 * 3080 * Copyright jQuery Foundation and other contributors 3081 * Released under the MIT license. 3082 * http://jquery.org/license 3083 */ 3084 3085 //>>label: Clip Effect 3086 //>>group: Effects 3087 //>>description: Clips the element on and off like an old TV. 3088 //>>docs: http://api.jqueryui.com/clip-effect/ 3089 //>>demos: http://jqueryui.com/effect/ 3090 3091 3092 3093 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) { 3094 var start, 3095 animate = {}, 3096 element = $( this ), 3097 direction = options.direction || "vertical", 3098 both = direction === "both", 3099 horizontal = both || direction === "horizontal", 3100 vertical = both || direction === "vertical"; 3101 3102 start = element.cssClip(); 3103 animate.clip = { 3104 top: vertical ? ( start.bottom - start.top ) / 2 : start.top, 3105 right: horizontal ? ( start.right - start.left ) / 2 : start.right, 3106 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom, 3107 left: horizontal ? ( start.right - start.left ) / 2 : start.left 3108 }; 3109 3110 $.effects.createPlaceholder( element ); 3111 3112 if ( options.mode === "show" ) { 3113 element.cssClip( animate.clip ); 3114 animate.clip = start; 3115 } 3116 3117 element.animate( animate, { 3118 queue: false, 3119 duration: options.duration, 3120 easing: options.easing, 3121 complete: done 3122 } ); 3123 3124 } ); 3125 3126 3127 /*! 3128 * jQuery UI Effects Drop 1.12.1 3129 * http://jqueryui.com 3130 * 3131 * Copyright jQuery Foundation and other contributors 3132 * Released under the MIT license. 3133 * http://jquery.org/license 3134 */ 3135 3136 //>>label: Drop Effect 3137 //>>group: Effects 3138 //>>description: Moves an element in one direction and hides it at the same time. 3139 //>>docs: http://api.jqueryui.com/drop-effect/ 3140 //>>demos: http://jqueryui.com/effect/ 3141 3142 3143 3144 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) { 3145 3146 var distance, 3147 element = $( this ), 3148 mode = options.mode, 3149 show = mode === "show", 3150 direction = options.direction || "left", 3151 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3152 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=", 3153 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=", 3154 animation = { 3155 opacity: 0 3156 }; 3157 3158 $.effects.createPlaceholder( element ); 3159 3160 distance = options.distance || 3161 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; 3162 3163 animation[ ref ] = motion + distance; 3164 3165 if ( show ) { 3166 element.css( animation ); 3167 3168 animation[ ref ] = oppositeMotion + distance; 3169 animation.opacity = 1; 3170 } 3171 3172 // Animate 3173 element.animate( animation, { 3174 queue: false, 3175 duration: options.duration, 3176 easing: options.easing, 3177 complete: done 3178 } ); 3179 } ); 3180 3181 3182 /*! 3183 * jQuery UI Effects Explode 1.12.1 3184 * http://jqueryui.com 3185 * 3186 * Copyright jQuery Foundation and other contributors 3187 * Released under the MIT license. 3188 * http://jquery.org/license 3189 */ 3190 3191 //>>label: Explode Effect 3192 //>>group: Effects 3193 // jscs:disable maximumLineLength 3194 //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness. 3195 // jscs:enable maximumLineLength 3196 //>>docs: http://api.jqueryui.com/explode-effect/ 3197 //>>demos: http://jqueryui.com/effect/ 3198 3199 3200 3201 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) { 3202 3203 var i, j, left, top, mx, my, 3204 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3, 3205 cells = rows, 3206 element = $( this ), 3207 mode = options.mode, 3208 show = mode === "show", 3209 3210 // Show and then visibility:hidden the element before calculating offset 3211 offset = element.show().css( "visibility", "hidden" ).offset(), 3212 3213 // Width and height of a piece 3214 width = Math.ceil( element.outerWidth() / cells ), 3215 height = Math.ceil( element.outerHeight() / rows ), 3216 pieces = []; 3217 3218 // Children animate complete: 3219 function childComplete() { 3220 pieces.push( this ); 3221 if ( pieces.length === rows * cells ) { 3222 animComplete(); 3223 } 3224 } 3225 3226 // Clone the element for each row and cell. 3227 for ( i = 0; i < rows; i++ ) { // ===> 3228 top = offset.top + i * height; 3229 my = i - ( rows - 1 ) / 2; 3230 3231 for ( j = 0; j < cells; j++ ) { // ||| 3232 left = offset.left + j * width; 3233 mx = j - ( cells - 1 ) / 2; 3234 3235 // Create a clone of the now hidden main element that will be absolute positioned 3236 // within a wrapper div off the -left and -top equal to size of our pieces 3237 element 3238 .clone() 3239 .appendTo( "body" ) 3240 .wrap( "<div></div>" ) 3241 .css( { 3242 position: "absolute", 3243 visibility: "visible", 3244 left: -j * width, 3245 top: -i * height 3246 } ) 3247 3248 // Select the wrapper - make it overflow: hidden and absolute positioned based on 3249 // where the original was located +left and +top equal to the size of pieces 3250 .parent() 3251 .addClass( "ui-effects-explode" ) 3252 .css( { 3253 position: "absolute", 3254 overflow: "hidden", 3255 width: width, 3256 height: height, 3257 left: left + ( show ? mx * width : 0 ), 3258 top: top + ( show ? my * height : 0 ), 3259 opacity: show ? 0 : 1 3260 } ) 3261 .animate( { 3262 left: left + ( show ? 0 : mx * width ), 3263 top: top + ( show ? 0 : my * height ), 3264 opacity: show ? 1 : 0 3265 }, options.duration || 500, options.easing, childComplete ); 3266 } 3267 } 3268 3269 function animComplete() { 3270 element.css( { 3271 visibility: "visible" 3272 } ); 3273 $( pieces ).remove(); 3274 done(); 3275 } 3276 } ); 3277 3278 3279 /*! 3280 * jQuery UI Effects Fade 1.12.1 3281 * http://jqueryui.com 3282 * 3283 * Copyright jQuery Foundation and other contributors 3284 * Released under the MIT license. 3285 * http://jquery.org/license 3286 */ 3287 3288 //>>label: Fade Effect 3289 //>>group: Effects 3290 //>>description: Fades the element. 3291 //>>docs: http://api.jqueryui.com/fade-effect/ 3292 //>>demos: http://jqueryui.com/effect/ 3293 3294 3295 3296 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) { 3297 var show = options.mode === "show"; 3298 3299 $( this ) 3300 .css( "opacity", show ? 0 : 1 ) 3301 .animate( { 3302 opacity: show ? 1 : 0 3303 }, { 3304 queue: false, 3305 duration: options.duration, 3306 easing: options.easing, 3307 complete: done 3308 } ); 3309 } ); 3310 3311 3312 /*! 3313 * jQuery UI Effects Fold 1.12.1 3314 * http://jqueryui.com 3315 * 3316 * Copyright jQuery Foundation and other contributors 3317 * Released under the MIT license. 3318 * http://jquery.org/license 3319 */ 3320 3321 //>>label: Fold Effect 3322 //>>group: Effects 3323 //>>description: Folds an element first horizontally and then vertically. 3324 //>>docs: http://api.jqueryui.com/fold-effect/ 3325 //>>demos: http://jqueryui.com/effect/ 3326 3327 3328 3329 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) { 3330 3331 // Create element 3332 var element = $( this ), 3333 mode = options.mode, 3334 show = mode === "show", 3335 hide = mode === "hide", 3336 size = options.size || 15, 3337 percent = /([0-9]+)%/.exec( size ), 3338 horizFirst = !!options.horizFirst, 3339 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ], 3340 duration = options.duration / 2, 3341 3342 placeholder = $.effects.createPlaceholder( element ), 3343 3344 start = element.cssClip(), 3345 animation1 = { clip: $.extend( {}, start ) }, 3346 animation2 = { clip: $.extend( {}, start ) }, 3347 3348 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ], 3349 3350 queuelen = element.queue().length; 3351 3352 if ( percent ) { 3353 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; 3354 } 3355 animation1.clip[ ref[ 0 ] ] = size; 3356 animation2.clip[ ref[ 0 ] ] = size; 3357 animation2.clip[ ref[ 1 ] ] = 0; 3358 3359 if ( show ) { 3360 element.cssClip( animation2.clip ); 3361 if ( placeholder ) { 3362 placeholder.css( $.effects.clipToBox( animation2 ) ); 3363 } 3364 3365 animation2.clip = start; 3366 } 3367 3368 // Animate 3369 element 3370 .queue( function( next ) { 3371 if ( placeholder ) { 3372 placeholder 3373 .animate( $.effects.clipToBox( animation1 ), duration, options.easing ) 3374 .animate( $.effects.clipToBox( animation2 ), duration, options.easing ); 3375 } 3376 3377 next(); 3378 } ) 3379 .animate( animation1, duration, options.easing ) 3380 .animate( animation2, duration, options.easing ) 3381 .queue( done ); 3382 3383 $.effects.unshift( element, queuelen, 4 ); 3384 } ); 3385 3386 3387 /*! 3388 * jQuery UI Effects Highlight 1.12.1 3389 * http://jqueryui.com 3390 * 3391 * Copyright jQuery Foundation and other contributors 3392 * Released under the MIT license. 3393 * http://jquery.org/license 3394 */ 3395 3396 //>>label: Highlight Effect 3397 //>>group: Effects 3398 //>>description: Highlights the background of an element in a defined color for a custom duration. 3399 //>>docs: http://api.jqueryui.com/highlight-effect/ 3400 //>>demos: http://jqueryui.com/effect/ 3401 3402 3403 3404 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) { 3405 var element = $( this ), 3406 animation = { 3407 backgroundColor: element.css( "backgroundColor" ) 3408 }; 3409 3410 if ( options.mode === "hide" ) { 3411 animation.opacity = 0; 3412 } 3413 3414 $.effects.saveStyle( element ); 3415 3416 element 3417 .css( { 3418 backgroundImage: "none", 3419 backgroundColor: options.color || "#ffff99" 3420 } ) 3421 .animate( animation, { 3422 queue: false, 3423 duration: options.duration, 3424 easing: options.easing, 3425 complete: done 3426 } ); 3427 } ); 3428 3429 3430 /*! 3431 * jQuery UI Effects Size 1.12.1 3432 * http://jqueryui.com 3433 * 3434 * Copyright jQuery Foundation and other contributors 3435 * Released under the MIT license. 3436 * http://jquery.org/license 3437 */ 3438 3439 //>>label: Size Effect 3440 //>>group: Effects 3441 //>>description: Resize an element to a specified width and height. 3442 //>>docs: http://api.jqueryui.com/size-effect/ 3443 //>>demos: http://jqueryui.com/effect/ 3444 3445 3446 3447 var effectsEffectSize = $.effects.define( "size", function( options, done ) { 3448 3449 // Create element 3450 var baseline, factor, temp, 3451 element = $( this ), 3452 3453 // Copy for children 3454 cProps = [ "fontSize" ], 3455 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], 3456 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], 3457 3458 // Set options 3459 mode = options.mode, 3460 restore = mode !== "effect", 3461 scale = options.scale || "both", 3462 origin = options.origin || [ "middle", "center" ], 3463 position = element.css( "position" ), 3464 pos = element.position(), 3465 original = $.effects.scaledDimensions( element ), 3466 from = options.from || original, 3467 to = options.to || $.effects.scaledDimensions( element, 0 ); 3468 3469 $.effects.createPlaceholder( element ); 3470 3471 if ( mode === "show" ) { 3472 temp = from; 3473 from = to; 3474 to = temp; 3475 } 3476 3477 // Set scaling factor 3478 factor = { 3479 from: { 3480 y: from.height / original.height, 3481 x: from.width / original.width 3482 }, 3483 to: { 3484 y: to.height / original.height, 3485 x: to.width / original.width 3486 } 3487 }; 3488 3489 // Scale the css box 3490 if ( scale === "box" || scale === "both" ) { 3491 3492 // Vertical props scaling 3493 if ( factor.from.y !== factor.to.y ) { 3494 from = $.effects.setTransition( element, vProps, factor.from.y, from ); 3495 to = $.effects.setTransition( element, vProps, factor.to.y, to ); 3496 } 3497 3498 // Horizontal props scaling 3499 if ( factor.from.x !== factor.to.x ) { 3500 from = $.effects.setTransition( element, hProps, factor.from.x, from ); 3501 to = $.effects.setTransition( element, hProps, factor.to.x, to ); 3502 } 3503 } 3504 3505 // Scale the content 3506 if ( scale === "content" || scale === "both" ) { 3507 3508 // Vertical props scaling 3509 if ( factor.from.y !== factor.to.y ) { 3510 from = $.effects.setTransition( element, cProps, factor.from.y, from ); 3511 to = $.effects.setTransition( element, cProps, factor.to.y, to ); 3512 } 3513 } 3514 3515 // Adjust the position properties based on the provided origin points 3516 if ( origin ) { 3517 baseline = $.effects.getBaseline( origin, original ); 3518 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top; 3519 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left; 3520 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top; 3521 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left; 3522 } 3523 element.css( from ); 3524 3525 // Animate the children if desired 3526 if ( scale === "content" || scale === "both" ) { 3527 3528 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps ); 3529 hProps = hProps.concat( [ "marginLeft", "marginRight" ] ); 3530 3531 // Only animate children with width attributes specified 3532 // TODO: is this right? should we include anything with css width specified as well 3533 element.find( "*[width]" ).each( function() { 3534 var child = $( this ), 3535 childOriginal = $.effects.scaledDimensions( child ), 3536 childFrom = { 3537 height: childOriginal.height * factor.from.y, 3538 width: childOriginal.width * factor.from.x, 3539 outerHeight: childOriginal.outerHeight * factor.from.y, 3540 outerWidth: childOriginal.outerWidth * factor.from.x 3541 }, 3542 childTo = { 3543 height: childOriginal.height * factor.to.y, 3544 width: childOriginal.width * factor.to.x, 3545 outerHeight: childOriginal.height * factor.to.y, 3546 outerWidth: childOriginal.width * factor.to.x 3547 }; 3548 3549 // Vertical props scaling 3550 if ( factor.from.y !== factor.to.y ) { 3551 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom ); 3552 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo ); 3553 } 3554 3555 // Horizontal props scaling 3556 if ( factor.from.x !== factor.to.x ) { 3557 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom ); 3558 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo ); 3559 } 3560 3561 if ( restore ) { 3562 $.effects.saveStyle( child ); 3563 } 3564 3565 // Animate children 3566 child.css( childFrom ); 3567 child.animate( childTo, options.duration, options.easing, function() { 3568 3569 // Restore children 3570 if ( restore ) { 3571 $.effects.restoreStyle( child ); 3572 } 3573 } ); 3574 } ); 3575 } 3576 3577 // Animate 3578 element.animate( to, { 3579 queue: false, 3580 duration: options.duration, 3581 easing: options.easing, 3582 complete: function() { 3583 3584 var offset = element.offset(); 3585 3586 if ( to.opacity === 0 ) { 3587 element.css( "opacity", from.opacity ); 3588 } 3589 3590 if ( !restore ) { 3591 element 3592 .css( "position", position === "static" ? "relative" : position ) 3593 .offset( offset ); 3594 3595 // Need to save style here so that automatic style restoration 3596 // doesn't restore to the original styles from before the animation. 3597 $.effects.saveStyle( element ); 3598 } 3599 3600 done(); 3601 } 3602 } ); 3603 3604 } ); 3605 3606 3607 /*! 3608 * jQuery UI Effects Scale 1.12.1 3609 * http://jqueryui.com 3610 * 3611 * Copyright jQuery Foundation and other contributors 3612 * Released under the MIT license. 3613 * http://jquery.org/license 3614 */ 3615 3616 //>>label: Scale Effect 3617 //>>group: Effects 3618 //>>description: Grows or shrinks an element and its content. 3619 //>>docs: http://api.jqueryui.com/scale-effect/ 3620 //>>demos: http://jqueryui.com/effect/ 3621 3622 3623 3624 var effectsEffectScale = $.effects.define( "scale", function( options, done ) { 3625 3626 // Create element 3627 var el = $( this ), 3628 mode = options.mode, 3629 percent = parseInt( options.percent, 10 ) || 3630 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ), 3631 3632 newOptions = $.extend( true, { 3633 from: $.effects.scaledDimensions( el ), 3634 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ), 3635 origin: options.origin || [ "middle", "center" ] 3636 }, options ); 3637 3638 // Fade option to support puff 3639 if ( options.fade ) { 3640 newOptions.from.opacity = 1; 3641 newOptions.to.opacity = 0; 3642 } 3643 3644 $.effects.effect.size.call( this, newOptions, done ); 3645 } ); 3646 3647 3648 /*! 3649 * jQuery UI Effects Puff 1.12.1 3650 * http://jqueryui.com 3651 * 3652 * Copyright jQuery Foundation and other contributors 3653 * Released under the MIT license. 3654 * http://jquery.org/license 3655 */ 3656 3657 //>>label: Puff Effect 3658 //>>group: Effects 3659 //>>description: Creates a puff effect by scaling the element up and hiding it at the same time. 3660 //>>docs: http://api.jqueryui.com/puff-effect/ 3661 //>>demos: http://jqueryui.com/effect/ 3662 3663 3664 3665 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) { 3666 var newOptions = $.extend( true, {}, options, { 3667 fade: true, 3668 percent: parseInt( options.percent, 10 ) || 150 3669 } ); 3670 3671 $.effects.effect.scale.call( this, newOptions, done ); 3672 } ); 3673 3674 3675 /*! 3676 * jQuery UI Effects Pulsate 1.12.1 3677 * http://jqueryui.com 3678 * 3679 * Copyright jQuery Foundation and other contributors 3680 * Released under the MIT license. 3681 * http://jquery.org/license 3682 */ 3683 3684 //>>label: Pulsate Effect 3685 //>>group: Effects 3686 //>>description: Pulsates an element n times by changing the opacity to zero and back. 3687 //>>docs: http://api.jqueryui.com/pulsate-effect/ 3688 //>>demos: http://jqueryui.com/effect/ 3689 3690 3691 3692 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) { 3693 var element = $( this ), 3694 mode = options.mode, 3695 show = mode === "show", 3696 hide = mode === "hide", 3697 showhide = show || hide, 3698 3699 // Showing or hiding leaves off the "last" animation 3700 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), 3701 duration = options.duration / anims, 3702 animateTo = 0, 3703 i = 1, 3704 queuelen = element.queue().length; 3705 3706 if ( show || !element.is( ":visible" ) ) { 3707 element.css( "opacity", 0 ).show(); 3708 animateTo = 1; 3709 } 3710 3711 // Anims - 1 opacity "toggles" 3712 for ( ; i < anims; i++ ) { 3713 element.animate( { opacity: animateTo }, duration, options.easing ); 3714 animateTo = 1 - animateTo; 3715 } 3716 3717 element.animate( { opacity: animateTo }, duration, options.easing ); 3718 3719 element.queue( done ); 3720 3721 $.effects.unshift( element, queuelen, anims + 1 ); 3722 } ); 3723 3724 3725 /*! 3726 * jQuery UI Effects Shake 1.12.1 3727 * http://jqueryui.com 3728 * 3729 * Copyright jQuery Foundation and other contributors 3730 * Released under the MIT license. 3731 * http://jquery.org/license 3732 */ 3733 3734 //>>label: Shake Effect 3735 //>>group: Effects 3736 //>>description: Shakes an element horizontally or vertically n times. 3737 //>>docs: http://api.jqueryui.com/shake-effect/ 3738 //>>demos: http://jqueryui.com/effect/ 3739 3740 3741 3742 var effectsEffectShake = $.effects.define( "shake", function( options, done ) { 3743 3744 var i = 1, 3745 element = $( this ), 3746 direction = options.direction || "left", 3747 distance = options.distance || 20, 3748 times = options.times || 3, 3749 anims = times * 2 + 1, 3750 speed = Math.round( options.duration / anims ), 3751 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3752 positiveMotion = ( direction === "up" || direction === "left" ), 3753 animation = {}, 3754 animation1 = {}, 3755 animation2 = {}, 3756 3757 queuelen = element.queue().length; 3758 3759 $.effects.createPlaceholder( element ); 3760 3761 // Animation 3762 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; 3763 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; 3764 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; 3765 3766 // Animate 3767 element.animate( animation, speed, options.easing ); 3768 3769 // Shakes 3770 for ( ; i < times; i++ ) { 3771 element 3772 .animate( animation1, speed, options.easing ) 3773 .animate( animation2, speed, options.easing ); 3774 } 3775 3776 element 3777 .animate( animation1, speed, options.easing ) 3778 .animate( animation, speed / 2, options.easing ) 3779 .queue( done ); 3780 3781 $.effects.unshift( element, queuelen, anims + 1 ); 3782 } ); 3783 3784 3785 /*! 3786 * jQuery UI Effects Slide 1.12.1 3787 * http://jqueryui.com 3788 * 3789 * Copyright jQuery Foundation and other contributors 3790 * Released under the MIT license. 3791 * http://jquery.org/license 3792 */ 3793 3794 //>>label: Slide Effect 3795 //>>group: Effects 3796 //>>description: Slides an element in and out of the viewport. 3797 //>>docs: http://api.jqueryui.com/slide-effect/ 3798 //>>demos: http://jqueryui.com/effect/ 3799 3800 3801 3802 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) { 3803 var startClip, startRef, 3804 element = $( this ), 3805 map = { 3806 up: [ "bottom", "top" ], 3807 down: [ "top", "bottom" ], 3808 left: [ "right", "left" ], 3809 right: [ "left", "right" ] 3810 }, 3811 mode = options.mode, 3812 direction = options.direction || "left", 3813 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3814 positiveMotion = ( direction === "up" || direction === "left" ), 3815 distance = options.distance || 3816 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ), 3817 animation = {}; 3818 3819 $.effects.createPlaceholder( element ); 3820 3821 startClip = element.cssClip(); 3822 startRef = element.position()[ ref ]; 3823 3824 // Define hide animation 3825 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef; 3826 animation.clip = element.cssClip(); 3827 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ]; 3828 3829 // Reverse the animation if we're showing 3830 if ( mode === "show" ) { 3831 element.cssClip( animation.clip ); 3832 element.css( ref, animation[ ref ] ); 3833 animation.clip = startClip; 3834 animation[ ref ] = startRef; 3835 } 3836 3837 // Actually animate 3838 element.animate( animation, { 3839 queue: false, 3840 duration: options.duration, 3841 easing: options.easing, 3842 complete: done 3843 } ); 3844 } ); 3845 3846 3847 /*! 3848 * jQuery UI Effects Transfer 1.12.1 3849 * http://jqueryui.com 3850 * 3851 * Copyright jQuery Foundation and other contributors 3852 * Released under the MIT license. 3853 * http://jquery.org/license 3854 */ 3855 3856 //>>label: Transfer Effect 3857 //>>group: Effects 3858 //>>description: Displays a transfer effect from one element to another. 3859 //>>docs: http://api.jqueryui.com/transfer-effect/ 3860 //>>demos: http://jqueryui.com/effect/ 3861 3862 3863 3864 var effect; 3865 if ( $.uiBackCompat !== false ) { 3866 effect = $.effects.define( "transfer", function( options, done ) { 3867 $( this ).transfer( options, done ); 3868 } ); 3869 } 3870 var effectsEffectTransfer = effect; 3871 3872 3873 /*! 3874 * jQuery UI Focusable 1.12.1 3875 * http://jqueryui.com 3876 * 3877 * Copyright jQuery Foundation and other contributors 3878 * Released under the MIT license. 3879 * http://jquery.org/license 3880 */ 3881 3882 //>>label: :focusable Selector 3883 //>>group: Core 3884 //>>description: Selects elements which can be focused. 3885 //>>docs: http://api.jqueryui.com/focusable-selector/ 3886 3887 3888 3889 // Selectors 3890 $.ui.focusable = function( element, hasTabindex ) { 3891 var map, mapName, img, focusableIfVisible, fieldset, 3892 nodeName = element.nodeName.toLowerCase(); 3893 3894 if ( "area" === nodeName ) { 3895 map = element.parentNode; 3896 mapName = map.name; 3897 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { 3898 return false; 3899 } 3900 img = $( "img[usemap='#" + mapName + "']" ); 3901 return img.length > 0 && img.is( ":visible" ); 3902 } 3903 3904 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { 3905 focusableIfVisible = !element.disabled; 3906 3907 if ( focusableIfVisible ) { 3908 3909 // Form controls within a disabled fieldset are disabled. 3910 // However, controls within the fieldset's legend do not get disabled. 3911 // Since controls generally aren't placed inside legends, we skip 3912 // this portion of the check. 3913 fieldset = $( element ).closest( "fieldset" )[ 0 ]; 3914 if ( fieldset ) { 3915 focusableIfVisible = !fieldset.disabled; 3916 } 3917 } 3918 } else if ( "a" === nodeName ) { 3919 focusableIfVisible = element.href || hasTabindex; 3920 } else { 3921 focusableIfVisible = hasTabindex; 3922 } 3923 3924 return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) ); 3925 }; 3926 3927 // Support: IE 8 only 3928 // IE 8 doesn't resolve inherit to visible/hidden for computed values 3929 function visible( element ) { 3930 var visibility = element.css( "visibility" ); 3931 while ( visibility === "inherit" ) { 3932 element = element.parent(); 3933 visibility = element.css( "visibility" ); 3934 } 3935 return visibility !== "hidden"; 3936 } 3937 3938 $.extend( $.expr[ ":" ], { 3939 focusable: function( element ) { 3940 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); 3941 } 3942 } ); 3943 3944 var focusable = $.ui.focusable; 3945 3946 3947 3948 3949 // Support: IE8 Only 3950 // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop 3951 // with a string, so we need to find the proper form. 3952 var form = $.fn.form = function() { 3953 return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form ); 3954 }; 3955 3956 3957 /*! 3958 * jQuery UI Form Reset Mixin 1.12.1 3959 * http://jqueryui.com 3960 * 3961 * Copyright jQuery Foundation and other contributors 3962 * Released under the MIT license. 3963 * http://jquery.org/license 3964 */ 3965 3966 //>>label: Form Reset Mixin 3967 //>>group: Core 3968 //>>description: Refresh input widgets when their form is reset 3969 //>>docs: http://api.jqueryui.com/form-reset-mixin/ 3970 3971 3972 3973 var formResetMixin = $.ui.formResetMixin = { 3974 _formResetHandler: function() { 3975 var form = $( this ); 3976 3977 // Wait for the form reset to actually happen before refreshing 3978 setTimeout( function() { 3979 var instances = form.data( "ui-form-reset-instances" ); 3980 $.each( instances, function() { 3981 this.refresh(); 3982 } ); 3983 } ); 3984 }, 3985 3986 _bindFormResetHandler: function() { 3987 this.form = this.element.form(); 3988 if ( !this.form.length ) { 3989 return; 3990 } 3991 3992 var instances = this.form.data( "ui-form-reset-instances" ) || []; 3993 if ( !instances.length ) { 3994 3995 // We don't use _on() here because we use a single event handler per form 3996 this.form.on( "reset.ui-form-reset", this._formResetHandler ); 3997 } 3998 instances.push( this ); 3999 this.form.data( "ui-form-reset-instances", instances ); 4000 }, 4001 4002 _unbindFormResetHandler: function() { 4003 if ( !this.form.length ) { 4004 return; 4005 } 4006 4007 var instances = this.form.data( "ui-form-reset-instances" ); 4008 instances.splice( $.inArray( this, instances ), 1 ); 4009 if ( instances.length ) { 4010 this.form.data( "ui-form-reset-instances", instances ); 4011 } else { 4012 this.form 4013 .removeData( "ui-form-reset-instances" ) 4014 .off( "reset.ui-form-reset" ); 4015 } 4016 } 4017 }; 4018 4019 4020 /*! 4021 * jQuery UI Support for jQuery core 1.7.x 1.12.1 4022 * http://jqueryui.com 4023 * 4024 * Copyright jQuery Foundation and other contributors 4025 * Released under the MIT license. 4026 * http://jquery.org/license 4027 * 4028 */ 4029 4030 //>>label: jQuery 1.7 Support 4031 //>>group: Core 4032 //>>description: Support version 1.7.x of jQuery core 4033 4034 4035 4036 // Support: jQuery 1.7 only 4037 // Not a great way to check versions, but since we only support 1.7+ and only 4038 // need to detect <1.8, this is a simple check that should suffice. Checking 4039 // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0 4040 // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting 4041 // 1.7 anymore). See #11197 for why we're not using feature detection. 4042 if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) { 4043 4044 // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight() 4045 // Unlike jQuery Core 1.8+, these only support numeric values to set the 4046 // dimensions in pixels 4047 $.each( [ "Width", "Height" ], function( i, name ) { 4048 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], 4049 type = name.toLowerCase(), 4050 orig = { 4051 innerWidth: $.fn.innerWidth, 4052 innerHeight: $.fn.innerHeight, 4053 outerWidth: $.fn.outerWidth, 4054 outerHeight: $.fn.outerHeight 4055 }; 4056 4057 function reduce( elem, size, border, margin ) { 4058 $.each( side, function() { 4059 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; 4060 if ( border ) { 4061 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; 4062 } 4063 if ( margin ) { 4064 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; 4065 } 4066 } ); 4067 return size; 4068 } 4069 4070 $.fn[ "inner" + name ] = function( size ) { 4071 if ( size === undefined ) { 4072 return orig[ "inner" + name ].call( this ); 4073 } 4074 4075 return this.each( function() { 4076 $( this ).css( type, reduce( this, size ) + "px" ); 4077 } ); 4078 }; 4079 4080 $.fn[ "outer" + name ] = function( size, margin ) { 4081 if ( typeof size !== "number" ) { 4082 return orig[ "outer" + name ].call( this, size ); 4083 } 4084 4085 return this.each( function() { 4086 $( this ).css( type, reduce( this, size, true, margin ) + "px" ); 4087 } ); 4088 }; 4089 } ); 4090 4091 $.fn.addBack = function( selector ) { 4092 return this.add( selector == null ? 4093 this.prevObject : this.prevObject.filter( selector ) 4094 ); 4095 }; 4096 } 4097 4098 ; 4099 /*! 4100 * jQuery UI Keycode 1.12.1 4101 * http://jqueryui.com 4102 * 4103 * Copyright jQuery Foundation and other contributors 4104 * Released under the MIT license. 4105 * http://jquery.org/license 4106 */ 4107 4108 //>>label: Keycode 4109 //>>group: Core 4110 //>>description: Provide keycodes as keynames 4111 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ 4112 4113 4114 var keycode = $.ui.keyCode = { 4115 BACKSPACE: 8, 4116 COMMA: 188, 4117 DELETE: 46, 4118 DOWN: 40, 4119 END: 35, 4120 ENTER: 13, 4121 ESCAPE: 27, 4122 HOME: 36, 4123 LEFT: 37, 4124 PAGE_DOWN: 34, 4125 PAGE_UP: 33, 4126 PERIOD: 190, 4127 RIGHT: 39, 4128 SPACE: 32, 4129 TAB: 9, 4130 UP: 38 4131 }; 4132 4133 4134 4135 4136 // Internal use only 4137 var escapeSelector = $.ui.escapeSelector = ( function() { 4138 var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g; 4139 return function( selector ) { 4140 return selector.replace( selectorEscape, "\\$1" ); 4141 }; 4142 } )(); 4143 4144 4145 /*! 4146 * jQuery UI Labels 1.12.1 4147 * http://jqueryui.com 4148 * 4149 * Copyright jQuery Foundation and other contributors 4150 * Released under the MIT license. 4151 * http://jquery.org/license 4152 */ 4153 4154 //>>label: labels 4155 //>>group: Core 4156 //>>description: Find all the labels associated with a given input 4157 //>>docs: http://api.jqueryui.com/labels/ 4158 4159 4160 4161 var labels = $.fn.labels = function() { 4162 var ancestor, selector, id, labels, ancestors; 4163 4164 // Check control.labels first 4165 if ( this[ 0 ].labels && this[ 0 ].labels.length ) { 4166 return this.pushStack( this[ 0 ].labels ); 4167 } 4168 4169 // Support: IE <= 11, FF <= 37, Android <= 2.3 only 4170 // Above browsers do not support control.labels. Everything below is to support them 4171 // as well as document fragments. control.labels does not work on document fragments 4172 labels = this.eq( 0 ).parents( "label" ); 4173 4174 // Look for the label based on the id 4175 id = this.attr( "id" ); 4176 if ( id ) { 4177 4178 // We don't search against the document in case the element 4179 // is disconnected from the DOM 4180 ancestor = this.eq( 0 ).parents().last(); 4181 4182 // Get a full set of top level ancestors 4183 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); 4184 4185 // Create a selector for the label based on the id 4186 selector = "label[for='" + $.ui.escapeSelector( id ) + "']"; 4187 4188 labels = labels.add( ancestors.find( selector ).addBack( selector ) ); 4189 4190 } 4191 4192 // Return whatever we have found for labels 4193 return this.pushStack( labels ); 4194 }; 4195 4196 4197 /*! 4198 * jQuery UI Scroll Parent 1.12.1 4199 * http://jqueryui.com 4200 * 4201 * Copyright jQuery Foundation and other contributors 4202 * Released under the MIT license. 4203 * http://jquery.org/license 4204 */ 4205 4206 //>>label: scrollParent 4207 //>>group: Core 4208 //>>description: Get the closest ancestor element that is scrollable. 4209 //>>docs: http://api.jqueryui.com/scrollParent/ 4210 4211 4212 4213 var scrollParent = $.fn.scrollParent = function( includeHidden ) { 4214 var position = this.css( "position" ), 4215 excludeStaticParent = position === "absolute", 4216 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, 4217 scrollParent = this.parents().filter( function() { 4218 var parent = $( this ); 4219 if ( excludeStaticParent && parent.css( "position" ) === "static" ) { 4220 return false; 4221 } 4222 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + 4223 parent.css( "overflow-x" ) ); 4224 } ).eq( 0 ); 4225 4226 return position === "fixed" || !scrollParent.length ? 4227 $( this[ 0 ].ownerDocument || document ) : 4228 scrollParent; 4229 }; 4230 4231 4232 /*! 4233 * jQuery UI Tabbable 1.12.1 4234 * http://jqueryui.com 4235 * 4236 * Copyright jQuery Foundation and other contributors 4237 * Released under the MIT license. 4238 * http://jquery.org/license 4239 */ 4240 4241 //>>label: :tabbable Selector 4242 //>>group: Core 4243 //>>description: Selects elements which can be tabbed to. 4244 //>>docs: http://api.jqueryui.com/tabbable-selector/ 4245 4246 4247 4248 var tabbable = $.extend( $.expr[ ":" ], { 4249 tabbable: function( element ) { 4250 var tabIndex = $.attr( element, "tabindex" ), 4251 hasTabindex = tabIndex != null; 4252 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); 4253 } 4254 } ); 4255 4256 4257 /*! 4258 * jQuery UI Unique ID 1.12.1 4259 * http://jqueryui.com 4260 * 4261 * Copyright jQuery Foundation and other contributors 4262 * Released under the MIT license. 4263 * http://jquery.org/license 4264 */ 4265 4266 //>>label: uniqueId 4267 //>>group: Core 4268 //>>description: Functions to generate and remove uniqueId's 4269 //>>docs: http://api.jqueryui.com/uniqueId/ 4270 4271 4272 4273 var uniqueId = $.fn.extend( { 4274 uniqueId: ( function() { 4275 var uuid = 0; 4276 4277 return function() { 4278 return this.each( function() { 4279 if ( !this.id ) { 4280 this.id = "ui-id-" + ( ++uuid ); 4281 } 4282 } ); 4283 }; 4284 } )(), 4285 4286 removeUniqueId: function() { 4287 return this.each( function() { 4288 if ( /^ui-id-\d+$/.test( this.id ) ) { 4289 $( this ).removeAttr( "id" ); 4290 } 4291 } ); 4292 } 4293 } ); 4294 4295 4296 /*! 4297 * jQuery UI Accordion 1.12.1 4298 * http://jqueryui.com 4299 * 4300 * Copyright jQuery Foundation and other contributors 4301 * Released under the MIT license. 4302 * http://jquery.org/license 4303 */ 4304 4305 //>>label: Accordion 4306 //>>group: Widgets 4307 // jscs:disable maximumLineLength 4308 //>>description: Displays collapsible content panels for presenting information in a limited amount of space. 4309 // jscs:enable maximumLineLength 4310 //>>docs: http://api.jqueryui.com/accordion/ 4311 //>>demos: http://jqueryui.com/accordion/ 4312 //>>css.structure: ../../themes/base/core.css 4313 //>>css.structure: ../../themes/base/accordion.css 4314 //>>css.theme: ../../themes/base/theme.css 4315 4316 4317 4318 var widgetsAccordion = $.widget( "ui.accordion", { 4319 version: "1.12.1", 4320 options: { 4321 active: 0, 4322 animate: {}, 4323 classes: { 4324 "ui-accordion-header": "ui-corner-top", 4325 "ui-accordion-header-collapsed": "ui-corner-all", 4326 "ui-accordion-content": "ui-corner-bottom" 4327 }, 4328 collapsible: false, 4329 event: "click", 4330 header: "> li > :first-child, > :not(li):even", 4331 heightStyle: "auto", 4332 icons: { 4333 activeHeader: "ui-icon-triangle-1-s", 4334 header: "ui-icon-triangle-1-e" 4335 }, 4336 4337 // Callbacks 4338 activate: null, 4339 beforeActivate: null 4340 }, 4341 4342 hideProps: { 4343 borderTopWidth: "hide", 4344 borderBottomWidth: "hide", 4345 paddingTop: "hide", 4346 paddingBottom: "hide", 4347 height: "hide" 4348 }, 4349 4350 showProps: { 4351 borderTopWidth: "show", 4352 borderBottomWidth: "show", 4353 paddingTop: "show", 4354 paddingBottom: "show", 4355 height: "show" 4356 }, 4357 4358 _create: function() { 4359 var options = this.options; 4360 4361 this.prevShow = this.prevHide = $(); 4362 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); 4363 this.element.attr( "role", "tablist" ); 4364 4365 // Don't allow collapsible: false and active: false / null 4366 if ( !options.collapsible && ( options.active === false || options.active == null ) ) { 4367 options.active = 0; 4368 } 4369 4370 this._processPanels(); 4371 4372 // handle negative values 4373 if ( options.active < 0 ) { 4374 options.active += this.headers.length; 4375 } 4376 this._refresh(); 4377 }, 4378 4379 _getCreateEventData: function() { 4380 return { 4381 header: this.active, 4382 panel: !this.active.length ? $() : this.active.next() 4383 }; 4384 }, 4385 4386 _createIcons: function() { 4387 var icon, children, 4388 icons = this.options.icons; 4389 4390 if ( icons ) { 4391 icon = $( "<span>" ); 4392 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); 4393 icon.prependTo( this.headers ); 4394 children = this.active.children( ".ui-accordion-header-icon" ); 4395 this._removeClass( children, icons.header ) 4396 ._addClass( children, null, icons.activeHeader ) 4397 ._addClass( this.headers, "ui-accordion-icons" ); 4398 } 4399 }, 4400 4401 _destroyIcons: function() { 4402 this._removeClass( this.headers, "ui-accordion-icons" ); 4403 this.headers.children( ".ui-accordion-header-icon" ).remove(); 4404 }, 4405 4406 _destroy: function() { 4407 var contents; 4408 4409 // Clean up main element 4410 this.element.removeAttr( "role" ); 4411 4412 // Clean up headers 4413 this.headers 4414 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) 4415 .removeUniqueId(); 4416 4417 this._destroyIcons(); 4418 4419 // Clean up content panels 4420 contents = this.headers.next() 4421 .css( "display", "" ) 4422 .removeAttr( "role aria-hidden aria-labelledby" ) 4423 .removeUniqueId(); 4424 4425 if ( this.options.heightStyle !== "content" ) { 4426 contents.css( "height", "" ); 4427 } 4428 }, 4429 4430 _setOption: function( key, value ) { 4431 if ( key === "active" ) { 4432 4433 // _activate() will handle invalid values and update this.options 4434 this._activate( value ); 4435 return; 4436 } 4437 4438 if ( key === "event" ) { 4439 if ( this.options.event ) { 4440 this._off( this.headers, this.options.event ); 4441 } 4442 this._setupEvents( value ); 4443 } 4444 4445 this._super( key, value ); 4446 4447 // Setting collapsible: false while collapsed; open first panel 4448 if ( key === "collapsible" && !value && this.options.active === false ) { 4449 this._activate( 0 ); 4450 } 4451 4452 if ( key === "icons" ) { 4453 this._destroyIcons(); 4454 if ( value ) { 4455 this._createIcons(); 4456 } 4457 } 4458 }, 4459 4460 _setOptionDisabled: function( value ) { 4461 this._super( value ); 4462 4463 this.element.attr( "aria-disabled", value ); 4464 4465 // Support: IE8 Only 4466 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE 4467 // so we need to add the disabled class to the headers and panels 4468 this._toggleClass( null, "ui-state-disabled", !!value ); 4469 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled", 4470 !!value ); 4471 }, 4472 4473 _keydown: function( event ) { 4474 if ( event.altKey || event.ctrlKey ) { 4475 return; 4476 } 4477 4478 var keyCode = $.ui.keyCode, 4479 length = this.headers.length, 4480 currentIndex = this.headers.index( event.target ), 4481 toFocus = false; 4482 4483 switch ( event.keyCode ) { 4484 case keyCode.RIGHT: 4485 case keyCode.DOWN: 4486 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 4487 break; 4488 case keyCode.LEFT: 4489 case keyCode.UP: 4490 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 4491 break; 4492 case keyCode.SPACE: 4493 case keyCode.ENTER: 4494 this._eventHandler( event ); 4495 break; 4496 case keyCode.HOME: 4497 toFocus = this.headers[ 0 ]; 4498 break; 4499 case keyCode.END: 4500 toFocus = this.headers[ length - 1 ]; 4501 break; 4502 } 4503 4504 if ( toFocus ) { 4505 $( event.target ).attr( "tabIndex", -1 ); 4506 $( toFocus ).attr( "tabIndex", 0 ); 4507 $( toFocus ).trigger( "focus" ); 4508 event.preventDefault(); 4509 } 4510 }, 4511 4512 _panelKeyDown: function( event ) { 4513 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { 4514 $( event.currentTarget ).prev().trigger( "focus" ); 4515 } 4516 }, 4517 4518 refresh: function() { 4519 var options = this.options; 4520 this._processPanels(); 4521 4522 // Was collapsed or no panel 4523 if ( ( options.active === false && options.collapsible === true ) || 4524 !this.headers.length ) { 4525 options.active = false; 4526 this.active = $(); 4527 4528 // active false only when collapsible is true 4529 } else if ( options.active === false ) { 4530 this._activate( 0 ); 4531 4532 // was active, but active panel is gone 4533 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 4534 4535 // all remaining panel are disabled 4536 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { 4537 options.active = false; 4538 this.active = $(); 4539 4540 // activate previous panel 4541 } else { 4542 this._activate( Math.max( 0, options.active - 1 ) ); 4543 } 4544 4545 // was active, active panel still exists 4546 } else { 4547 4548 // make sure active index is correct 4549 options.active = this.headers.index( this.active ); 4550 } 4551 4552 this._destroyIcons(); 4553 4554 this._refresh(); 4555 }, 4556 4557 _processPanels: function() { 4558 var prevHeaders = this.headers, 4559 prevPanels = this.panels; 4560 4561 this.headers = this.element.find( this.options.header ); 4562 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", 4563 "ui-state-default" ); 4564 4565 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); 4566 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); 4567 4568 // Avoid memory leaks (#10056) 4569 if ( prevPanels ) { 4570 this._off( prevHeaders.not( this.headers ) ); 4571 this._off( prevPanels.not( this.panels ) ); 4572 } 4573 }, 4574 4575 _refresh: function() { 4576 var maxHeight, 4577 options = this.options, 4578 heightStyle = options.heightStyle, 4579 parent = this.element.parent(); 4580 4581 this.active = this._findActive( options.active ); 4582 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) 4583 ._removeClass( this.active, "ui-accordion-header-collapsed" ); 4584 this._addClass( this.active.next(), "ui-accordion-content-active" ); 4585 this.active.next().show(); 4586 4587 this.headers 4588 .attr( "role", "tab" ) 4589 .each( function() { 4590 var header = $( this ), 4591 headerId = header.uniqueId().attr( "id" ), 4592 panel = header.next(), 4593 panelId = panel.uniqueId().attr( "id" ); 4594 header.attr( "aria-controls", panelId ); 4595 panel.attr( "aria-labelledby", headerId ); 4596 } ) 4597 .next() 4598 .attr( "role", "tabpanel" ); 4599 4600 this.headers 4601 .not( this.active ) 4602 .attr( { 4603 "aria-selected": "false", 4604 "aria-expanded": "false", 4605 tabIndex: -1 4606 } ) 4607 .next() 4608 .attr( { 4609 "aria-hidden": "true" 4610 } ) 4611 .hide(); 4612 4613 // Make sure at least one header is in the tab order 4614 if ( !this.active.length ) { 4615 this.headers.eq( 0 ).attr( "tabIndex", 0 ); 4616 } else { 4617 this.active.attr( { 4618 "aria-selected": "true", 4619 "aria-expanded": "true", 4620 tabIndex: 0 4621 } ) 4622 .next() 4623 .attr( { 4624 "aria-hidden": "false" 4625 } ); 4626 } 4627 4628 this._createIcons(); 4629 4630 this._setupEvents( options.event ); 4631 4632 if ( heightStyle === "fill" ) { 4633 maxHeight = parent.height(); 4634 this.element.siblings( ":visible" ).each( function() { 4635 var elem = $( this ), 4636 position = elem.css( "position" ); 4637 4638 if ( position === "absolute" || position === "fixed" ) { 4639 return; 4640 } 4641 maxHeight -= elem.outerHeight( true ); 4642 } ); 4643 4644 this.headers.each( function() { 4645 maxHeight -= $( this ).outerHeight( true ); 4646 } ); 4647 4648 this.headers.next() 4649 .each( function() { 4650 $( this ).height( Math.max( 0, maxHeight - 4651 $( this ).innerHeight() + $( this ).height() ) ); 4652 } ) 4653 .css( "overflow", "auto" ); 4654 } else if ( heightStyle === "auto" ) { 4655 maxHeight = 0; 4656 this.headers.next() 4657 .each( function() { 4658 var isVisible = $( this ).is( ":visible" ); 4659 if ( !isVisible ) { 4660 $( this ).show(); 4661 } 4662 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); 4663 if ( !isVisible ) { 4664 $( this ).hide(); 4665 } 4666 } ) 4667 .height( maxHeight ); 4668 } 4669 }, 4670 4671 _activate: function( index ) { 4672 var active = this._findActive( index )[ 0 ]; 4673 4674 // Trying to activate the already active panel 4675 if ( active === this.active[ 0 ] ) { 4676 return; 4677 } 4678 4679 // Trying to collapse, simulate a click on the currently active header 4680 active = active || this.active[ 0 ]; 4681 4682 this._eventHandler( { 4683 target: active, 4684 currentTarget: active, 4685 preventDefault: $.noop 4686 } ); 4687 }, 4688 4689 _findActive: function( selector ) { 4690 return typeof selector === "number" ? this.headers.eq( selector ) : $(); 4691 }, 4692 4693 _setupEvents: function( event ) { 4694 var events = { 4695 keydown: "_keydown" 4696 }; 4697 if ( event ) { 4698 $.each( event.split( " " ), function( index, eventName ) { 4699 events[ eventName ] = "_eventHandler"; 4700 } ); 4701 } 4702 4703 this._off( this.headers.add( this.headers.next() ) ); 4704 this._on( this.headers, events ); 4705 this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); 4706 this._hoverable( this.headers ); 4707 this._focusable( this.headers ); 4708 }, 4709 4710 _eventHandler: function( event ) { 4711 var activeChildren, clickedChildren, 4712 options = this.options, 4713 active = this.active, 4714 clicked = $( event.currentTarget ), 4715 clickedIsActive = clicked[ 0 ] === active[ 0 ], 4716 collapsing = clickedIsActive && options.collapsible, 4717 toShow = collapsing ? $() : clicked.next(), 4718 toHide = active.next(), 4719 eventData = { 4720 oldHeader: active, 4721 oldPanel: toHide, 4722 newHeader: collapsing ? $() : clicked, 4723 newPanel: toShow 4724 }; 4725 4726 event.preventDefault(); 4727 4728 if ( 4729 4730 // click on active header, but not collapsible 4731 ( clickedIsActive && !options.collapsible ) || 4732 4733 // allow canceling activation 4734 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 4735 return; 4736 } 4737 4738 options.active = collapsing ? false : this.headers.index( clicked ); 4739 4740 // When the call to ._toggle() comes after the class changes 4741 // it causes a very odd bug in IE 8 (see #6720) 4742 this.active = clickedIsActive ? $() : clicked; 4743 this._toggle( eventData ); 4744 4745 // Switch classes 4746 // corner classes on the previously active header stay after the animation 4747 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); 4748 if ( options.icons ) { 4749 activeChildren = active.children( ".ui-accordion-header-icon" ); 4750 this._removeClass( activeChildren, null, options.icons.activeHeader ) 4751 ._addClass( activeChildren, null, options.icons.header ); 4752 } 4753 4754 if ( !clickedIsActive ) { 4755 this._removeClass( clicked, "ui-accordion-header-collapsed" ) 4756 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); 4757 if ( options.icons ) { 4758 clickedChildren = clicked.children( ".ui-accordion-header-icon" ); 4759 this._removeClass( clickedChildren, null, options.icons.header ) 4760 ._addClass( clickedChildren, null, options.icons.activeHeader ); 4761 } 4762 4763 this._addClass( clicked.next(), "ui-accordion-content-active" ); 4764 } 4765 }, 4766 4767 _toggle: function( data ) { 4768 var toShow = data.newPanel, 4769 toHide = this.prevShow.length ? this.prevShow : data.oldPanel; 4770 4771 // Handle activating a panel during the animation for another activation 4772 this.prevShow.add( this.prevHide ).stop( true, true ); 4773 this.prevShow = toShow; 4774 this.prevHide = toHide; 4775 4776 if ( this.options.animate ) { 4777 this._animate( toShow, toHide, data ); 4778 } else { 4779 toHide.hide(); 4780 toShow.show(); 4781 this._toggleComplete( data ); 4782 } 4783 4784 toHide.attr( { 4785 "aria-hidden": "true" 4786 } ); 4787 toHide.prev().attr( { 4788 "aria-selected": "false", 4789 "aria-expanded": "false" 4790 } ); 4791 4792 // if we're switching panels, remove the old header from the tab order 4793 // if we're opening from collapsed state, remove the previous header from the tab order 4794 // if we're collapsing, then keep the collapsing header in the tab order 4795 if ( toShow.length && toHide.length ) { 4796 toHide.prev().attr( { 4797 "tabIndex": -1, 4798 "aria-expanded": "false" 4799 } ); 4800 } else if ( toShow.length ) { 4801 this.headers.filter( function() { 4802 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; 4803 } ) 4804 .attr( "tabIndex", -1 ); 4805 } 4806 4807 toShow 4808 .attr( "aria-hidden", "false" ) 4809 .prev() 4810 .attr( { 4811 "aria-selected": "true", 4812 "aria-expanded": "true", 4813 tabIndex: 0 4814 } ); 4815 }, 4816 4817 _animate: function( toShow, toHide, data ) { 4818 var total, easing, duration, 4819 that = this, 4820 adjust = 0, 4821 boxSizing = toShow.css( "box-sizing" ), 4822 down = toShow.length && 4823 ( !toHide.length || ( toShow.index() < toHide.index() ) ), 4824 animate = this.options.animate || {}, 4825 options = down && animate.down || animate, 4826 complete = function() { 4827 that._toggleComplete( data ); 4828 }; 4829 4830 if ( typeof options === "number" ) { 4831 duration = options; 4832 } 4833 if ( typeof options === "string" ) { 4834 easing = options; 4835 } 4836 4837 // fall back from options to animation in case of partial down settings 4838 easing = easing || options.easing || animate.easing; 4839 duration = duration || options.duration || animate.duration; 4840 4841 if ( !toHide.length ) { 4842 return toShow.animate( this.showProps, duration, easing, complete ); 4843 } 4844 if ( !toShow.length ) { 4845 return toHide.animate( this.hideProps, duration, easing, complete ); 4846 } 4847 4848 total = toShow.show().outerHeight(); 4849 toHide.animate( this.hideProps, { 4850 duration: duration, 4851 easing: easing, 4852 step: function( now, fx ) { 4853 fx.now = Math.round( now ); 4854 } 4855 } ); 4856 toShow 4857 .hide() 4858 .animate( this.showProps, { 4859 duration: duration, 4860 easing: easing, 4861 complete: complete, 4862 step: function( now, fx ) { 4863 fx.now = Math.round( now ); 4864 if ( fx.prop !== "height" ) { 4865 if ( boxSizing === "content-box" ) { 4866 adjust += fx.now; 4867 } 4868 } else if ( that.options.heightStyle !== "content" ) { 4869 fx.now = Math.round( total - toHide.outerHeight() - adjust ); 4870 adjust = 0; 4871 } 4872 } 4873 } ); 4874 }, 4875 4876 _toggleComplete: function( data ) { 4877 var toHide = data.oldPanel, 4878 prev = toHide.prev(); 4879 4880 this._removeClass( toHide, "ui-accordion-content-active" ); 4881 this._removeClass( prev, "ui-accordion-header-active" ) 4882 ._addClass( prev, "ui-accordion-header-collapsed" ); 4883 4884 // Work around for rendering bug in IE (#5421) 4885 if ( toHide.length ) { 4886 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; 4887 } 4888 this._trigger( "activate", null, data ); 4889 } 4890 } ); 4891 4892 4893 4894 var safeActiveElement = $.ui.safeActiveElement = function( document ) { 4895 var activeElement; 4896 4897 // Support: IE 9 only 4898 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 4899 try { 4900 activeElement = document.activeElement; 4901 } catch ( error ) { 4902 activeElement = document.body; 4903 } 4904 4905 // Support: IE 9 - 11 only 4906 // IE may return null instead of an element 4907 // Interestingly, this only seems to occur when NOT in an iframe 4908 if ( !activeElement ) { 4909 activeElement = document.body; 4910 } 4911 4912 // Support: IE 11 only 4913 // IE11 returns a seemingly empty object in some cases when accessing 4914 // document.activeElement from an <iframe> 4915 if ( !activeElement.nodeName ) { 4916 activeElement = document.body; 4917 } 4918 4919 return activeElement; 4920 }; 4921 4922 4923 /*! 4924 * jQuery UI Menu 1.12.1 4925 * http://jqueryui.com 4926 * 4927 * Copyright jQuery Foundation and other contributors 4928 * Released under the MIT license. 4929 * http://jquery.org/license 4930 */ 4931 4932 //>>label: Menu 4933 //>>group: Widgets 4934 //>>description: Creates nestable menus. 4935 //>>docs: http://api.jqueryui.com/menu/ 4936 //>>demos: http://jqueryui.com/menu/ 4937 //>>css.structure: ../../themes/base/core.css 4938 //>>css.structure: ../../themes/base/menu.css 4939 //>>css.theme: ../../themes/base/theme.css 4940 4941 4942 4943 var widgetsMenu = $.widget( "ui.menu", { 4944 version: "1.12.1", 4945 defaultElement: "<ul>", 4946 delay: 300, 4947 options: { 4948 icons: { 4949 submenu: "ui-icon-caret-1-e" 4950 }, 4951 items: "> *", 4952 menus: "ul", 4953 position: { 4954 my: "left top", 4955 at: "right top" 4956 }, 4957 role: "menu", 4958 4959 // Callbacks 4960 blur: null, 4961 focus: null, 4962 select: null 4963 }, 4964 4965 _create: function() { 4966 this.activeMenu = this.element; 4967 4968 // Flag used to prevent firing of the click handler 4969 // as the event bubbles up through nested menus 4970 this.mouseHandled = false; 4971 this.element 4972 .uniqueId() 4973 .attr( { 4974 role: this.options.role, 4975 tabIndex: 0 4976 } ); 4977 4978 this._addClass( "ui-menu", "ui-widget ui-widget-content" ); 4979 this._on( { 4980 4981 // Prevent focus from sticking to links inside menu after clicking 4982 // them (focus should always stay on UL during navigation). 4983 "mousedown .ui-menu-item": function( event ) { 4984 event.preventDefault(); 4985 }, 4986 "click .ui-menu-item": function( event ) { 4987 var target = $( event.target ); 4988 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); 4989 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { 4990 this.select( event ); 4991 4992 // Only set the mouseHandled flag if the event will bubble, see #9469. 4993 if ( !event.isPropagationStopped() ) { 4994 this.mouseHandled = true; 4995 } 4996 4997 // Open submenu on click 4998 if ( target.has( ".ui-menu" ).length ) { 4999 this.expand( event ); 5000 } else if ( !this.element.is( ":focus" ) && 5001 active.closest( ".ui-menu" ).length ) { 5002 5003 // Redirect focus to the menu 5004 this.element.trigger( "focus", [ true ] ); 5005 5006 // If the active item is on the top level, let it stay active. 5007 // Otherwise, blur the active item since it is no longer visible. 5008 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { 5009 clearTimeout( this.timer ); 5010 } 5011 } 5012 } 5013 }, 5014 "mouseenter .ui-menu-item": function( event ) { 5015 5016 // Ignore mouse events while typeahead is active, see #10458. 5017 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse 5018 // is over an item in the menu 5019 if ( this.previousFilter ) { 5020 return; 5021 } 5022 5023 var actualTarget = $( event.target ).closest( ".ui-menu-item" ), 5024 target = $( event.currentTarget ); 5025 5026 // Ignore bubbled events on parent items, see #11641 5027 if ( actualTarget[ 0 ] !== target[ 0 ] ) { 5028 return; 5029 } 5030 5031 // Remove ui-state-active class from siblings of the newly focused menu item 5032 // to avoid a jump caused by adjacent elements both having a class with a border 5033 this._removeClass( target.siblings().children( ".ui-state-active" ), 5034 null, "ui-state-active" ); 5035 this.focus( event, target ); 5036 }, 5037 mouseleave: "collapseAll", 5038 "mouseleave .ui-menu": "collapseAll", 5039 focus: function( event, keepActiveItem ) { 5040 5041 // If there's already an active item, keep it active 5042 // If not, activate the first item 5043 var item = this.active || this.element.find( this.options.items ).eq( 0 ); 5044 5045 if ( !keepActiveItem ) { 5046 this.focus( event, item ); 5047 } 5048 }, 5049 blur: function( event ) { 5050 this._delay( function() { 5051 var notContained = !$.contains( 5052 this.element[ 0 ], 5053 $.ui.safeActiveElement( this.document[ 0 ] ) 5054 ); 5055 if ( notContained ) { 5056 this.collapseAll( event ); 5057 } 5058 } ); 5059 }, 5060 keydown: "_keydown" 5061 } ); 5062 5063 this.refresh(); 5064 5065 // Clicks outside of a menu collapse any open menus 5066 this._on( this.document, { 5067 click: function( event ) { 5068 if ( this._closeOnDocumentClick( event ) ) { 5069 this.collapseAll( event ); 5070 } 5071 5072 // Reset the mouseHandled flag 5073 this.mouseHandled = false; 5074 } 5075 } ); 5076 }, 5077 5078 _destroy: function() { 5079 var items = this.element.find( ".ui-menu-item" ) 5080 .removeAttr( "role aria-disabled" ), 5081 submenus = items.children( ".ui-menu-item-wrapper" ) 5082 .removeUniqueId() 5083 .removeAttr( "tabIndex role aria-haspopup" ); 5084 5085 // Destroy (sub)menus 5086 this.element 5087 .removeAttr( "aria-activedescendant" ) 5088 .find( ".ui-menu" ).addBack() 5089 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " + 5090 "tabIndex" ) 5091 .removeUniqueId() 5092 .show(); 5093 5094 submenus.children().each( function() { 5095 var elem = $( this ); 5096 if ( elem.data( "ui-menu-submenu-caret" ) ) { 5097 elem.remove(); 5098 } 5099 } ); 5100 }, 5101 5102 _keydown: function( event ) { 5103 var match, prev, character, skip, 5104 preventDefault = true; 5105 5106 switch ( event.keyCode ) { 5107 case $.ui.keyCode.PAGE_UP: 5108 this.previousPage( event ); 5109 break; 5110 case $.ui.keyCode.PAGE_DOWN: 5111 this.nextPage( event ); 5112 break; 5113 case $.ui.keyCode.HOME: 5114 this._move( "first", "first", event ); 5115 break; 5116 case $.ui.keyCode.END: 5117 this._move( "last", "last", event ); 5118 break; 5119 case $.ui.keyCode.UP: 5120 this.previous( event ); 5121 break; 5122 case $.ui.keyCode.DOWN: 5123 this.next( event ); 5124 break; 5125 case $.ui.keyCode.LEFT: 5126 this.collapse( event ); 5127 break; 5128 case $.ui.keyCode.RIGHT: 5129 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 5130 this.expand( event ); 5131 } 5132 break; 5133 case $.ui.keyCode.ENTER: 5134 case $.ui.keyCode.SPACE: 5135 this._activate( event ); 5136 break; 5137 case $.ui.keyCode.ESCAPE: 5138 this.collapse( event ); 5139 break; 5140 default: 5141 preventDefault = false; 5142 prev = this.previousFilter || ""; 5143 skip = false; 5144 5145 // Support number pad values 5146 character = event.keyCode >= 96 && event.keyCode <= 105 ? 5147 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode ); 5148 5149 clearTimeout( this.filterTimer ); 5150 5151 if ( character === prev ) { 5152 skip = true; 5153 } else { 5154 character = prev + character; 5155 } 5156 5157 match = this._filterMenuItems( character ); 5158 match = skip && match.index( this.active.next() ) !== -1 ? 5159 this.active.nextAll( ".ui-menu-item" ) : 5160 match; 5161 5162 // If no matches on the current filter, reset to the last character pressed 5163 // to move down the menu to the first item that starts with that character 5164 if ( !match.length ) { 5165 character = String.fromCharCode( event.keyCode ); 5166 match = this._filterMenuItems( character ); 5167 } 5168 5169 if ( match.length ) { 5170 this.focus( event, match ); 5171 this.previousFilter = character; 5172 this.filterTimer = this._delay( function() { 5173 delete this.previousFilter; 5174 }, 1000 ); 5175 } else { 5176 delete this.previousFilter; 5177 } 5178 } 5179 5180 if ( preventDefault ) { 5181 event.preventDefault(); 5182 } 5183 }, 5184 5185 _activate: function( event ) { 5186 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 5187 if ( this.active.children( "[aria-haspopup='true']" ).length ) { 5188 this.expand( event ); 5189 } else { 5190 this.select( event ); 5191 } 5192 } 5193 }, 5194 5195 refresh: function() { 5196 var menus, items, newSubmenus, newItems, newWrappers, 5197 that = this, 5198 icon = this.options.icons.submenu, 5199 submenus = this.element.find( this.options.menus ); 5200 5201 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length ); 5202 5203 // Initialize nested menus 5204 newSubmenus = submenus.filter( ":not(.ui-menu)" ) 5205 .hide() 5206 .attr( { 5207 role: this.options.role, 5208 "aria-hidden": "true", 5209 "aria-expanded": "false" 5210 } ) 5211 .each( function() { 5212 var menu = $( this ), 5213 item = menu.prev(), 5214 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true ); 5215 5216 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon ); 5217 item 5218 .attr( "aria-haspopup", "true" ) 5219 .prepend( submenuCaret ); 5220 menu.attr( "aria-labelledby", item.attr( "id" ) ); 5221 } ); 5222 5223 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" ); 5224 5225 menus = submenus.add( this.element ); 5226 items = menus.find( this.options.items ); 5227 5228 // Initialize menu-items containing spaces and/or dashes only as dividers 5229 items.not( ".ui-menu-item" ).each( function() { 5230 var item = $( this ); 5231 if ( that._isDivider( item ) ) { 5232 that._addClass( item, "ui-menu-divider", "ui-widget-content" ); 5233 } 5234 } ); 5235 5236 // Don't refresh list items that are already adapted 5237 newItems = items.not( ".ui-menu-item, .ui-menu-divider" ); 5238 newWrappers = newItems.children() 5239 .not( ".ui-menu" ) 5240 .uniqueId() 5241 .attr( { 5242 tabIndex: -1, 5243 role: this._itemRole() 5244 } ); 5245 this._addClass( newItems, "ui-menu-item" ) 5246 ._addClass( newWrappers, "ui-menu-item-wrapper" ); 5247 5248 // Add aria-disabled attribute to any disabled menu item 5249 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); 5250 5251 // If the active item has been removed, blur the menu 5252 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 5253 this.blur(); 5254 } 5255 }, 5256 5257 _itemRole: function() { 5258 return { 5259 menu: "menuitem", 5260 listbox: "option" 5261 }[ this.options.role ]; 5262 }, 5263 5264 _setOption: function( key, value ) { 5265 if ( key === "icons" ) { 5266 var icons = this.element.find( ".ui-menu-icon" ); 5267 this._removeClass( icons, null, this.options.icons.submenu ) 5268 ._addClass( icons, null, value.submenu ); 5269 } 5270 this._super( key, value ); 5271 }, 5272 5273 _setOptionDisabled: function( value ) { 5274 this._super( value ); 5275 5276 this.element.attr( "aria-disabled", String( value ) ); 5277 this._toggleClass( null, "ui-state-disabled", !!value ); 5278 }, 5279 5280 focus: function( event, item ) { 5281 var nested, focused, activeParent; 5282 this.blur( event, event && event.type === "focus" ); 5283 5284 this._scrollIntoView( item ); 5285 5286 this.active = item.first(); 5287 5288 focused = this.active.children( ".ui-menu-item-wrapper" ); 5289 this._addClass( focused, null, "ui-state-active" ); 5290 5291 // Only update aria-activedescendant if there's a role 5292 // otherwise we assume focus is managed elsewhere 5293 if ( this.options.role ) { 5294 this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); 5295 } 5296 5297 // Highlight active parent menu item, if any 5298 activeParent = this.active 5299 .parent() 5300 .closest( ".ui-menu-item" ) 5301 .children( ".ui-menu-item-wrapper" ); 5302 this._addClass( activeParent, null, "ui-state-active" ); 5303 5304 if ( event && event.type === "keydown" ) { 5305 this._close(); 5306 } else { 5307 this.timer = this._delay( function() { 5308 this._close(); 5309 }, this.delay ); 5310 } 5311 5312 nested = item.children( ".ui-menu" ); 5313 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { 5314 this._startOpening( nested ); 5315 } 5316 this.activeMenu = item.parent(); 5317 5318 this._trigger( "focus", event, { item: item } ); 5319 }, 5320 5321 _scrollIntoView: function( item ) { 5322 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; 5323 if ( this._hasScroll() ) { 5324 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0; 5325 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0; 5326 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; 5327 scroll = this.activeMenu.scrollTop(); 5328 elementHeight = this.activeMenu.height(); 5329 itemHeight = item.outerHeight(); 5330 5331 if ( offset < 0 ) { 5332 this.activeMenu.scrollTop( scroll + offset ); 5333 } else if ( offset + itemHeight > elementHeight ) { 5334 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); 5335 } 5336 } 5337 }, 5338 5339 blur: function( event, fromFocus ) { 5340 if ( !fromFocus ) { 5341 clearTimeout( this.timer ); 5342 } 5343 5344 if ( !this.active ) { 5345 return; 5346 } 5347 5348 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ), 5349 null, "ui-state-active" ); 5350 5351 this._trigger( "blur", event, { item: this.active } ); 5352 this.active = null; 5353 }, 5354 5355 _startOpening: function( submenu ) { 5356 clearTimeout( this.timer ); 5357 5358 // Don't open if already open fixes a Firefox bug that caused a .5 pixel 5359 // shift in the submenu position when mousing over the caret icon 5360 if ( submenu.attr( "aria-hidden" ) !== "true" ) { 5361 return; 5362 } 5363 5364 this.timer = this._delay( function() { 5365 this._close(); 5366 this._open( submenu ); 5367 }, this.delay ); 5368 }, 5369 5370 _open: function( submenu ) { 5371 var position = $.extend( { 5372 of: this.active 5373 }, this.options.position ); 5374 5375 clearTimeout( this.timer ); 5376 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) 5377 .hide() 5378 .attr( "aria-hidden", "true" ); 5379 5380 submenu 5381 .show() 5382 .removeAttr( "aria-hidden" ) 5383 .attr( "aria-expanded", "true" ) 5384 .position( position ); 5385 }, 5386 5387 collapseAll: function( event, all ) { 5388 clearTimeout( this.timer ); 5389 this.timer = this._delay( function() { 5390 5391 // If we were passed an event, look for the submenu that contains the event 5392 var currentMenu = all ? this.element : 5393 $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); 5394 5395 // If we found no valid submenu ancestor, use the main menu to close all 5396 // sub menus anyway 5397 if ( !currentMenu.length ) { 5398 currentMenu = this.element; 5399 } 5400 5401 this._close( currentMenu ); 5402 5403 this.blur( event ); 5404 5405 // Work around active item staying active after menu is blurred 5406 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" ); 5407 5408 this.activeMenu = currentMenu; 5409 }, this.delay ); 5410 }, 5411 5412 // With no arguments, closes the currently active menu - if nothing is active 5413 // it closes all menus. If passed an argument, it will search for menus BELOW 5414 _close: function( startMenu ) { 5415 if ( !startMenu ) { 5416 startMenu = this.active ? this.active.parent() : this.element; 5417 } 5418 5419 startMenu.find( ".ui-menu" ) 5420 .hide() 5421 .attr( "aria-hidden", "true" ) 5422 .attr( "aria-expanded", "false" ); 5423 }, 5424 5425 _closeOnDocumentClick: function( event ) { 5426 return !$( event.target ).closest( ".ui-menu" ).length; 5427 }, 5428 5429 _isDivider: function( item ) { 5430 5431 // Match hyphen, em dash, en dash 5432 return !/[^\-\u2014\u2013\s]/.test( item.text() ); 5433 }, 5434 5435 collapse: function( event ) { 5436 var newItem = this.active && 5437 this.active.parent().closest( ".ui-menu-item", this.element ); 5438 if ( newItem && newItem.length ) { 5439 this._close(); 5440 this.focus( event, newItem ); 5441 } 5442 }, 5443 5444 expand: function( event ) { 5445 var newItem = this.active && 5446 this.active 5447 .children( ".ui-menu " ) 5448 .find( this.options.items ) 5449 .first(); 5450 5451 if ( newItem && newItem.length ) { 5452 this._open( newItem.parent() ); 5453 5454 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT 5455 this._delay( function() { 5456 this.focus( event, newItem ); 5457 } ); 5458 } 5459 }, 5460 5461 next: function( event ) { 5462 this._move( "next", "first", event ); 5463 }, 5464 5465 previous: function( event ) { 5466 this._move( "prev", "last", event ); 5467 }, 5468 5469 isFirstItem: function() { 5470 return this.active && !this.active.prevAll( ".ui-menu-item" ).length; 5471 }, 5472 5473 isLastItem: function() { 5474 return this.active && !this.active.nextAll( ".ui-menu-item" ).length; 5475 }, 5476 5477 _move: function( direction, filter, event ) { 5478 var next; 5479 if ( this.active ) { 5480 if ( direction === "first" || direction === "last" ) { 5481 next = this.active 5482 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) 5483 .eq( -1 ); 5484 } else { 5485 next = this.active 5486 [ direction + "All" ]( ".ui-menu-item" ) 5487 .eq( 0 ); 5488 } 5489 } 5490 if ( !next || !next.length || !this.active ) { 5491 next = this.activeMenu.find( this.options.items )[ filter ](); 5492 } 5493 5494 this.focus( event, next ); 5495 }, 5496 5497 nextPage: function( event ) { 5498 var item, base, height; 5499 5500 if ( !this.active ) { 5501 this.next( event ); 5502 return; 5503 } 5504 if ( this.isLastItem() ) { 5505 return; 5506 } 5507 if ( this._hasScroll() ) { 5508 base = this.active.offset().top; 5509 height = this.element.height(); 5510 this.active.nextAll( ".ui-menu-item" ).each( function() { 5511 item = $( this ); 5512 return item.offset().top - base - height < 0; 5513 } ); 5514 5515 this.focus( event, item ); 5516 } else { 5517 this.focus( event, this.activeMenu.find( this.options.items ) 5518 [ !this.active ? "first" : "last" ]() ); 5519 } 5520 }, 5521 5522 previousPage: function( event ) { 5523 var item, base, height; 5524 if ( !this.active ) { 5525 this.next( event ); 5526 return; 5527 } 5528 if ( this.isFirstItem() ) { 5529 return; 5530 } 5531 if ( this._hasScroll() ) { 5532 base = this.active.offset().top; 5533 height = this.element.height(); 5534 this.active.prevAll( ".ui-menu-item" ).each( function() { 5535 item = $( this ); 5536 return item.offset().top - base + height > 0; 5537 } ); 5538 5539 this.focus( event, item ); 5540 } else { 5541 this.focus( event, this.activeMenu.find( this.options.items ).first() ); 5542 } 5543 }, 5544 5545 _hasScroll: function() { 5546 return this.element.outerHeight() < this.element.prop( "scrollHeight" ); 5547 }, 5548 5549 select: function( event ) { 5550 5551 // TODO: It should never be possible to not have an active item at this 5552 // point, but the tests don't trigger mouseenter before click. 5553 this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); 5554 var ui = { item: this.active }; 5555 if ( !this.active.has( ".ui-menu" ).length ) { 5556 this.collapseAll( event, true ); 5557 } 5558 this._trigger( "select", event, ui ); 5559 }, 5560 5561 _filterMenuItems: function( character ) { 5562 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), 5563 regex = new RegExp( "^" + escapedCharacter, "i" ); 5564 5565 return this.activeMenu 5566 .find( this.options.items ) 5567 5568 // Only match on items, not dividers or other content (#10571) 5569 .filter( ".ui-menu-item" ) 5570 .filter( function() { 5571 return regex.test( 5572 $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) ); 5573 } ); 5574 } 5575 } ); 5576 5577 5578 /*! 5579 * jQuery UI Autocomplete 1.12.1 5580 * http://jqueryui.com 5581 * 5582 * Copyright jQuery Foundation and other contributors 5583 * Released under the MIT license. 5584 * http://jquery.org/license 5585 */ 5586 5587 //>>label: Autocomplete 5588 //>>group: Widgets 5589 //>>description: Lists suggested words as the user is typing. 5590 //>>docs: http://api.jqueryui.com/autocomplete/ 5591 //>>demos: http://jqueryui.com/autocomplete/ 5592 //>>css.structure: ../../themes/base/core.css 5593 //>>css.structure: ../../themes/base/autocomplete.css 5594 //>>css.theme: ../../themes/base/theme.css 5595 5596 5597 5598 $.widget( "ui.autocomplete", { 5599 version: "1.12.1", 5600 defaultElement: "<input>", 5601 options: { 5602 appendTo: null, 5603 autoFocus: false, 5604 delay: 300, 5605 minLength: 1, 5606 position: { 5607 my: "left top", 5608 at: "left bottom", 5609 collision: "none" 5610 }, 5611 source: null, 5612 5613 // Callbacks 5614 change: null, 5615 close: null, 5616 focus: null, 5617 open: null, 5618 response: null, 5619 search: null, 5620 select: null 5621 }, 5622 5623 requestIndex: 0, 5624 pending: 0, 5625 5626 _create: function() { 5627 5628 // Some browsers only repeat keydown events, not keypress events, 5629 // so we use the suppressKeyPress flag to determine if we've already 5630 // handled the keydown event. #7269 5631 // Unfortunately the code for & in keypress is the same as the up arrow, 5632 // so we use the suppressKeyPressRepeat flag to avoid handling keypress 5633 // events when we know the keydown event was used to modify the 5634 // search term. #7799 5635 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, 5636 nodeName = this.element[ 0 ].nodeName.toLowerCase(), 5637 isTextarea = nodeName === "textarea", 5638 isInput = nodeName === "input"; 5639 5640 // Textareas are always multi-line 5641 // Inputs are always single-line, even if inside a contentEditable element 5642 // IE also treats inputs as contentEditable 5643 // All other element types are determined by whether or not they're contentEditable 5644 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element ); 5645 5646 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; 5647 this.isNewMenu = true; 5648 5649 this._addClass( "ui-autocomplete-input" ); 5650 this.element.attr( "autocomplete", "off" ); 5651 5652 this._on( this.element, { 5653 keydown: function( event ) { 5654 if ( this.element.prop( "readOnly" ) ) { 5655 suppressKeyPress = true; 5656 suppressInput = true; 5657 suppressKeyPressRepeat = true; 5658 return; 5659 } 5660 5661 suppressKeyPress = false; 5662 suppressInput = false; 5663 suppressKeyPressRepeat = false; 5664 var keyCode = $.ui.keyCode; 5665 switch ( event.keyCode ) { 5666 case keyCode.PAGE_UP: 5667 suppressKeyPress = true; 5668 this._move( "previousPage", event ); 5669 break; 5670 case keyCode.PAGE_DOWN: 5671 suppressKeyPress = true; 5672 this._move( "nextPage", event ); 5673 break; 5674 case keyCode.UP: 5675 suppressKeyPress = true; 5676 this._keyEvent( "previous", event ); 5677 break; 5678 case keyCode.DOWN: 5679 suppressKeyPress = true; 5680 this._keyEvent( "next", event ); 5681 break; 5682 case keyCode.ENTER: 5683 5684 // when menu is open and has focus 5685 if ( this.menu.active ) { 5686 5687 // #6055 - Opera still allows the keypress to occur 5688 // which causes forms to submit 5689 suppressKeyPress = true; 5690 event.preventDefault(); 5691 this.menu.select( event ); 5692 } 5693 break; 5694 case keyCode.TAB: 5695 if ( this.menu.active ) { 5696 this.menu.select( event ); 5697 } 5698 break; 5699 case keyCode.ESCAPE: 5700 if ( this.menu.element.is( ":visible" ) ) { 5701 if ( !this.isMultiLine ) { 5702 this._value( this.term ); 5703 } 5704 this.close( event ); 5705 5706 // Different browsers have different default behavior for escape 5707 // Single press can mean undo or clear 5708 // Double press in IE means clear the whole form 5709 event.preventDefault(); 5710 } 5711 break; 5712 default: 5713 suppressKeyPressRepeat = true; 5714 5715 // search timeout should be triggered before the input value is changed 5716 this._searchTimeout( event ); 5717 break; 5718 } 5719 }, 5720 keypress: function( event ) { 5721 if ( suppressKeyPress ) { 5722 suppressKeyPress = false; 5723 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 5724 event.preventDefault(); 5725 } 5726 return; 5727 } 5728 if ( suppressKeyPressRepeat ) { 5729 return; 5730 } 5731 5732 // Replicate some key handlers to allow them to repeat in Firefox and Opera 5733 var keyCode = $.ui.keyCode; 5734 switch ( event.keyCode ) { 5735 case keyCode.PAGE_UP: 5736 this._move( "previousPage", event ); 5737 break; 5738 case keyCode.PAGE_DOWN: 5739 this._move( "nextPage", event ); 5740 break; 5741 case keyCode.UP: 5742 this._keyEvent( "previous", event ); 5743 break; 5744 case keyCode.DOWN: 5745 this._keyEvent( "next", event ); 5746 break; 5747 } 5748 }, 5749 input: function( event ) { 5750 if ( suppressInput ) { 5751 suppressInput = false; 5752 event.preventDefault(); 5753 return; 5754 } 5755 this._searchTimeout( event ); 5756 }, 5757 focus: function() { 5758 this.selectedItem = null; 5759 this.previous = this._value(); 5760 }, 5761 blur: function( event ) { 5762 if ( this.cancelBlur ) { 5763 delete this.cancelBlur; 5764 return; 5765 } 5766 5767 clearTimeout( this.searching ); 5768 this.close( event ); 5769 this._change( event ); 5770 } 5771 } ); 5772 5773 this._initSource(); 5774 this.menu = $( "<ul>" ) 5775 .appendTo( this._appendTo() ) 5776 .menu( { 5777 5778 // disable ARIA support, the live region takes care of that 5779 role: null 5780 } ) 5781 .hide() 5782 .menu( "instance" ); 5783 5784 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" ); 5785 this._on( this.menu.element, { 5786 mousedown: function( event ) { 5787 5788 // prevent moving focus out of the text field 5789 event.preventDefault(); 5790 5791 // IE doesn't prevent moving focus even with event.preventDefault() 5792 // so we set a flag to know when we should ignore the blur event 5793 this.cancelBlur = true; 5794 this._delay( function() { 5795 delete this.cancelBlur; 5796 5797 // Support: IE 8 only 5798 // Right clicking a menu item or selecting text from the menu items will 5799 // result in focus moving out of the input. However, we've already received 5800 // and ignored the blur event because of the cancelBlur flag set above. So 5801 // we restore focus to ensure that the menu closes properly based on the user's 5802 // next actions. 5803 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { 5804 this.element.trigger( "focus" ); 5805 } 5806 } ); 5807 }, 5808 menufocus: function( event, ui ) { 5809 var label, item; 5810 5811 // support: Firefox 5812 // Prevent accidental activation of menu items in Firefox (#7024 #9118) 5813 if ( this.isNewMenu ) { 5814 this.isNewMenu = false; 5815 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { 5816 this.menu.blur(); 5817 5818 this.document.one( "mousemove", function() { 5819 $( event.target ).trigger( event.originalEvent ); 5820 } ); 5821 5822 return; 5823 } 5824 } 5825 5826 item = ui.item.data( "ui-autocomplete-item" ); 5827 if ( false !== this._trigger( "focus", event, { item: item } ) ) { 5828 5829 // use value to match what will end up in the input, if it was a key event 5830 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { 5831 this._value( item.value ); 5832 } 5833 } 5834 5835 // Announce the value in the liveRegion 5836 label = ui.item.attr( "aria-label" ) || item.value; 5837 if ( label && $.trim( label ).length ) { 5838 this.liveRegion.children().hide(); 5839 $( "<div>" ).text( label ).appendTo( this.liveRegion ); 5840 } 5841 }, 5842 menuselect: function( event, ui ) { 5843 var item = ui.item.data( "ui-autocomplete-item" ), 5844 previous = this.previous; 5845 5846 // Only trigger when focus was lost (click on menu) 5847 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { 5848 this.element.trigger( "focus" ); 5849 this.previous = previous; 5850 5851 // #6109 - IE triggers two focus events and the second 5852 // is asynchronous, so we need to reset the previous 5853 // term synchronously and asynchronously :-( 5854 this._delay( function() { 5855 this.previous = previous; 5856 this.selectedItem = item; 5857 } ); 5858 } 5859 5860 if ( false !== this._trigger( "select", event, { item: item } ) ) { 5861 this._value( item.value ); 5862 } 5863 5864 // reset the term after the select event 5865 // this allows custom select handling to work properly 5866 this.term = this._value(); 5867 5868 this.close( event ); 5869 this.selectedItem = item; 5870 } 5871 } ); 5872 5873 this.liveRegion = $( "<div>", { 5874 role: "status", 5875 "aria-live": "assertive", 5876 "aria-relevant": "additions" 5877 } ) 5878 .appendTo( this.document[ 0 ].body ); 5879 5880 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 5881 5882 // Turning off autocomplete prevents the browser from remembering the 5883 // value when navigating through history, so we re-enable autocomplete 5884 // if the page is unloaded before the widget is destroyed. #7790 5885 this._on( this.window, { 5886 beforeunload: function() { 5887 this.element.removeAttr( "autocomplete" ); 5888 } 5889 } ); 5890 }, 5891 5892 _destroy: function() { 5893 clearTimeout( this.searching ); 5894 this.element.removeAttr( "autocomplete" ); 5895 this.menu.element.remove(); 5896 this.liveRegion.remove(); 5897 }, 5898 5899 _setOption: function( key, value ) { 5900 this._super( key, value ); 5901 if ( key === "source" ) { 5902 this._initSource(); 5903 } 5904 if ( key === "appendTo" ) { 5905 this.menu.element.appendTo( this._appendTo() ); 5906 } 5907 if ( key === "disabled" && value && this.xhr ) { 5908 this.xhr.abort(); 5909 } 5910 }, 5911 5912 _isEventTargetInWidget: function( event ) { 5913 var menuElement = this.menu.element[ 0 ]; 5914 5915 return event.target === this.element[ 0 ] || 5916 event.target === menuElement || 5917 $.contains( menuElement, event.target ); 5918 }, 5919 5920 _closeOnClickOutside: function( event ) { 5921 if ( !this._isEventTargetInWidget( event ) ) { 5922 this.close(); 5923 } 5924 }, 5925 5926 _appendTo: function() { 5927 var element = this.options.appendTo; 5928 5929 if ( element ) { 5930 element = element.jquery || element.nodeType ? 5931 $( element ) : 5932 this.document.find( element ).eq( 0 ); 5933 } 5934 5935 if ( !element || !element[ 0 ] ) { 5936 element = this.element.closest( ".ui-front, dialog" ); 5937 } 5938 5939 if ( !element.length ) { 5940 element = this.document[ 0 ].body; 5941 } 5942 5943 return element; 5944 }, 5945 5946 _initSource: function() { 5947 var array, url, 5948 that = this; 5949 if ( $.isArray( this.options.source ) ) { 5950 array = this.options.source; 5951 this.source = function( request, response ) { 5952 response( $.ui.autocomplete.filter( array, request.term ) ); 5953 }; 5954 } else if ( typeof this.options.source === "string" ) { 5955 url = this.options.source; 5956 this.source = function( request, response ) { 5957 if ( that.xhr ) { 5958 that.xhr.abort(); 5959 } 5960 that.xhr = $.ajax( { 5961 url: url, 5962 data: request, 5963 dataType: "json", 5964 success: function( data ) { 5965 response( data ); 5966 }, 5967 error: function() { 5968 response( [] ); 5969 } 5970 } ); 5971 }; 5972 } else { 5973 this.source = this.options.source; 5974 } 5975 }, 5976 5977 _searchTimeout: function( event ) { 5978 clearTimeout( this.searching ); 5979 this.searching = this._delay( function() { 5980 5981 // Search if the value has changed, or if the user retypes the same value (see #7434) 5982 var equalValues = this.term === this._value(), 5983 menuVisible = this.menu.element.is( ":visible" ), 5984 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; 5985 5986 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { 5987 this.selectedItem = null; 5988 this.search( null, event ); 5989 } 5990 }, this.options.delay ); 5991 }, 5992 5993 search: function( value, event ) { 5994 value = value != null ? value : this._value(); 5995 5996 // Always save the actual value, not the one passed as an argument 5997 this.term = this._value(); 5998 5999 if ( value.length < this.options.minLength ) { 6000 return this.close( event ); 6001 } 6002 6003 if ( this._trigger( "search", event ) === false ) { 6004 return; 6005 } 6006 6007 return this._search( value ); 6008 }, 6009 6010 _search: function( value ) { 6011 this.pending++; 6012 this._addClass( "ui-autocomplete-loading" ); 6013 this.cancelSearch = false; 6014 6015 this.source( { term: value }, this._response() ); 6016 }, 6017 6018 _response: function() { 6019 var index = ++this.requestIndex; 6020 6021 return $.proxy( function( content ) { 6022 if ( index === this.requestIndex ) { 6023 this.__response( content ); 6024 } 6025 6026 this.pending--; 6027 if ( !this.pending ) { 6028 this._removeClass( "ui-autocomplete-loading" ); 6029 } 6030 }, this ); 6031 }, 6032 6033 __response: function( content ) { 6034 if ( content ) { 6035 content = this._normalize( content ); 6036 } 6037 this._trigger( "response", null, { content: content } ); 6038 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { 6039 this._suggest( content ); 6040 this._trigger( "open" ); 6041 } else { 6042 6043 // use ._close() instead of .close() so we don't cancel future searches 6044 this._close(); 6045 } 6046 }, 6047 6048 close: function( event ) { 6049 this.cancelSearch = true; 6050 this._close( event ); 6051 }, 6052 6053 _close: function( event ) { 6054 6055 // Remove the handler that closes the menu on outside clicks 6056 this._off( this.document, "mousedown" ); 6057 6058 if ( this.menu.element.is( ":visible" ) ) { 6059 this.menu.element.hide(); 6060 this.menu.blur(); 6061 this.isNewMenu = true; 6062 this._trigger( "close", event ); 6063 } 6064 }, 6065 6066 _change: function( event ) { 6067 if ( this.previous !== this._value() ) { 6068 this._trigger( "change", event, { item: this.selectedItem } ); 6069 } 6070 }, 6071 6072 _normalize: function( items ) { 6073 6074 // assume all items have the right format when the first item is complete 6075 if ( items.length && items[ 0 ].label && items[ 0 ].value ) { 6076 return items; 6077 } 6078 return $.map( items, function( item ) { 6079 if ( typeof item === "string" ) { 6080 return { 6081 label: item, 6082 value: item 6083 }; 6084 } 6085 return $.extend( {}, item, { 6086 label: item.label || item.value, 6087 value: item.value || item.label 6088 } ); 6089 } ); 6090 }, 6091 6092 _suggest: function( items ) { 6093 var ul = this.menu.element.empty(); 6094 this._renderMenu( ul, items ); 6095 this.isNewMenu = true; 6096 this.menu.refresh(); 6097 6098 // Size and position menu 6099 ul.show(); 6100 this._resizeMenu(); 6101 ul.position( $.extend( { 6102 of: this.element 6103 }, this.options.position ) ); 6104 6105 if ( this.options.autoFocus ) { 6106 this.menu.next(); 6107 } 6108 6109 // Listen for interactions outside of the widget (#6642) 6110 this._on( this.document, { 6111 mousedown: "_closeOnClickOutside" 6112 } ); 6113 }, 6114 6115 _resizeMenu: function() { 6116 var ul = this.menu.element; 6117 ul.outerWidth( Math.max( 6118 6119 // Firefox wraps long text (possibly a rounding bug) 6120 // so we add 1px to avoid the wrapping (#7513) 6121 ul.width( "" ).outerWidth() + 1, 6122 this.element.outerWidth() 6123 ) ); 6124 }, 6125 6126 _renderMenu: function( ul, items ) { 6127 var that = this; 6128 $.each( items, function( index, item ) { 6129 that._renderItemData( ul, item ); 6130 } ); 6131 }, 6132 6133 _renderItemData: function( ul, item ) { 6134 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 6135 }, 6136 6137 _renderItem: function( ul, item ) { 6138 return $( "<li>" ) 6139 .append( $( "<div>" ).text( item.label ) ) 6140 .appendTo( ul ); 6141 }, 6142 6143 _move: function( direction, event ) { 6144 if ( !this.menu.element.is( ":visible" ) ) { 6145 this.search( null, event ); 6146 return; 6147 } 6148 if ( this.menu.isFirstItem() && /^previous/.test( direction ) || 6149 this.menu.isLastItem() && /^next/.test( direction ) ) { 6150 6151 if ( !this.isMultiLine ) { 6152 this._value( this.term ); 6153 } 6154 6155 this.menu.blur(); 6156 return; 6157 } 6158 this.menu[ direction ]( event ); 6159 }, 6160 6161 widget: function() { 6162 return this.menu.element; 6163 }, 6164 6165 _value: function() { 6166 return this.valueMethod.apply( this.element, arguments ); 6167 }, 6168 6169 _keyEvent: function( keyEvent, event ) { 6170 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 6171 this._move( keyEvent, event ); 6172 6173 // Prevents moving cursor to beginning/end of the text field in some browsers 6174 event.preventDefault(); 6175 } 6176 }, 6177 6178 // Support: Chrome <=50 6179 // We should be able to just use this.element.prop( "isContentEditable" ) 6180 // but hidden elements always report false in Chrome. 6181 // https://code.google.com/p/chromium/issues/detail?id=313082 6182 _isContentEditable: function( element ) { 6183 if ( !element.length ) { 6184 return false; 6185 } 6186 6187 var editable = element.prop( "contentEditable" ); 6188 6189 if ( editable === "inherit" ) { 6190 return this._isContentEditable( element.parent() ); 6191 } 6192 6193 return editable === "true"; 6194 } 6195 } ); 6196 6197 $.extend( $.ui.autocomplete, { 6198 escapeRegex: function( value ) { 6199 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 6200 }, 6201 filter: function( array, term ) { 6202 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 6203 return $.grep( array, function( value ) { 6204 return matcher.test( value.label || value.value || value ); 6205 } ); 6206 } 6207 } ); 6208 6209 // Live region extension, adding a `messages` option 6210 // NOTE: This is an experimental API. We are still investigating 6211 // a full solution for string manipulation and internationalization. 6212 $.widget( "ui.autocomplete", $.ui.autocomplete, { 6213 options: { 6214 messages: { 6215 noResults: "No search results.", 6216 results: function( amount ) { 6217 return amount + ( amount > 1 ? " results are" : " result is" ) + 6218 " available, use up and down arrow keys to navigate."; 6219 } 6220 } 6221 }, 6222 6223 __response: function( content ) { 6224 var message; 6225 this._superApply( arguments ); 6226 if ( this.options.disabled || this.cancelSearch ) { 6227 return; 6228 } 6229 if ( content && content.length ) { 6230 message = this.options.messages.results( content.length ); 6231 } else { 6232 message = this.options.messages.noResults; 6233 } 6234 this.liveRegion.children().hide(); 6235 $( "<div>" ).text( message ).appendTo( this.liveRegion ); 6236 } 6237 } ); 6238 6239 var widgetsAutocomplete = $.ui.autocomplete; 6240 6241 6242 /*! 6243 * jQuery UI Controlgroup 1.12.1 6244 * http://jqueryui.com 6245 * 6246 * Copyright jQuery Foundation and other contributors 6247 * Released under the MIT license. 6248 * http://jquery.org/license 6249 */ 6250 6251 //>>label: Controlgroup 6252 //>>group: Widgets 6253 //>>description: Visually groups form control widgets 6254 //>>docs: http://api.jqueryui.com/controlgroup/ 6255 //>>demos: http://jqueryui.com/controlgroup/ 6256 //>>css.structure: ../../themes/base/core.css 6257 //>>css.structure: ../../themes/base/controlgroup.css 6258 //>>css.theme: ../../themes/base/theme.css 6259 6260 6261 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g; 6262 6263 var widgetsControlgroup = $.widget( "ui.controlgroup", { 6264 version: "1.12.1", 6265 defaultElement: "<div>", 6266 options: { 6267 direction: "horizontal", 6268 disabled: null, 6269 onlyVisible: true, 6270 items: { 6271 "button": "input[type=button], input[type=submit], input[type=reset], button, a", 6272 "controlgroupLabel": ".ui-controlgroup-label", 6273 "checkboxradio": "input[type='checkbox'], input[type='radio']", 6274 "selectmenu": "select", 6275 "spinner": ".ui-spinner-input" 6276 } 6277 }, 6278 6279 _create: function() { 6280 this._enhance(); 6281 }, 6282 6283 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation 6284 _enhance: function() { 6285 this.element.attr( "role", "toolbar" ); 6286 this.refresh(); 6287 }, 6288 6289 _destroy: function() { 6290 this._callChildMethod( "destroy" ); 6291 this.childWidgets.removeData( "ui-controlgroup-data" ); 6292 this.element.removeAttr( "role" ); 6293 if ( this.options.items.controlgroupLabel ) { 6294 this.element 6295 .find( this.options.items.controlgroupLabel ) 6296 .find( ".ui-controlgroup-label-contents" ) 6297 .contents().unwrap(); 6298 } 6299 }, 6300 6301 _initWidgets: function() { 6302 var that = this, 6303 childWidgets = []; 6304 6305 // First we iterate over each of the items options 6306 $.each( this.options.items, function( widget, selector ) { 6307 var labels; 6308 var options = {}; 6309 6310 // Make sure the widget has a selector set 6311 if ( !selector ) { 6312 return; 6313 } 6314 6315 if ( widget === "controlgroupLabel" ) { 6316 labels = that.element.find( selector ); 6317 labels.each( function() { 6318 var element = $( this ); 6319 6320 if ( element.children( ".ui-controlgroup-label-contents" ).length ) { 6321 return; 6322 } 6323 element.contents() 6324 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" ); 6325 } ); 6326 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" ); 6327 childWidgets = childWidgets.concat( labels.get() ); 6328 return; 6329 } 6330 6331 // Make sure the widget actually exists 6332 if ( !$.fn[ widget ] ) { 6333 return; 6334 } 6335 6336 // We assume everything is in the middle to start because we can't determine 6337 // first / last elements until all enhancments are done. 6338 if ( that[ "_" + widget + "Options" ] ) { 6339 options = that[ "_" + widget + "Options" ]( "middle" ); 6340 } else { 6341 options = { classes: {} }; 6342 } 6343 6344 // Find instances of this widget inside controlgroup and init them 6345 that.element 6346 .find( selector ) 6347 .each( function() { 6348 var element = $( this ); 6349 var instance = element[ widget ]( "instance" ); 6350 6351 // We need to clone the default options for this type of widget to avoid 6352 // polluting the variable options which has a wider scope than a single widget. 6353 var instanceOptions = $.widget.extend( {}, options ); 6354 6355 // If the button is the child of a spinner ignore it 6356 // TODO: Find a more generic solution 6357 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) { 6358 return; 6359 } 6360 6361 // Create the widget if it doesn't exist 6362 if ( !instance ) { 6363 instance = element[ widget ]()[ widget ]( "instance" ); 6364 } 6365 if ( instance ) { 6366 instanceOptions.classes = 6367 that._resolveClassesValues( instanceOptions.classes, instance ); 6368 } 6369 element[ widget ]( instanceOptions ); 6370 6371 // Store an instance of the controlgroup to be able to reference 6372 // from the outermost element for changing options and refresh 6373 var widgetElement = element[ widget ]( "widget" ); 6374 $.data( widgetElement[ 0 ], "ui-controlgroup-data", 6375 instance ? instance : element[ widget ]( "instance" ) ); 6376 6377 childWidgets.push( widgetElement[ 0 ] ); 6378 } ); 6379 } ); 6380 6381 this.childWidgets = $( $.unique( childWidgets ) ); 6382 this._addClass( this.childWidgets, "ui-controlgroup-item" ); 6383 }, 6384 6385 _callChildMethod: function( method ) { 6386 this.childWidgets.each( function() { 6387 var element = $( this ), 6388 data = element.data( "ui-controlgroup-data" ); 6389 if ( data && data[ method ] ) { 6390 data[ method ](); 6391 } 6392 } ); 6393 }, 6394 6395 _updateCornerClass: function( element, position ) { 6396 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all"; 6397 var add = this._buildSimpleOptions( position, "label" ).classes.label; 6398 6399 this._removeClass( element, null, remove ); 6400 this._addClass( element, null, add ); 6401 }, 6402 6403 _buildSimpleOptions: function( position, key ) { 6404 var direction = this.options.direction === "vertical"; 6405 var result = { 6406 classes: {} 6407 }; 6408 result.classes[ key ] = { 6409 "middle": "", 6410 "first": "ui-corner-" + ( direction ? "top" : "left" ), 6411 "last": "ui-corner-" + ( direction ? "bottom" : "right" ), 6412 "only": "ui-corner-all" 6413 }[ position ]; 6414 6415 return result; 6416 }, 6417 6418 _spinnerOptions: function( position ) { 6419 var options = this._buildSimpleOptions( position, "ui-spinner" ); 6420 6421 options.classes[ "ui-spinner-up" ] = ""; 6422 options.classes[ "ui-spinner-down" ] = ""; 6423 6424 return options; 6425 }, 6426 6427 _buttonOptions: function( position ) { 6428 return this._buildSimpleOptions( position, "ui-button" ); 6429 }, 6430 6431 _checkboxradioOptions: function( position ) { 6432 return this._buildSimpleOptions( position, "ui-checkboxradio-label" ); 6433 }, 6434 6435 _selectmenuOptions: function( position ) { 6436 var direction = this.options.direction === "vertical"; 6437 return { 6438 width: direction ? "auto" : false, 6439 classes: { 6440 middle: { 6441 "ui-selectmenu-button-open": "", 6442 "ui-selectmenu-button-closed": "" 6443 }, 6444 first: { 6445 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ), 6446 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" ) 6447 }, 6448 last: { 6449 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr", 6450 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" ) 6451 }, 6452 only: { 6453 "ui-selectmenu-button-open": "ui-corner-top", 6454 "ui-selectmenu-button-closed": "ui-corner-all" 6455 } 6456 6457 }[ position ] 6458 }; 6459 }, 6460 6461 _resolveClassesValues: function( classes, instance ) { 6462 var result = {}; 6463 $.each( classes, function( key ) { 6464 var current = instance.options.classes[ key ] || ""; 6465 current = $.trim( current.replace( controlgroupCornerRegex, "" ) ); 6466 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " ); 6467 } ); 6468 return result; 6469 }, 6470 6471 _setOption: function( key, value ) { 6472 if ( key === "direction" ) { 6473 this._removeClass( "ui-controlgroup-" + this.options.direction ); 6474 } 6475 6476 this._super( key, value ); 6477 if ( key === "disabled" ) { 6478 this._callChildMethod( value ? "disable" : "enable" ); 6479 return; 6480 } 6481 6482 this.refresh(); 6483 }, 6484 6485 refresh: function() { 6486 var children, 6487 that = this; 6488 6489 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); 6490 6491 if ( this.options.direction === "horizontal" ) { 6492 this._addClass( null, "ui-helper-clearfix" ); 6493 } 6494 this._initWidgets(); 6495 6496 children = this.childWidgets; 6497 6498 // We filter here because we need to track all childWidgets not just the visible ones 6499 if ( this.options.onlyVisible ) { 6500 children = children.filter( ":visible" ); 6501 } 6502 6503 if ( children.length ) { 6504 6505 // We do this last because we need to make sure all enhancment is done 6506 // before determining first and last 6507 $.each( [ "first", "last" ], function( index, value ) { 6508 var instance = children[ value ]().data( "ui-controlgroup-data" ); 6509 6510 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) { 6511 var options = that[ "_" + instance.widgetName + "Options" ]( 6512 children.length === 1 ? "only" : value 6513 ); 6514 options.classes = that._resolveClassesValues( options.classes, instance ); 6515 instance.element[ instance.widgetName ]( options ); 6516 } else { 6517 that._updateCornerClass( children[ value ](), value ); 6518 } 6519 } ); 6520 6521 // Finally call the refresh method on each of the child widgets. 6522 this._callChildMethod( "refresh" ); 6523 } 6524 } 6525 } ); 6526 6527 /*! 6528 * jQuery UI Checkboxradio 1.12.1 6529 * http://jqueryui.com 6530 * 6531 * Copyright jQuery Foundation and other contributors 6532 * Released under the MIT license. 6533 * http://jquery.org/license 6534 */ 6535 6536 //>>label: Checkboxradio 6537 //>>group: Widgets 6538 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons. 6539 //>>docs: http://api.jqueryui.com/checkboxradio/ 6540 //>>demos: http://jqueryui.com/checkboxradio/ 6541 //>>css.structure: ../../themes/base/core.css 6542 //>>css.structure: ../../themes/base/button.css 6543 //>>css.structure: ../../themes/base/checkboxradio.css 6544 //>>css.theme: ../../themes/base/theme.css 6545 6546 6547 6548 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, { 6549 version: "1.12.1", 6550 options: { 6551 disabled: null, 6552 label: null, 6553 icon: true, 6554 classes: { 6555 "ui-checkboxradio-label": "ui-corner-all", 6556 "ui-checkboxradio-icon": "ui-corner-all" 6557 } 6558 }, 6559 6560 _getCreateOptions: function() { 6561 var disabled, labels; 6562 var that = this; 6563 var options = this._super() || {}; 6564 6565 // We read the type here, because it makes more sense to throw a element type error first, 6566 // rather then the error for lack of a label. Often if its the wrong type, it 6567 // won't have a label (e.g. calling on a div, btn, etc) 6568 this._readType(); 6569 6570 labels = this.element.labels(); 6571 6572 // If there are multiple labels, use the last one 6573 this.label = $( labels[ labels.length - 1 ] ); 6574 if ( !this.label.length ) { 6575 $.error( "No label found for checkboxradio widget" ); 6576 } 6577 6578 this.originalLabel = ""; 6579 6580 // We need to get the label text but this may also need to make sure it does not contain the 6581 // input itself. 6582 this.label.contents().not( this.element[ 0 ] ).each( function() { 6583 6584 // The label contents could be text, html, or a mix. We concat each element to get a 6585 // string representation of the label, without the input as part of it. 6586 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML; 6587 } ); 6588 6589 // Set the label option if we found label text 6590 if ( this.originalLabel ) { 6591 options.label = this.originalLabel; 6592 } 6593 6594 disabled = this.element[ 0 ].disabled; 6595 if ( disabled != null ) { 6596 options.disabled = disabled; 6597 } 6598 return options; 6599 }, 6600 6601 _create: function() { 6602 var checked = this.element[ 0 ].checked; 6603 6604 this._bindFormResetHandler(); 6605 6606 if ( this.options.disabled == null ) { 6607 this.options.disabled = this.element[ 0 ].disabled; 6608 } 6609 6610 this._setOption( "disabled", this.options.disabled ); 6611 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); 6612 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); 6613 6614 if ( this.type === "radio" ) { 6615 this._addClass( this.label, "ui-checkboxradio-radio-label" ); 6616 } 6617 6618 if ( this.options.label && this.options.label !== this.originalLabel ) { 6619 this._updateLabel(); 6620 } else if ( this.originalLabel ) { 6621 this.options.label = this.originalLabel; 6622 } 6623 6624 this._enhance(); 6625 6626 if ( checked ) { 6627 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); 6628 if ( this.icon ) { 6629 this._addClass( this.icon, null, "ui-state-hover" ); 6630 } 6631 } 6632 6633 this._on( { 6634 change: "_toggleClasses", 6635 focus: function() { 6636 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); 6637 }, 6638 blur: function() { 6639 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); 6640 } 6641 } ); 6642 }, 6643 6644 _readType: function() { 6645 var nodeName = this.element[ 0 ].nodeName.toLowerCase(); 6646 this.type = this.element[ 0 ].type; 6647 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { 6648 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + 6649 " and element.type=" + this.type ); 6650 } 6651 }, 6652 6653 // Support jQuery Mobile enhanced option 6654 _enhance: function() { 6655 this._updateIcon( this.element[ 0 ].checked ); 6656 }, 6657 6658 widget: function() { 6659 return this.label; 6660 }, 6661 6662 _getRadioGroup: function() { 6663 var group; 6664 var name = this.element[ 0 ].name; 6665 var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']"; 6666 6667 if ( !name ) { 6668 return $( [] ); 6669 } 6670 6671 if ( this.form.length ) { 6672 group = $( this.form[ 0 ].elements ).filter( nameSelector ); 6673 } else { 6674 6675 // Not inside a form, check all inputs that also are not inside a form 6676 group = $( nameSelector ).filter( function() { 6677 return $( this ).form().length === 0; 6678 } ); 6679 } 6680 6681 return group.not( this.element ); 6682 }, 6683 6684 _toggleClasses: function() { 6685 var checked = this.element[ 0 ].checked; 6686 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 6687 6688 if ( this.options.icon && this.type === "checkbox" ) { 6689 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked ) 6690 ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); 6691 } 6692 6693 if ( this.type === "radio" ) { 6694 this._getRadioGroup() 6695 .each( function() { 6696 var instance = $( this ).checkboxradio( "instance" ); 6697 6698 if ( instance ) { 6699 instance._removeClass( instance.label, 6700 "ui-checkboxradio-checked", "ui-state-active" ); 6701 } 6702 } ); 6703 } 6704 }, 6705 6706 _destroy: function() { 6707 this._unbindFormResetHandler(); 6708 6709 if ( this.icon ) { 6710 this.icon.remove(); 6711 this.iconSpace.remove(); 6712 } 6713 }, 6714 6715 _setOption: function( key, value ) { 6716 6717 // We don't allow the value to be set to nothing 6718 if ( key === "label" && !value ) { 6719 return; 6720 } 6721 6722 this._super( key, value ); 6723 6724 if ( key === "disabled" ) { 6725 this._toggleClass( this.label, null, "ui-state-disabled", value ); 6726 this.element[ 0 ].disabled = value; 6727 6728 // Don't refresh when setting disabled 6729 return; 6730 } 6731 this.refresh(); 6732 }, 6733 6734 _updateIcon: function( checked ) { 6735 var toAdd = "ui-icon ui-icon-background "; 6736 6737 if ( this.options.icon ) { 6738 if ( !this.icon ) { 6739 this.icon = $( "<span>" ); 6740 this.iconSpace = $( "<span> </span>" ); 6741 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); 6742 } 6743 6744 if ( this.type === "checkbox" ) { 6745 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank"; 6746 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); 6747 } else { 6748 toAdd += "ui-icon-blank"; 6749 } 6750 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); 6751 if ( !checked ) { 6752 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" ); 6753 } 6754 this.icon.prependTo( this.label ).after( this.iconSpace ); 6755 } else if ( this.icon !== undefined ) { 6756 this.icon.remove(); 6757 this.iconSpace.remove(); 6758 delete this.icon; 6759 } 6760 }, 6761 6762 _updateLabel: function() { 6763 6764 // Remove the contents of the label ( minus the icon, icon space, and input ) 6765 var contents = this.label.contents().not( this.element[ 0 ] ); 6766 if ( this.icon ) { 6767 contents = contents.not( this.icon[ 0 ] ); 6768 } 6769 if ( this.iconSpace ) { 6770 contents = contents.not( this.iconSpace[ 0 ] ); 6771 } 6772 contents.remove(); 6773 6774 this.label.append( this.options.label ); 6775 }, 6776 6777 refresh: function() { 6778 var checked = this.element[ 0 ].checked, 6779 isDisabled = this.element[ 0 ].disabled; 6780 6781 this._updateIcon( checked ); 6782 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 6783 if ( this.options.label !== null ) { 6784 this._updateLabel(); 6785 } 6786 6787 if ( isDisabled !== this.options.disabled ) { 6788 this._setOptions( { "disabled": isDisabled } ); 6789 } 6790 } 6791 6792 } ] ); 6793 6794 var widgetsCheckboxradio = $.ui.checkboxradio; 6795 6796 6797 /*! 6798 * jQuery UI Button 1.12.1 6799 * http://jqueryui.com 6800 * 6801 * Copyright jQuery Foundation and other contributors 6802 * Released under the MIT license. 6803 * http://jquery.org/license 6804 */ 6805 6806 //>>label: Button 6807 //>>group: Widgets 6808 //>>description: Enhances a form with themeable buttons. 6809 //>>docs: http://api.jqueryui.com/button/ 6810 //>>demos: http://jqueryui.com/button/ 6811 //>>css.structure: ../../themes/base/core.css 6812 //>>css.structure: ../../themes/base/button.css 6813 //>>css.theme: ../../themes/base/theme.css 6814 6815 6816 6817 $.widget( "ui.button", { 6818 version: "1.12.1", 6819 defaultElement: "<button>", 6820 options: { 6821 classes: { 6822 "ui-button": "ui-corner-all" 6823 }, 6824 disabled: null, 6825 icon: null, 6826 iconPosition: "beginning", 6827 label: null, 6828 showLabel: true 6829 }, 6830 6831 _getCreateOptions: function() { 6832 var disabled, 6833 6834 // This is to support cases like in jQuery Mobile where the base widget does have 6835 // an implementation of _getCreateOptions 6836 options = this._super() || {}; 6837 6838 this.isInput = this.element.is( "input" ); 6839 6840 disabled = this.element[ 0 ].disabled; 6841 if ( disabled != null ) { 6842 options.disabled = disabled; 6843 } 6844 6845 this.originalLabel = this.isInput ? this.element.val() : this.element.html(); 6846 if ( this.originalLabel ) { 6847 options.label = this.originalLabel; 6848 } 6849 6850 return options; 6851 }, 6852 6853 _create: function() { 6854 if ( !this.option.showLabel & !this.options.icon ) { 6855 this.options.showLabel = true; 6856 } 6857 6858 // We have to check the option again here even though we did in _getCreateOptions, 6859 // because null may have been passed on init which would override what was set in 6860 // _getCreateOptions 6861 if ( this.options.disabled == null ) { 6862 this.options.disabled = this.element[ 0 ].disabled || false; 6863 } 6864 6865 this.hasTitle = !!this.element.attr( "title" ); 6866 6867 // Check to see if the label needs to be set or if its already correct 6868 if ( this.options.label && this.options.label !== this.originalLabel ) { 6869 if ( this.isInput ) { 6870 this.element.val( this.options.label ); 6871 } else { 6872 this.element.html( this.options.label ); 6873 } 6874 } 6875 this._addClass( "ui-button", "ui-widget" ); 6876 this._setOption( "disabled", this.options.disabled ); 6877 this._enhance(); 6878 6879 if ( this.element.is( "a" ) ) { 6880 this._on( { 6881 "keyup": function( event ) { 6882 if ( event.keyCode === $.ui.keyCode.SPACE ) { 6883 event.preventDefault(); 6884 6885 // Support: PhantomJS <= 1.9, IE 8 Only 6886 // If a native click is available use it so we actually cause navigation 6887 // otherwise just trigger a click event 6888 if ( this.element[ 0 ].click ) { 6889 this.element[ 0 ].click(); 6890 } else { 6891 this.element.trigger( "click" ); 6892 } 6893 } 6894 } 6895 } ); 6896 } 6897 }, 6898 6899 _enhance: function() { 6900 if ( !this.element.is( "button" ) ) { 6901 this.element.attr( "role", "button" ); 6902 } 6903 6904 if ( this.options.icon ) { 6905 this._updateIcon( "icon", this.options.icon ); 6906 this._updateTooltip(); 6907 } 6908 }, 6909 6910 _updateTooltip: function() { 6911 this.title = this.element.attr( "title" ); 6912 6913 if ( !this.options.showLabel && !this.title ) { 6914 this.element.attr( "title", this.options.label ); 6915 } 6916 }, 6917 6918 _updateIcon: function( option, value ) { 6919 var icon = option !== "iconPosition", 6920 position = icon ? this.options.iconPosition : value, 6921 displayBlock = position === "top" || position === "bottom"; 6922 6923 // Create icon 6924 if ( !this.icon ) { 6925 this.icon = $( "<span>" ); 6926 6927 this._addClass( this.icon, "ui-button-icon", "ui-icon" ); 6928 6929 if ( !this.options.showLabel ) { 6930 this._addClass( "ui-button-icon-only" ); 6931 } 6932 } else if ( icon ) { 6933 6934 // If we are updating the icon remove the old icon class 6935 this._removeClass( this.icon, null, this.options.icon ); 6936 } 6937 6938 // If we are updating the icon add the new icon class 6939 if ( icon ) { 6940 this._addClass( this.icon, null, value ); 6941 } 6942 6943 this._attachIcon( position ); 6944 6945 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove 6946 // the iconSpace if there is one. 6947 if ( displayBlock ) { 6948 this._addClass( this.icon, null, "ui-widget-icon-block" ); 6949 if ( this.iconSpace ) { 6950 this.iconSpace.remove(); 6951 } 6952 } else { 6953 6954 // Position is beginning or end so remove the ui-widget-icon-block class and add the 6955 // space if it does not exist 6956 if ( !this.iconSpace ) { 6957 this.iconSpace = $( "<span> </span>" ); 6958 this._addClass( this.iconSpace, "ui-button-icon-space" ); 6959 } 6960 this._removeClass( this.icon, null, "ui-wiget-icon-block" ); 6961 this._attachIconSpace( position ); 6962 } 6963 }, 6964 6965 _destroy: function() { 6966 this.element.removeAttr( "role" ); 6967 6968 if ( this.icon ) { 6969 this.icon.remove(); 6970 } 6971 if ( this.iconSpace ) { 6972 this.iconSpace.remove(); 6973 } 6974 if ( !this.hasTitle ) { 6975 this.element.removeAttr( "title" ); 6976 } 6977 }, 6978 6979 _attachIconSpace: function( iconPosition ) { 6980 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace ); 6981 }, 6982 6983 _attachIcon: function( iconPosition ) { 6984 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon ); 6985 }, 6986 6987 _setOptions: function( options ) { 6988 var newShowLabel = options.showLabel === undefined ? 6989 this.options.showLabel : 6990 options.showLabel, 6991 newIcon = options.icon === undefined ? this.options.icon : options.icon; 6992 6993 if ( !newShowLabel && !newIcon ) { 6994 options.showLabel = true; 6995 } 6996 this._super( options ); 6997 }, 6998 6999 _setOption: function( key, value ) { 7000 if ( key === "icon" ) { 7001 if ( value ) { 7002 this._updateIcon( key, value ); 7003 } else if ( this.icon ) { 7004 this.icon.remove(); 7005 if ( this.iconSpace ) { 7006 this.iconSpace.remove(); 7007 } 7008 } 7009 } 7010 7011 if ( key === "iconPosition" ) { 7012 this._updateIcon( key, value ); 7013 } 7014 7015 // Make sure we can't end up with a button that has neither text nor icon 7016 if ( key === "showLabel" ) { 7017 this._toggleClass( "ui-button-icon-only", null, !value ); 7018 this._updateTooltip(); 7019 } 7020 7021 if ( key === "label" ) { 7022 if ( this.isInput ) { 7023 this.element.val( value ); 7024 } else { 7025 7026 // If there is an icon, append it, else nothing then append the value 7027 // this avoids removal of the icon when setting label text 7028 this.element.html( value ); 7029 if ( this.icon ) { 7030 this._attachIcon( this.options.iconPosition ); 7031 this._attachIconSpace( this.options.iconPosition ); 7032 } 7033 } 7034 } 7035 7036 this._super( key, value ); 7037 7038 if ( key === "disabled" ) { 7039 this._toggleClass( null, "ui-state-disabled", value ); 7040 this.element[ 0 ].disabled = value; 7041 if ( value ) { 7042 this.element.blur(); 7043 } 7044 } 7045 }, 7046 7047 refresh: function() { 7048 7049 // Make sure to only check disabled if its an element that supports this otherwise 7050 // check for the disabled class to determine state 7051 var isDisabled = this.element.is( "input, button" ) ? 7052 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" ); 7053 7054 if ( isDisabled !== this.options.disabled ) { 7055 this._setOptions( { disabled: isDisabled } ); 7056 } 7057 7058 this._updateTooltip(); 7059 } 7060 } ); 7061 7062 // DEPRECATED 7063 if ( $.uiBackCompat !== false ) { 7064 7065 // Text and Icons options 7066 $.widget( "ui.button", $.ui.button, { 7067 options: { 7068 text: true, 7069 icons: { 7070 primary: null, 7071 secondary: null 7072 } 7073 }, 7074 7075 _create: function() { 7076 if ( this.options.showLabel && !this.options.text ) { 7077 this.options.showLabel = this.options.text; 7078 } 7079 if ( !this.options.showLabel && this.options.text ) { 7080 this.options.text = this.options.showLabel; 7081 } 7082 if ( !this.options.icon && ( this.options.icons.primary || 7083 this.options.icons.secondary ) ) { 7084 if ( this.options.icons.primary ) { 7085 this.options.icon = this.options.icons.primary; 7086 } else { 7087 this.options.icon = this.options.icons.secondary; 7088 this.options.iconPosition = "end"; 7089 } 7090 } else if ( this.options.icon ) { 7091 this.options.icons.primary = this.options.icon; 7092 } 7093 this._super(); 7094 }, 7095 7096 _setOption: function( key, value ) { 7097 if ( key === "text" ) { 7098 this._super( "showLabel", value ); 7099 return; 7100 } 7101 if ( key === "showLabel" ) { 7102 this.options.text = value; 7103 } 7104 if ( key === "icon" ) { 7105 this.options.icons.primary = value; 7106 } 7107 if ( key === "icons" ) { 7108 if ( value.primary ) { 7109 this._super( "icon", value.primary ); 7110 this._super( "iconPosition", "beginning" ); 7111 } else if ( value.secondary ) { 7112 this._super( "icon", value.secondary ); 7113 this._super( "iconPosition", "end" ); 7114 } 7115 } 7116 this._superApply( arguments ); 7117 } 7118 } ); 7119 7120 $.fn.button = ( function( orig ) { 7121 return function() { 7122 if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) || 7123 ( this.length && this[ 0 ].tagName === "INPUT" && ( 7124 this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio" 7125 ) ) ) { 7126 return orig.apply( this, arguments ); 7127 } 7128 if ( !$.ui.checkboxradio ) { 7129 $.error( "Checkboxradio widget missing" ); 7130 } 7131 if ( arguments.length === 0 ) { 7132 return this.checkboxradio( { 7133 "icon": false 7134 } ); 7135 } 7136 return this.checkboxradio.apply( this, arguments ); 7137 }; 7138 } )( $.fn.button ); 7139 7140 $.fn.buttonset = function() { 7141 if ( !$.ui.controlgroup ) { 7142 $.error( "Controlgroup widget missing" ); 7143 } 7144 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) { 7145 return this.controlgroup.apply( this, 7146 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] ); 7147 } 7148 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) { 7149 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] ); 7150 } 7151 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) { 7152 arguments[ 0 ].items = { 7153 button: arguments[ 0 ].items 7154 }; 7155 } 7156 return this.controlgroup.apply( this, arguments ); 7157 }; 7158 } 7159 7160 var widgetsButton = $.ui.button; 7161 7162 7163 // jscs:disable maximumLineLength 7164 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */ 7165 /*! 7166 * jQuery UI Datepicker 1.12.1 7167 * http://jqueryui.com 7168 * 7169 * Copyright jQuery Foundation and other contributors 7170 * Released under the MIT license. 7171 * http://jquery.org/license 7172 */ 7173 7174 //>>label: Datepicker 7175 //>>group: Widgets 7176 //>>description: Displays a calendar from an input or inline for selecting dates. 7177 //>>docs: http://api.jqueryui.com/datepicker/ 7178 //>>demos: http://jqueryui.com/datepicker/ 7179 //>>css.structure: ../../themes/base/core.css 7180 //>>css.structure: ../../themes/base/datepicker.css 7181 //>>css.theme: ../../themes/base/theme.css 7182 7183 7184 7185 $.extend( $.ui, { datepicker: { version: "1.12.1" } } ); 7186 7187 var datepicker_instActive; 7188 7189 function datepicker_getZindex( elem ) { 7190 var position, value; 7191 while ( elem.length && elem[ 0 ] !== document ) { 7192 7193 // Ignore z-index if position is set to a value where z-index is ignored by the browser 7194 // This makes behavior of this function consistent across browsers 7195 // WebKit always returns auto if the element is positioned 7196 position = elem.css( "position" ); 7197 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 7198 7199 // IE returns 0 when zIndex is not specified 7200 // other browsers return a string 7201 // we ignore the case of nested elements with an explicit value of 0 7202 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 7203 value = parseInt( elem.css( "zIndex" ), 10 ); 7204 if ( !isNaN( value ) && value !== 0 ) { 7205 return value; 7206 } 7207 } 7208 elem = elem.parent(); 7209 } 7210 7211 return 0; 7212 } 7213 /* Date picker manager. 7214 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 7215 Settings for (groups of) date pickers are maintained in an instance object, 7216 allowing multiple different settings on the same page. */ 7217 7218 function Datepicker() { 7219 this._curInst = null; // The current instance in use 7220 this._keyEvent = false; // If the last event was a key event 7221 this._disabledInputs = []; // List of date picker inputs that have been disabled 7222 this._datepickerShowing = false; // True if the popup picker is showing , false if not 7223 this._inDialog = false; // True if showing within a "dialog", false if not 7224 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 7225 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 7226 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 7227 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 7228 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 7229 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 7230 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 7231 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 7232 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 7233 this.regional = []; // Available regional settings, indexed by language code 7234 this.regional[ "" ] = { // Default regional settings 7235 closeText: "Done", // Display text for close link 7236 prevText: "Prev", // Display text for previous month link 7237 nextText: "Next", // Display text for next month link 7238 currentText: "Today", // Display text for current month link 7239 monthNames: [ "January","February","March","April","May","June", 7240 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting 7241 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting 7242 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting 7243 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting 7244 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday 7245 weekHeader: "Wk", // Column header for week of the year 7246 dateFormat: "mm/dd/yy", // See format options on parseDate 7247 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 7248 isRTL: false, // True if right-to-left language, false if left-to-right 7249 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 7250 yearSuffix: "" // Additional text to append to the year in the month headers 7251 }; 7252 this._defaults = { // Global defaults for all the date picker instances 7253 showOn: "focus", // "focus" for popup on focus, 7254 // "button" for trigger button, or "both" for either 7255 showAnim: "fadeIn", // Name of jQuery animation for popup 7256 showOptions: {}, // Options for enhanced animations 7257 defaultDate: null, // Used when field is blank: actual date, 7258 // +/-number for offset from today, null for today 7259 appendText: "", // Display text following the input box, e.g. showing the format 7260 buttonText: "...", // Text for trigger button 7261 buttonImage: "", // URL for trigger button image 7262 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 7263 hideIfNoPrevNext: false, // True to hide next/previous month links 7264 // if not applicable, false to just disable them 7265 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 7266 gotoCurrent: false, // True if today link goes back to current selection instead 7267 changeMonth: false, // True if month can be selected directly, false if only prev/next 7268 changeYear: false, // True if year can be selected directly, false if only prev/next 7269 yearRange: "c-10:c+10", // Range of years to display in drop-down, 7270 // either relative to today's year (-nn:+nn), relative to currently displayed year 7271 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 7272 showOtherMonths: false, // True to show dates in other months, false to leave blank 7273 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 7274 showWeek: false, // True to show week of the year, false to not show it 7275 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 7276 // takes a Date and returns the number of the week for it 7277 shortYearCutoff: "+10", // Short year values < this are in the current century, 7278 // > this are in the previous century, 7279 // string value starting with "+" for current year + value 7280 minDate: null, // The earliest selectable date, or null for no limit 7281 maxDate: null, // The latest selectable date, or null for no limit 7282 duration: "fast", // Duration of display/closure 7283 beforeShowDay: null, // Function that takes a date and returns an array with 7284 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 7285 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 7286 beforeShow: null, // Function that takes an input field and 7287 // returns a set of custom settings for the date picker 7288 onSelect: null, // Define a callback function when a date is selected 7289 onChangeMonthYear: null, // Define a callback function when the month or year is changed 7290 onClose: null, // Define a callback function when the datepicker is closed 7291 numberOfMonths: 1, // Number of months to show at a time 7292 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 7293 stepMonths: 1, // Number of months to step back/forward 7294 stepBigMonths: 12, // Number of months to step back/forward for the big links 7295 altField: "", // Selector for an alternate field to store selected dates into 7296 altFormat: "", // The date format to use for the alternate field 7297 constrainInput: true, // The input is constrained by the current date format 7298 showButtonPanel: false, // True to show button panel, false to not show it 7299 autoSize: false, // True to size the input for the date format, false to leave as is 7300 disabled: false // The initial disabled state 7301 }; 7302 $.extend( this._defaults, this.regional[ "" ] ); 7303 this.regional.en = $.extend( true, {}, this.regional[ "" ] ); 7304 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 7305 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 7306 } 7307 7308 $.extend( Datepicker.prototype, { 7309 /* Class name added to elements to indicate already configured with a date picker. */ 7310 markerClassName: "hasDatepicker", 7311 7312 //Keep track of the maximum number of rows displayed (see #7043) 7313 maxRows: 4, 7314 7315 // TODO rename to "widget" when switching to widget factory 7316 _widgetDatepicker: function() { 7317 return this.dpDiv; 7318 }, 7319 7320 /* Override the default settings for all instances of the date picker. 7321 * @param settings object - the new settings to use as defaults (anonymous object) 7322 * @return the manager object 7323 */ 7324 setDefaults: function( settings ) { 7325 datepicker_extendRemove( this._defaults, settings || {} ); 7326 return this; 7327 }, 7328 7329 /* Attach the date picker to a jQuery selection. 7330 * @param target element - the target input field or division or span 7331 * @param settings object - the new settings to use for this date picker instance (anonymous) 7332 */ 7333 _attachDatepicker: function( target, settings ) { 7334 var nodeName, inline, inst; 7335 nodeName = target.nodeName.toLowerCase(); 7336 inline = ( nodeName === "div" || nodeName === "span" ); 7337 if ( !target.id ) { 7338 this.uuid += 1; 7339 target.id = "dp" + this.uuid; 7340 } 7341 inst = this._newInst( $( target ), inline ); 7342 inst.settings = $.extend( {}, settings || {} ); 7343 if ( nodeName === "input" ) { 7344 this._connectDatepicker( target, inst ); 7345 } else if ( inline ) { 7346 this._inlineDatepicker( target, inst ); 7347 } 7348 }, 7349 7350 /* Create a new instance object. */ 7351 _newInst: function( target, inline ) { 7352 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars 7353 return { id: id, input: target, // associated target 7354 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 7355 drawMonth: 0, drawYear: 0, // month being drawn 7356 inline: inline, // is datepicker inline or not 7357 dpDiv: ( !inline ? this.dpDiv : // presentation div 7358 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) }; 7359 }, 7360 7361 /* Attach the date picker to an input field. */ 7362 _connectDatepicker: function( target, inst ) { 7363 var input = $( target ); 7364 inst.append = $( [] ); 7365 inst.trigger = $( [] ); 7366 if ( input.hasClass( this.markerClassName ) ) { 7367 return; 7368 } 7369 this._attachments( input, inst ); 7370 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ). 7371 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp ); 7372 this._autoSize( inst ); 7373 $.data( target, "datepicker", inst ); 7374 7375 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 7376 if ( inst.settings.disabled ) { 7377 this._disableDatepicker( target ); 7378 } 7379 }, 7380 7381 /* Make attachments based on settings. */ 7382 _attachments: function( input, inst ) { 7383 var showOn, buttonText, buttonImage, 7384 appendText = this._get( inst, "appendText" ), 7385 isRTL = this._get( inst, "isRTL" ); 7386 7387 if ( inst.append ) { 7388 inst.append.remove(); 7389 } 7390 if ( appendText ) { 7391 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" ); 7392 input[ isRTL ? "before" : "after" ]( inst.append ); 7393 } 7394 7395 input.off( "focus", this._showDatepicker ); 7396 7397 if ( inst.trigger ) { 7398 inst.trigger.remove(); 7399 } 7400 7401 showOn = this._get( inst, "showOn" ); 7402 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field 7403 input.on( "focus", this._showDatepicker ); 7404 } 7405 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked 7406 buttonText = this._get( inst, "buttonText" ); 7407 buttonImage = this._get( inst, "buttonImage" ); 7408 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ? 7409 $( "<img/>" ).addClass( this._triggerClass ). 7410 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) : 7411 $( "<button type='button'></button>" ).addClass( this._triggerClass ). 7412 html( !buttonImage ? buttonText : $( "<img/>" ).attr( 7413 { src:buttonImage, alt:buttonText, title:buttonText } ) ) ); 7414 input[ isRTL ? "before" : "after" ]( inst.trigger ); 7415 inst.trigger.on( "click", function() { 7416 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) { 7417 $.datepicker._hideDatepicker(); 7418 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) { 7419 $.datepicker._hideDatepicker(); 7420 $.datepicker._showDatepicker( input[ 0 ] ); 7421 } else { 7422 $.datepicker._showDatepicker( input[ 0 ] ); 7423 } 7424 return false; 7425 } ); 7426 } 7427 }, 7428 7429 /* Apply the maximum length for the date format. */ 7430 _autoSize: function( inst ) { 7431 if ( this._get( inst, "autoSize" ) && !inst.inline ) { 7432 var findMax, max, maxI, i, 7433 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits 7434 dateFormat = this._get( inst, "dateFormat" ); 7435 7436 if ( dateFormat.match( /[DM]/ ) ) { 7437 findMax = function( names ) { 7438 max = 0; 7439 maxI = 0; 7440 for ( i = 0; i < names.length; i++ ) { 7441 if ( names[ i ].length > max ) { 7442 max = names[ i ].length; 7443 maxI = i; 7444 } 7445 } 7446 return maxI; 7447 }; 7448 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ? 7449 "monthNames" : "monthNamesShort" ) ) ) ); 7450 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ? 7451 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() ); 7452 } 7453 inst.input.attr( "size", this._formatDate( inst, date ).length ); 7454 } 7455 }, 7456 7457 /* Attach an inline date picker to a div. */ 7458 _inlineDatepicker: function( target, inst ) { 7459 var divSpan = $( target ); 7460 if ( divSpan.hasClass( this.markerClassName ) ) { 7461 return; 7462 } 7463 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 7464 $.data( target, "datepicker", inst ); 7465 this._setDate( inst, this._getDefaultDate( inst ), true ); 7466 this._updateDatepicker( inst ); 7467 this._updateAlternate( inst ); 7468 7469 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 7470 if ( inst.settings.disabled ) { 7471 this._disableDatepicker( target ); 7472 } 7473 7474 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 7475 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 7476 inst.dpDiv.css( "display", "block" ); 7477 }, 7478 7479 /* Pop-up the date picker in a "dialog" box. 7480 * @param input element - ignored 7481 * @param date string or Date - the initial date to display 7482 * @param onSelect function - the function to call when a date is selected 7483 * @param settings object - update the dialog date picker instance's settings (anonymous object) 7484 * @param pos int[2] - coordinates for the dialog's position within the screen or 7485 * event - with x/y coordinates or 7486 * leave empty for default (screen centre) 7487 * @return the manager object 7488 */ 7489 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 7490 var id, browserWidth, browserHeight, scrollX, scrollY, 7491 inst = this._dialogInst; // internal instance 7492 7493 if ( !inst ) { 7494 this.uuid += 1; 7495 id = "dp" + this.uuid; 7496 this._dialogInput = $( "<input type='text' id='" + id + 7497 "' style='position: absolute; top: -100px; width: 0px;'/>" ); 7498 this._dialogInput.on( "keydown", this._doKeyDown ); 7499 $( "body" ).append( this._dialogInput ); 7500 inst = this._dialogInst = this._newInst( this._dialogInput, false ); 7501 inst.settings = {}; 7502 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7503 } 7504 datepicker_extendRemove( inst.settings, settings || {} ); 7505 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date ); 7506 this._dialogInput.val( date ); 7507 7508 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null ); 7509 if ( !this._pos ) { 7510 browserWidth = document.documentElement.clientWidth; 7511 browserHeight = document.documentElement.clientHeight; 7512 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 7513 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 7514 this._pos = // should use actual width/height below 7515 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 7516 } 7517 7518 // Move input on screen for focus, but hidden behind dialog 7519 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" ); 7520 inst.settings.onSelect = onSelect; 7521 this._inDialog = true; 7522 this.dpDiv.addClass( this._dialogClass ); 7523 this._showDatepicker( this._dialogInput[ 0 ] ); 7524 if ( $.blockUI ) { 7525 $.blockUI( this.dpDiv ); 7526 } 7527 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7528 return this; 7529 }, 7530 7531 /* Detach a datepicker from its control. 7532 * @param target element - the target input field or division or span 7533 */ 7534 _destroyDatepicker: function( target ) { 7535 var nodeName, 7536 $target = $( target ), 7537 inst = $.data( target, "datepicker" ); 7538 7539 if ( !$target.hasClass( this.markerClassName ) ) { 7540 return; 7541 } 7542 7543 nodeName = target.nodeName.toLowerCase(); 7544 $.removeData( target, "datepicker" ); 7545 if ( nodeName === "input" ) { 7546 inst.append.remove(); 7547 inst.trigger.remove(); 7548 $target.removeClass( this.markerClassName ). 7549 off( "focus", this._showDatepicker ). 7550 off( "keydown", this._doKeyDown ). 7551 off( "keypress", this._doKeyPress ). 7552 off( "keyup", this._doKeyUp ); 7553 } else if ( nodeName === "div" || nodeName === "span" ) { 7554 $target.removeClass( this.markerClassName ).empty(); 7555 } 7556 7557 if ( datepicker_instActive === inst ) { 7558 datepicker_instActive = null; 7559 } 7560 }, 7561 7562 /* Enable the date picker to a jQuery selection. 7563 * @param target element - the target input field or division or span 7564 */ 7565 _enableDatepicker: function( target ) { 7566 var nodeName, inline, 7567 $target = $( target ), 7568 inst = $.data( target, "datepicker" ); 7569 7570 if ( !$target.hasClass( this.markerClassName ) ) { 7571 return; 7572 } 7573 7574 nodeName = target.nodeName.toLowerCase(); 7575 if ( nodeName === "input" ) { 7576 target.disabled = false; 7577 inst.trigger.filter( "button" ). 7578 each( function() { this.disabled = false; } ).end(). 7579 filter( "img" ).css( { opacity: "1.0", cursor: "" } ); 7580 } else if ( nodeName === "div" || nodeName === "span" ) { 7581 inline = $target.children( "." + this._inlineClass ); 7582 inline.children().removeClass( "ui-state-disabled" ); 7583 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7584 prop( "disabled", false ); 7585 } 7586 this._disabledInputs = $.map( this._disabledInputs, 7587 function( value ) { return ( value === target ? null : value ); } ); // delete entry 7588 }, 7589 7590 /* Disable the date picker to a jQuery selection. 7591 * @param target element - the target input field or division or span 7592 */ 7593 _disableDatepicker: function( target ) { 7594 var nodeName, inline, 7595 $target = $( target ), 7596 inst = $.data( target, "datepicker" ); 7597 7598 if ( !$target.hasClass( this.markerClassName ) ) { 7599 return; 7600 } 7601 7602 nodeName = target.nodeName.toLowerCase(); 7603 if ( nodeName === "input" ) { 7604 target.disabled = true; 7605 inst.trigger.filter( "button" ). 7606 each( function() { this.disabled = true; } ).end(). 7607 filter( "img" ).css( { opacity: "0.5", cursor: "default" } ); 7608 } else if ( nodeName === "div" || nodeName === "span" ) { 7609 inline = $target.children( "." + this._inlineClass ); 7610 inline.children().addClass( "ui-state-disabled" ); 7611 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7612 prop( "disabled", true ); 7613 } 7614 this._disabledInputs = $.map( this._disabledInputs, 7615 function( value ) { return ( value === target ? null : value ); } ); // delete entry 7616 this._disabledInputs[ this._disabledInputs.length ] = target; 7617 }, 7618 7619 /* Is the first field in a jQuery collection disabled as a datepicker? 7620 * @param target element - the target input field or division or span 7621 * @return boolean - true if disabled, false if enabled 7622 */ 7623 _isDisabledDatepicker: function( target ) { 7624 if ( !target ) { 7625 return false; 7626 } 7627 for ( var i = 0; i < this._disabledInputs.length; i++ ) { 7628 if ( this._disabledInputs[ i ] === target ) { 7629 return true; 7630 } 7631 } 7632 return false; 7633 }, 7634 7635 /* Retrieve the instance data for the target control. 7636 * @param target element - the target input field or division or span 7637 * @return object - the associated instance data 7638 * @throws error if a jQuery problem getting data 7639 */ 7640 _getInst: function( target ) { 7641 try { 7642 return $.data( target, "datepicker" ); 7643 } 7644 catch ( err ) { 7645 throw "Missing instance data for this datepicker"; 7646 } 7647 }, 7648 7649 /* Update or retrieve the settings for a date picker attached to an input field or division. 7650 * @param target element - the target input field or division or span 7651 * @param name object - the new settings to update or 7652 * string - the name of the setting to change or retrieve, 7653 * when retrieving also "all" for all instance settings or 7654 * "defaults" for all global defaults 7655 * @param value any - the new value for the setting 7656 * (omit if above is an object or to retrieve a value) 7657 */ 7658 _optionDatepicker: function( target, name, value ) { 7659 var settings, date, minDate, maxDate, 7660 inst = this._getInst( target ); 7661 7662 if ( arguments.length === 2 && typeof name === "string" ) { 7663 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) : 7664 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) : 7665 this._get( inst, name ) ) : null ) ); 7666 } 7667 7668 settings = name || {}; 7669 if ( typeof name === "string" ) { 7670 settings = {}; 7671 settings[ name ] = value; 7672 } 7673 7674 if ( inst ) { 7675 if ( this._curInst === inst ) { 7676 this._hideDatepicker(); 7677 } 7678 7679 date = this._getDateDatepicker( target, true ); 7680 minDate = this._getMinMaxDate( inst, "min" ); 7681 maxDate = this._getMinMaxDate( inst, "max" ); 7682 datepicker_extendRemove( inst.settings, settings ); 7683 7684 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 7685 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 7686 inst.settings.minDate = this._formatDate( inst, minDate ); 7687 } 7688 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 7689 inst.settings.maxDate = this._formatDate( inst, maxDate ); 7690 } 7691 if ( "disabled" in settings ) { 7692 if ( settings.disabled ) { 7693 this._disableDatepicker( target ); 7694 } else { 7695 this._enableDatepicker( target ); 7696 } 7697 } 7698 this._attachments( $( target ), inst ); 7699 this._autoSize( inst ); 7700 this._setDate( inst, date ); 7701 this._updateAlternate( inst ); 7702 this._updateDatepicker( inst ); 7703 } 7704 }, 7705 7706 // Change method deprecated 7707 _changeDatepicker: function( target, name, value ) { 7708 this._optionDatepicker( target, name, value ); 7709 }, 7710 7711 /* Redraw the date picker attached to an input field or division. 7712 * @param target element - the target input field or division or span 7713 */ 7714 _refreshDatepicker: function( target ) { 7715 var inst = this._getInst( target ); 7716 if ( inst ) { 7717 this._updateDatepicker( inst ); 7718 } 7719 }, 7720 7721 /* Set the dates for a jQuery selection. 7722 * @param target element - the target input field or division or span 7723 * @param date Date - the new date 7724 */ 7725 _setDateDatepicker: function( target, date ) { 7726 var inst = this._getInst( target ); 7727 if ( inst ) { 7728 this._setDate( inst, date ); 7729 this._updateDatepicker( inst ); 7730 this._updateAlternate( inst ); 7731 } 7732 }, 7733 7734 /* Get the date(s) for the first entry in a jQuery selection. 7735 * @param target element - the target input field or division or span 7736 * @param noDefault boolean - true if no default date is to be used 7737 * @return Date - the current date 7738 */ 7739 _getDateDatepicker: function( target, noDefault ) { 7740 var inst = this._getInst( target ); 7741 if ( inst && !inst.inline ) { 7742 this._setDateFromField( inst, noDefault ); 7743 } 7744 return ( inst ? this._getDate( inst ) : null ); 7745 }, 7746 7747 /* Handle keystrokes. */ 7748 _doKeyDown: function( event ) { 7749 var onSelect, dateStr, sel, 7750 inst = $.datepicker._getInst( event.target ), 7751 handled = true, 7752 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" ); 7753 7754 inst._keyEvent = true; 7755 if ( $.datepicker._datepickerShowing ) { 7756 switch ( event.keyCode ) { 7757 case 9: $.datepicker._hideDatepicker(); 7758 handled = false; 7759 break; // hide on tab out 7760 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." + 7761 $.datepicker._currentClass + ")", inst.dpDiv ); 7762 if ( sel[ 0 ] ) { 7763 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 7764 } 7765 7766 onSelect = $.datepicker._get( inst, "onSelect" ); 7767 if ( onSelect ) { 7768 dateStr = $.datepicker._formatDate( inst ); 7769 7770 // Trigger custom callback 7771 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); 7772 } else { 7773 $.datepicker._hideDatepicker(); 7774 } 7775 7776 return false; // don't submit the form 7777 case 27: $.datepicker._hideDatepicker(); 7778 break; // hide on escape 7779 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7780 -$.datepicker._get( inst, "stepBigMonths" ) : 7781 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7782 break; // previous month/year on page up/+ ctrl 7783 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7784 +$.datepicker._get( inst, "stepBigMonths" ) : 7785 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7786 break; // next month/year on page down/+ ctrl 7787 case 35: if ( event.ctrlKey || event.metaKey ) { 7788 $.datepicker._clearDate( event.target ); 7789 } 7790 handled = event.ctrlKey || event.metaKey; 7791 break; // clear on ctrl or command +end 7792 case 36: if ( event.ctrlKey || event.metaKey ) { 7793 $.datepicker._gotoToday( event.target ); 7794 } 7795 handled = event.ctrlKey || event.metaKey; 7796 break; // current on ctrl or command +home 7797 case 37: if ( event.ctrlKey || event.metaKey ) { 7798 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" ); 7799 } 7800 handled = event.ctrlKey || event.metaKey; 7801 7802 // -1 day on ctrl or command +left 7803 if ( event.originalEvent.altKey ) { 7804 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7805 -$.datepicker._get( inst, "stepBigMonths" ) : 7806 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7807 } 7808 7809 // next month/year on alt +left on Mac 7810 break; 7811 case 38: if ( event.ctrlKey || event.metaKey ) { 7812 $.datepicker._adjustDate( event.target, -7, "D" ); 7813 } 7814 handled = event.ctrlKey || event.metaKey; 7815 break; // -1 week on ctrl or command +up 7816 case 39: if ( event.ctrlKey || event.metaKey ) { 7817 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" ); 7818 } 7819 handled = event.ctrlKey || event.metaKey; 7820 7821 // +1 day on ctrl or command +right 7822 if ( event.originalEvent.altKey ) { 7823 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7824 +$.datepicker._get( inst, "stepBigMonths" ) : 7825 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7826 } 7827 7828 // next month/year on alt +right 7829 break; 7830 case 40: if ( event.ctrlKey || event.metaKey ) { 7831 $.datepicker._adjustDate( event.target, +7, "D" ); 7832 } 7833 handled = event.ctrlKey || event.metaKey; 7834 break; // +1 week on ctrl or command +down 7835 default: handled = false; 7836 } 7837 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home 7838 $.datepicker._showDatepicker( this ); 7839 } else { 7840 handled = false; 7841 } 7842 7843 if ( handled ) { 7844 event.preventDefault(); 7845 event.stopPropagation(); 7846 } 7847 }, 7848 7849 /* Filter entered characters - based on date format. */ 7850 _doKeyPress: function( event ) { 7851 var chars, chr, 7852 inst = $.datepicker._getInst( event.target ); 7853 7854 if ( $.datepicker._get( inst, "constrainInput" ) ) { 7855 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) ); 7856 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode ); 7857 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 ); 7858 } 7859 }, 7860 7861 /* Synchronise manual entry and field/alternate field. */ 7862 _doKeyUp: function( event ) { 7863 var date, 7864 inst = $.datepicker._getInst( event.target ); 7865 7866 if ( inst.input.val() !== inst.lastVal ) { 7867 try { 7868 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 7869 ( inst.input ? inst.input.val() : null ), 7870 $.datepicker._getFormatConfig( inst ) ); 7871 7872 if ( date ) { // only if valid 7873 $.datepicker._setDateFromField( inst ); 7874 $.datepicker._updateAlternate( inst ); 7875 $.datepicker._updateDatepicker( inst ); 7876 } 7877 } 7878 catch ( err ) { 7879 } 7880 } 7881 return true; 7882 }, 7883 7884 /* Pop-up the date picker for a given input field. 7885 * If false returned from beforeShow event handler do not show. 7886 * @param input element - the input field attached to the date picker or 7887 * event - if triggered by focus 7888 */ 7889 _showDatepicker: function( input ) { 7890 input = input.target || input; 7891 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger 7892 input = $( "input", input.parentNode )[ 0 ]; 7893 } 7894 7895 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here 7896 return; 7897 } 7898 7899 var inst, beforeShow, beforeShowSettings, isFixed, 7900 offset, showAnim, duration; 7901 7902 inst = $.datepicker._getInst( input ); 7903 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) { 7904 $.datepicker._curInst.dpDiv.stop( true, true ); 7905 if ( inst && $.datepicker._datepickerShowing ) { 7906 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] ); 7907 } 7908 } 7909 7910 beforeShow = $.datepicker._get( inst, "beforeShow" ); 7911 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 7912 if ( beforeShowSettings === false ) { 7913 return; 7914 } 7915 datepicker_extendRemove( inst.settings, beforeShowSettings ); 7916 7917 inst.lastVal = null; 7918 $.datepicker._lastInput = input; 7919 $.datepicker._setDateFromField( inst ); 7920 7921 if ( $.datepicker._inDialog ) { // hide cursor 7922 input.value = ""; 7923 } 7924 if ( !$.datepicker._pos ) { // position below input 7925 $.datepicker._pos = $.datepicker._findPos( input ); 7926 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height 7927 } 7928 7929 isFixed = false; 7930 $( input ).parents().each( function() { 7931 isFixed |= $( this ).css( "position" ) === "fixed"; 7932 return !isFixed; 7933 } ); 7934 7935 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] }; 7936 $.datepicker._pos = null; 7937 7938 //to avoid flashes on Firefox 7939 inst.dpDiv.empty(); 7940 7941 // determine sizing offscreen 7942 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } ); 7943 $.datepicker._updateDatepicker( inst ); 7944 7945 // fix width for dynamic number of date pickers 7946 // and adjust position before showing 7947 offset = $.datepicker._checkOffset( inst, offset, isFixed ); 7948 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ? 7949 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none", 7950 left: offset.left + "px", top: offset.top + "px" } ); 7951 7952 if ( !inst.inline ) { 7953 showAnim = $.datepicker._get( inst, "showAnim" ); 7954 duration = $.datepicker._get( inst, "duration" ); 7955 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 7956 $.datepicker._datepickerShowing = true; 7957 7958 if ( $.effects && $.effects.effect[ showAnim ] ) { 7959 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration ); 7960 } else { 7961 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null ); 7962 } 7963 7964 if ( $.datepicker._shouldFocusInput( inst ) ) { 7965 inst.input.trigger( "focus" ); 7966 } 7967 7968 $.datepicker._curInst = inst; 7969 } 7970 }, 7971 7972 /* Generate the date picker content. */ 7973 _updateDatepicker: function( inst ) { 7974 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 7975 datepicker_instActive = inst; // for delegate hover events 7976 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 7977 this._attachHandlers( inst ); 7978 7979 var origyearshtml, 7980 numMonths = this._getNumberOfMonths( inst ), 7981 cols = numMonths[ 1 ], 7982 width = 17, 7983 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); 7984 7985 if ( activeCell.length > 0 ) { 7986 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 7987 } 7988 7989 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" ); 7990 if ( cols > 1 ) { 7991 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" ); 7992 } 7993 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) + 7994 "Class" ]( "ui-datepicker-multi" ); 7995 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) + 7996 "Class" ]( "ui-datepicker-rtl" ); 7997 7998 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 7999 inst.input.trigger( "focus" ); 8000 } 8001 8002 // Deffered render of the years select (to avoid flashes on Firefox) 8003 if ( inst.yearshtml ) { 8004 origyearshtml = inst.yearshtml; 8005 setTimeout( function() { 8006 8007 //assure that inst.yearshtml didn't change. 8008 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) { 8009 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml ); 8010 } 8011 origyearshtml = inst.yearshtml = null; 8012 }, 0 ); 8013 } 8014 }, 8015 8016 // #6694 - don't focus the input if it's already focused 8017 // this breaks the change event in IE 8018 // Support: IE and jQuery <1.9 8019 _shouldFocusInput: function( inst ) { 8020 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); 8021 }, 8022 8023 /* Check positioning to remain on screen. */ 8024 _checkOffset: function( inst, offset, isFixed ) { 8025 var dpWidth = inst.dpDiv.outerWidth(), 8026 dpHeight = inst.dpDiv.outerHeight(), 8027 inputWidth = inst.input ? inst.input.outerWidth() : 0, 8028 inputHeight = inst.input ? inst.input.outerHeight() : 0, 8029 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 8030 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 8031 8032 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 ); 8033 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0; 8034 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0; 8035 8036 // Now check if datepicker is showing outside window viewport - move to a better place if so. 8037 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ? 8038 Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 8039 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ? 8040 Math.abs( dpHeight + inputHeight ) : 0 ); 8041 8042 return offset; 8043 }, 8044 8045 /* Find an object's position on the screen. */ 8046 _findPos: function( obj ) { 8047 var position, 8048 inst = this._getInst( obj ), 8049 isRTL = this._get( inst, "isRTL" ); 8050 8051 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) { 8052 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ]; 8053 } 8054 8055 position = $( obj ).offset(); 8056 return [ position.left, position.top ]; 8057 }, 8058 8059 /* Hide the date picker from view. 8060 * @param input element - the input field attached to the date picker 8061 */ 8062 _hideDatepicker: function( input ) { 8063 var showAnim, duration, postProcess, onClose, 8064 inst = this._curInst; 8065 8066 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) { 8067 return; 8068 } 8069 8070 if ( this._datepickerShowing ) { 8071 showAnim = this._get( inst, "showAnim" ); 8072 duration = this._get( inst, "duration" ); 8073 postProcess = function() { 8074 $.datepicker._tidyDialog( inst ); 8075 }; 8076 8077 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 8078 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 8079 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess ); 8080 } else { 8081 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" : 8082 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess ); 8083 } 8084 8085 if ( !showAnim ) { 8086 postProcess(); 8087 } 8088 this._datepickerShowing = false; 8089 8090 onClose = this._get( inst, "onClose" ); 8091 if ( onClose ) { 8092 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] ); 8093 } 8094 8095 this._lastInput = null; 8096 if ( this._inDialog ) { 8097 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } ); 8098 if ( $.blockUI ) { 8099 $.unblockUI(); 8100 $( "body" ).append( this.dpDiv ); 8101 } 8102 } 8103 this._inDialog = false; 8104 } 8105 }, 8106 8107 /* Tidy up after a dialog display. */ 8108 _tidyDialog: function( inst ) { 8109 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" ); 8110 }, 8111 8112 /* Close date picker if clicked elsewhere. */ 8113 _checkExternalClick: function( event ) { 8114 if ( !$.datepicker._curInst ) { 8115 return; 8116 } 8117 8118 var $target = $( event.target ), 8119 inst = $.datepicker._getInst( $target[ 0 ] ); 8120 8121 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId && 8122 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 && 8123 !$target.hasClass( $.datepicker.markerClassName ) && 8124 !$target.closest( "." + $.datepicker._triggerClass ).length && 8125 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) || 8126 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) { 8127 $.datepicker._hideDatepicker(); 8128 } 8129 }, 8130 8131 /* Adjust one of the date sub-fields. */ 8132 _adjustDate: function( id, offset, period ) { 8133 var target = $( id ), 8134 inst = this._getInst( target[ 0 ] ); 8135 8136 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 8137 return; 8138 } 8139 this._adjustInstDate( inst, offset + 8140 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning 8141 period ); 8142 this._updateDatepicker( inst ); 8143 }, 8144 8145 /* Action for current link. */ 8146 _gotoToday: function( id ) { 8147 var date, 8148 target = $( id ), 8149 inst = this._getInst( target[ 0 ] ); 8150 8151 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) { 8152 inst.selectedDay = inst.currentDay; 8153 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 8154 inst.drawYear = inst.selectedYear = inst.currentYear; 8155 } else { 8156 date = new Date(); 8157 inst.selectedDay = date.getDate(); 8158 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8159 inst.drawYear = inst.selectedYear = date.getFullYear(); 8160 } 8161 this._notifyChange( inst ); 8162 this._adjustDate( target ); 8163 }, 8164 8165 /* Action for selecting a new month/year. */ 8166 _selectMonthYear: function( id, select, period ) { 8167 var target = $( id ), 8168 inst = this._getInst( target[ 0 ] ); 8169 8170 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] = 8171 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] = 8172 parseInt( select.options[ select.selectedIndex ].value, 10 ); 8173 8174 this._notifyChange( inst ); 8175 this._adjustDate( target ); 8176 }, 8177 8178 /* Action for selecting a day. */ 8179 _selectDay: function( id, month, year, td ) { 8180 var inst, 8181 target = $( id ); 8182 8183 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 8184 return; 8185 } 8186 8187 inst = this._getInst( target[ 0 ] ); 8188 inst.selectedDay = inst.currentDay = $( "a", td ).html(); 8189 inst.selectedMonth = inst.currentMonth = month; 8190 inst.selectedYear = inst.currentYear = year; 8191 this._selectDate( id, this._formatDate( inst, 8192 inst.currentDay, inst.currentMonth, inst.currentYear ) ); 8193 }, 8194 8195 /* Erase the input field and hide the date picker. */ 8196 _clearDate: function( id ) { 8197 var target = $( id ); 8198 this._selectDate( target, "" ); 8199 }, 8200 8201 /* Update the input field with the selected date. */ 8202 _selectDate: function( id, dateStr ) { 8203 var onSelect, 8204 target = $( id ), 8205 inst = this._getInst( target[ 0 ] ); 8206 8207 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) ); 8208 if ( inst.input ) { 8209 inst.input.val( dateStr ); 8210 } 8211 this._updateAlternate( inst ); 8212 8213 onSelect = this._get( inst, "onSelect" ); 8214 if ( onSelect ) { 8215 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback 8216 } else if ( inst.input ) { 8217 inst.input.trigger( "change" ); // fire the change event 8218 } 8219 8220 if ( inst.inline ) { 8221 this._updateDatepicker( inst ); 8222 } else { 8223 this._hideDatepicker(); 8224 this._lastInput = inst.input[ 0 ]; 8225 if ( typeof( inst.input[ 0 ] ) !== "object" ) { 8226 inst.input.trigger( "focus" ); // restore focus 8227 } 8228 this._lastInput = null; 8229 } 8230 }, 8231 8232 /* Update any alternate field to synchronise with the main field. */ 8233 _updateAlternate: function( inst ) { 8234 var altFormat, date, dateStr, 8235 altField = this._get( inst, "altField" ); 8236 8237 if ( altField ) { // update alternate field too 8238 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" ); 8239 date = this._getDate( inst ); 8240 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 8241 $( altField ).val( dateStr ); 8242 } 8243 }, 8244 8245 /* Set as beforeShowDay function to prevent selection of weekends. 8246 * @param date Date - the date to customise 8247 * @return [boolean, string] - is this date selectable?, what is its CSS class? 8248 */ 8249 noWeekends: function( date ) { 8250 var day = date.getDay(); 8251 return [ ( day > 0 && day < 6 ), "" ]; 8252 }, 8253 8254 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 8255 * @param date Date - the date to get the week for 8256 * @return number - the number of the week within the year that contains this date 8257 */ 8258 iso8601Week: function( date ) { 8259 var time, 8260 checkDate = new Date( date.getTime() ); 8261 8262 // Find Thursday of this week starting on Monday 8263 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 8264 8265 time = checkDate.getTime(); 8266 checkDate.setMonth( 0 ); // Compare with Jan 1 8267 checkDate.setDate( 1 ); 8268 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 8269 }, 8270 8271 /* Parse a string value into a date object. 8272 * See formatDate below for the possible formats. 8273 * 8274 * @param format string - the expected format of the date 8275 * @param value string - the date in the above format 8276 * @param settings Object - attributes include: 8277 * shortYearCutoff number - the cutoff year for determining the century (optional) 8278 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8279 * dayNames string[7] - names of the days from Sunday (optional) 8280 * monthNamesShort string[12] - abbreviated names of the months (optional) 8281 * monthNames string[12] - names of the months (optional) 8282 * @return Date - the extracted date value or null if value is blank 8283 */ 8284 parseDate: function( format, value, settings ) { 8285 if ( format == null || value == null ) { 8286 throw "Invalid arguments"; 8287 } 8288 8289 value = ( typeof value === "object" ? value.toString() : value + "" ); 8290 if ( value === "" ) { 8291 return null; 8292 } 8293 8294 var iFormat, dim, extra, 8295 iValue = 0, 8296 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff, 8297 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 8298 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ), 8299 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8300 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8301 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8302 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8303 year = -1, 8304 month = -1, 8305 day = -1, 8306 doy = -1, 8307 literal = false, 8308 date, 8309 8310 // Check whether a format character is doubled 8311 lookAhead = function( match ) { 8312 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8313 if ( matches ) { 8314 iFormat++; 8315 } 8316 return matches; 8317 }, 8318 8319 // Extract a number from the string value 8320 getNumber = function( match ) { 8321 var isDoubled = lookAhead( match ), 8322 size = ( match === "@" ? 14 : ( match === "!" ? 20 : 8323 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ), 8324 minSize = ( match === "y" ? size : 1 ), 8325 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ), 8326 num = value.substring( iValue ).match( digits ); 8327 if ( !num ) { 8328 throw "Missing number at position " + iValue; 8329 } 8330 iValue += num[ 0 ].length; 8331 return parseInt( num[ 0 ], 10 ); 8332 }, 8333 8334 // Extract a name from the string value and convert to an index 8335 getName = function( match, shortNames, longNames ) { 8336 var index = -1, 8337 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 8338 return [ [ k, v ] ]; 8339 } ).sort( function( a, b ) { 8340 return -( a[ 1 ].length - b[ 1 ].length ); 8341 } ); 8342 8343 $.each( names, function( i, pair ) { 8344 var name = pair[ 1 ]; 8345 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) { 8346 index = pair[ 0 ]; 8347 iValue += name.length; 8348 return false; 8349 } 8350 } ); 8351 if ( index !== -1 ) { 8352 return index + 1; 8353 } else { 8354 throw "Unknown name at position " + iValue; 8355 } 8356 }, 8357 8358 // Confirm that a literal character matches the string value 8359 checkLiteral = function() { 8360 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 8361 throw "Unexpected literal at position " + iValue; 8362 } 8363 iValue++; 8364 }; 8365 8366 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8367 if ( literal ) { 8368 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8369 literal = false; 8370 } else { 8371 checkLiteral(); 8372 } 8373 } else { 8374 switch ( format.charAt( iFormat ) ) { 8375 case "d": 8376 day = getNumber( "d" ); 8377 break; 8378 case "D": 8379 getName( "D", dayNamesShort, dayNames ); 8380 break; 8381 case "o": 8382 doy = getNumber( "o" ); 8383 break; 8384 case "m": 8385 month = getNumber( "m" ); 8386 break; 8387 case "M": 8388 month = getName( "M", monthNamesShort, monthNames ); 8389 break; 8390 case "y": 8391 year = getNumber( "y" ); 8392 break; 8393 case "@": 8394 date = new Date( getNumber( "@" ) ); 8395 year = date.getFullYear(); 8396 month = date.getMonth() + 1; 8397 day = date.getDate(); 8398 break; 8399 case "!": 8400 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 ); 8401 year = date.getFullYear(); 8402 month = date.getMonth() + 1; 8403 day = date.getDate(); 8404 break; 8405 case "'": 8406 if ( lookAhead( "'" ) ) { 8407 checkLiteral(); 8408 } else { 8409 literal = true; 8410 } 8411 break; 8412 default: 8413 checkLiteral(); 8414 } 8415 } 8416 } 8417 8418 if ( iValue < value.length ) { 8419 extra = value.substr( iValue ); 8420 if ( !/^\s+/.test( extra ) ) { 8421 throw "Extra/unparsed characters found in date: " + extra; 8422 } 8423 } 8424 8425 if ( year === -1 ) { 8426 year = new Date().getFullYear(); 8427 } else if ( year < 100 ) { 8428 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 8429 ( year <= shortYearCutoff ? 0 : -100 ); 8430 } 8431 8432 if ( doy > -1 ) { 8433 month = 1; 8434 day = doy; 8435 do { 8436 dim = this._getDaysInMonth( year, month - 1 ); 8437 if ( day <= dim ) { 8438 break; 8439 } 8440 month++; 8441 day -= dim; 8442 } while ( true ); 8443 } 8444 8445 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 8446 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 8447 throw "Invalid date"; // E.g. 31/02/00 8448 } 8449 return date; 8450 }, 8451 8452 /* Standard date formats. */ 8453 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 8454 COOKIE: "D, dd M yy", 8455 ISO_8601: "yy-mm-dd", 8456 RFC_822: "D, d M y", 8457 RFC_850: "DD, dd-M-y", 8458 RFC_1036: "D, d M y", 8459 RFC_1123: "D, d M yy", 8460 RFC_2822: "D, d M yy", 8461 RSS: "D, d M y", // RFC 822 8462 TICKS: "!", 8463 TIMESTAMP: "@", 8464 W3C: "yy-mm-dd", // ISO 8601 8465 8466 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + 8467 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ), 8468 8469 /* Format a date object into a string value. 8470 * The format can be combinations of the following: 8471 * d - day of month (no leading zero) 8472 * dd - day of month (two digit) 8473 * o - day of year (no leading zeros) 8474 * oo - day of year (three digit) 8475 * D - day name short 8476 * DD - day name long 8477 * m - month of year (no leading zero) 8478 * mm - month of year (two digit) 8479 * M - month name short 8480 * MM - month name long 8481 * y - year (two digit) 8482 * yy - year (four digit) 8483 * @ - Unix timestamp (ms since 01/01/1970) 8484 * ! - Windows ticks (100ns since 01/01/0001) 8485 * "..." - literal text 8486 * '' - single quote 8487 * 8488 * @param format string - the desired format of the date 8489 * @param date Date - the date value to format 8490 * @param settings Object - attributes include: 8491 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8492 * dayNames string[7] - names of the days from Sunday (optional) 8493 * monthNamesShort string[12] - abbreviated names of the months (optional) 8494 * monthNames string[12] - names of the months (optional) 8495 * @return string - the date in the above format 8496 */ 8497 formatDate: function( format, date, settings ) { 8498 if ( !date ) { 8499 return ""; 8500 } 8501 8502 var iFormat, 8503 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8504 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8505 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8506 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8507 8508 // Check whether a format character is doubled 8509 lookAhead = function( match ) { 8510 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8511 if ( matches ) { 8512 iFormat++; 8513 } 8514 return matches; 8515 }, 8516 8517 // Format a number, with leading zero if necessary 8518 formatNumber = function( match, value, len ) { 8519 var num = "" + value; 8520 if ( lookAhead( match ) ) { 8521 while ( num.length < len ) { 8522 num = "0" + num; 8523 } 8524 } 8525 return num; 8526 }, 8527 8528 // Format a name, short or long as requested 8529 formatName = function( match, value, shortNames, longNames ) { 8530 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] ); 8531 }, 8532 output = "", 8533 literal = false; 8534 8535 if ( date ) { 8536 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8537 if ( literal ) { 8538 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8539 literal = false; 8540 } else { 8541 output += format.charAt( iFormat ); 8542 } 8543 } else { 8544 switch ( format.charAt( iFormat ) ) { 8545 case "d": 8546 output += formatNumber( "d", date.getDate(), 2 ); 8547 break; 8548 case "D": 8549 output += formatName( "D", date.getDay(), dayNamesShort, dayNames ); 8550 break; 8551 case "o": 8552 output += formatNumber( "o", 8553 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 8554 break; 8555 case "m": 8556 output += formatNumber( "m", date.getMonth() + 1, 2 ); 8557 break; 8558 case "M": 8559 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames ); 8560 break; 8561 case "y": 8562 output += ( lookAhead( "y" ) ? date.getFullYear() : 8563 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 ); 8564 break; 8565 case "@": 8566 output += date.getTime(); 8567 break; 8568 case "!": 8569 output += date.getTime() * 10000 + this._ticksTo1970; 8570 break; 8571 case "'": 8572 if ( lookAhead( "'" ) ) { 8573 output += "'"; 8574 } else { 8575 literal = true; 8576 } 8577 break; 8578 default: 8579 output += format.charAt( iFormat ); 8580 } 8581 } 8582 } 8583 } 8584 return output; 8585 }, 8586 8587 /* Extract all possible characters from the date format. */ 8588 _possibleChars: function( format ) { 8589 var iFormat, 8590 chars = "", 8591 literal = false, 8592 8593 // Check whether a format character is doubled 8594 lookAhead = function( match ) { 8595 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8596 if ( matches ) { 8597 iFormat++; 8598 } 8599 return matches; 8600 }; 8601 8602 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8603 if ( literal ) { 8604 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8605 literal = false; 8606 } else { 8607 chars += format.charAt( iFormat ); 8608 } 8609 } else { 8610 switch ( format.charAt( iFormat ) ) { 8611 case "d": case "m": case "y": case "@": 8612 chars += "0123456789"; 8613 break; 8614 case "D": case "M": 8615 return null; // Accept anything 8616 case "'": 8617 if ( lookAhead( "'" ) ) { 8618 chars += "'"; 8619 } else { 8620 literal = true; 8621 } 8622 break; 8623 default: 8624 chars += format.charAt( iFormat ); 8625 } 8626 } 8627 } 8628 return chars; 8629 }, 8630 8631 /* Get a setting value, defaulting if necessary. */ 8632 _get: function( inst, name ) { 8633 return inst.settings[ name ] !== undefined ? 8634 inst.settings[ name ] : this._defaults[ name ]; 8635 }, 8636 8637 /* Parse existing date and initialise date picker. */ 8638 _setDateFromField: function( inst, noDefault ) { 8639 if ( inst.input.val() === inst.lastVal ) { 8640 return; 8641 } 8642 8643 var dateFormat = this._get( inst, "dateFormat" ), 8644 dates = inst.lastVal = inst.input ? inst.input.val() : null, 8645 defaultDate = this._getDefaultDate( inst ), 8646 date = defaultDate, 8647 settings = this._getFormatConfig( inst ); 8648 8649 try { 8650 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 8651 } catch ( event ) { 8652 dates = ( noDefault ? "" : dates ); 8653 } 8654 inst.selectedDay = date.getDate(); 8655 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8656 inst.drawYear = inst.selectedYear = date.getFullYear(); 8657 inst.currentDay = ( dates ? date.getDate() : 0 ); 8658 inst.currentMonth = ( dates ? date.getMonth() : 0 ); 8659 inst.currentYear = ( dates ? date.getFullYear() : 0 ); 8660 this._adjustInstDate( inst ); 8661 }, 8662 8663 /* Retrieve the default date shown on opening. */ 8664 _getDefaultDate: function( inst ) { 8665 return this._restrictMinMax( inst, 8666 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) ); 8667 }, 8668 8669 /* A date may be specified as an exact value or a relative one. */ 8670 _determineDate: function( inst, date, defaultDate ) { 8671 var offsetNumeric = function( offset ) { 8672 var date = new Date(); 8673 date.setDate( date.getDate() + offset ); 8674 return date; 8675 }, 8676 offsetString = function( offset ) { 8677 try { 8678 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 8679 offset, $.datepicker._getFormatConfig( inst ) ); 8680 } 8681 catch ( e ) { 8682 8683 // Ignore 8684 } 8685 8686 var date = ( offset.toLowerCase().match( /^c/ ) ? 8687 $.datepicker._getDate( inst ) : null ) || new Date(), 8688 year = date.getFullYear(), 8689 month = date.getMonth(), 8690 day = date.getDate(), 8691 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 8692 matches = pattern.exec( offset ); 8693 8694 while ( matches ) { 8695 switch ( matches[ 2 ] || "d" ) { 8696 case "d" : case "D" : 8697 day += parseInt( matches[ 1 ], 10 ); break; 8698 case "w" : case "W" : 8699 day += parseInt( matches[ 1 ], 10 ) * 7; break; 8700 case "m" : case "M" : 8701 month += parseInt( matches[ 1 ], 10 ); 8702 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8703 break; 8704 case "y": case "Y" : 8705 year += parseInt( matches[ 1 ], 10 ); 8706 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8707 break; 8708 } 8709 matches = pattern.exec( offset ); 8710 } 8711 return new Date( year, month, day ); 8712 }, 8713 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) : 8714 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) ); 8715 8716 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate ); 8717 if ( newDate ) { 8718 newDate.setHours( 0 ); 8719 newDate.setMinutes( 0 ); 8720 newDate.setSeconds( 0 ); 8721 newDate.setMilliseconds( 0 ); 8722 } 8723 return this._daylightSavingAdjust( newDate ); 8724 }, 8725 8726 /* Handle switch to/from daylight saving. 8727 * Hours may be non-zero on daylight saving cut-over: 8728 * > 12 when midnight changeover, but then cannot generate 8729 * midnight datetime, so jump to 1AM, otherwise reset. 8730 * @param date (Date) the date to check 8731 * @return (Date) the corrected date 8732 */ 8733 _daylightSavingAdjust: function( date ) { 8734 if ( !date ) { 8735 return null; 8736 } 8737 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 8738 return date; 8739 }, 8740 8741 /* Set the date(s) directly. */ 8742 _setDate: function( inst, date, noChange ) { 8743 var clear = !date, 8744 origMonth = inst.selectedMonth, 8745 origYear = inst.selectedYear, 8746 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 8747 8748 inst.selectedDay = inst.currentDay = newDate.getDate(); 8749 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 8750 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 8751 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) { 8752 this._notifyChange( inst ); 8753 } 8754 this._adjustInstDate( inst ); 8755 if ( inst.input ) { 8756 inst.input.val( clear ? "" : this._formatDate( inst ) ); 8757 } 8758 }, 8759 8760 /* Retrieve the date(s) directly. */ 8761 _getDate: function( inst ) { 8762 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null : 8763 this._daylightSavingAdjust( new Date( 8764 inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 8765 return startDate; 8766 }, 8767 8768 /* Attach the onxxx handlers. These are declared statically so 8769 * they work with static code transformers like Caja. 8770 */ 8771 _attachHandlers: function( inst ) { 8772 var stepMonths = this._get( inst, "stepMonths" ), 8773 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 8774 inst.dpDiv.find( "[data-handler]" ).map( function() { 8775 var handler = { 8776 prev: function() { 8777 $.datepicker._adjustDate( id, -stepMonths, "M" ); 8778 }, 8779 next: function() { 8780 $.datepicker._adjustDate( id, +stepMonths, "M" ); 8781 }, 8782 hide: function() { 8783 $.datepicker._hideDatepicker(); 8784 }, 8785 today: function() { 8786 $.datepicker._gotoToday( id ); 8787 }, 8788 selectDay: function() { 8789 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this ); 8790 return false; 8791 }, 8792 selectMonth: function() { 8793 $.datepicker._selectMonthYear( id, this, "M" ); 8794 return false; 8795 }, 8796 selectYear: function() { 8797 $.datepicker._selectMonthYear( id, this, "Y" ); 8798 return false; 8799 } 8800 }; 8801 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] ); 8802 } ); 8803 }, 8804 8805 /* Generate the HTML for the current state of the date picker. */ 8806 _generateHTML: function( inst ) { 8807 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 8808 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 8809 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 8810 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 8811 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 8812 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 8813 tempDate = new Date(), 8814 today = this._daylightSavingAdjust( 8815 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 8816 isRTL = this._get( inst, "isRTL" ), 8817 showButtonPanel = this._get( inst, "showButtonPanel" ), 8818 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ), 8819 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ), 8820 numMonths = this._getNumberOfMonths( inst ), 8821 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ), 8822 stepMonths = this._get( inst, "stepMonths" ), 8823 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ), 8824 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) : 8825 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ), 8826 minDate = this._getMinMaxDate( inst, "min" ), 8827 maxDate = this._getMinMaxDate( inst, "max" ), 8828 drawMonth = inst.drawMonth - showCurrentAtPos, 8829 drawYear = inst.drawYear; 8830 8831 if ( drawMonth < 0 ) { 8832 drawMonth += 12; 8833 drawYear--; 8834 } 8835 if ( maxDate ) { 8836 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), 8837 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 8838 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw ); 8839 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 8840 drawMonth--; 8841 if ( drawMonth < 0 ) { 8842 drawMonth = 11; 8843 drawYear--; 8844 } 8845 } 8846 } 8847 inst.drawMonth = drawMonth; 8848 inst.drawYear = drawYear; 8849 8850 prevText = this._get( inst, "prevText" ); 8851 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText, 8852 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), 8853 this._getFormatConfig( inst ) ) ); 8854 8855 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ? 8856 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + 8857 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" : 8858 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) ); 8859 8860 nextText = this._get( inst, "nextText" ); 8861 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText, 8862 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), 8863 this._getFormatConfig( inst ) ) ); 8864 8865 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ? 8866 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + 8867 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" : 8868 ( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) ); 8869 8870 currentText = this._get( inst, "currentText" ); 8871 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today ); 8872 currentText = ( !navigationAsDateFormat ? currentText : 8873 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) ); 8874 8875 controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + 8876 this._get( inst, "closeText" ) + "</button>" : "" ); 8877 8878 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) + 8879 ( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + 8880 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : ""; 8881 8882 firstDay = parseInt( this._get( inst, "firstDay" ), 10 ); 8883 firstDay = ( isNaN( firstDay ) ? 0 : firstDay ); 8884 8885 showWeek = this._get( inst, "showWeek" ); 8886 dayNames = this._get( inst, "dayNames" ); 8887 dayNamesMin = this._get( inst, "dayNamesMin" ); 8888 monthNames = this._get( inst, "monthNames" ); 8889 monthNamesShort = this._get( inst, "monthNamesShort" ); 8890 beforeShowDay = this._get( inst, "beforeShowDay" ); 8891 showOtherMonths = this._get( inst, "showOtherMonths" ); 8892 selectOtherMonths = this._get( inst, "selectOtherMonths" ); 8893 defaultDate = this._getDefaultDate( inst ); 8894 html = ""; 8895 8896 for ( row = 0; row < numMonths[ 0 ]; row++ ) { 8897 group = ""; 8898 this.maxRows = 4; 8899 for ( col = 0; col < numMonths[ 1 ]; col++ ) { 8900 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 8901 cornerClass = " ui-corner-all"; 8902 calender = ""; 8903 if ( isMultiMonth ) { 8904 calender += "<div class='ui-datepicker-group"; 8905 if ( numMonths[ 1 ] > 1 ) { 8906 switch ( col ) { 8907 case 0: calender += " ui-datepicker-group-first"; 8908 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break; 8909 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last"; 8910 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break; 8911 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 8912 } 8913 } 8914 calender += "'>"; 8915 } 8916 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 8917 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) + 8918 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) + 8919 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate, 8920 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers 8921 "</div><table class='ui-datepicker-calendar'><thead>" + 8922 "<tr>"; 8923 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" ); 8924 for ( dow = 0; dow < 7; dow++ ) { // days of the week 8925 day = ( dow + firstDay ) % 7; 8926 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" + 8927 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>"; 8928 } 8929 calender += thead + "</tr></thead><tbody>"; 8930 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 8931 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 8932 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 8933 } 8934 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 8935 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate 8936 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043) 8937 this.maxRows = numRows; 8938 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 8939 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows 8940 calender += "<tr>"; 8941 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 8942 this._get( inst, "calculateWeek" )( printDate ) + "</td>" ); 8943 for ( dow = 0; dow < 7; dow++ ) { // create date picker days 8944 daySettings = ( beforeShowDay ? 8945 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] ); 8946 otherMonth = ( printDate.getMonth() !== drawMonth ); 8947 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] || 8948 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 8949 tbody += "<td class='" + 8950 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends 8951 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months 8952 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key 8953 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? 8954 8955 // or defaultDate is current printedDate and defaultDate is selectedDate 8956 " " + this._dayOverClass : "" ) + // highlight selected day 8957 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days 8958 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates 8959 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day 8960 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different) 8961 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title 8962 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions 8963 ( otherMonth && !showOtherMonths ? " " : // display for other months 8964 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 8965 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) + 8966 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day 8967 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months 8968 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date 8969 printDate.setDate( printDate.getDate() + 1 ); 8970 printDate = this._daylightSavingAdjust( printDate ); 8971 } 8972 calender += tbody + "</tr>"; 8973 } 8974 drawMonth++; 8975 if ( drawMonth > 11 ) { 8976 drawMonth = 0; 8977 drawYear++; 8978 } 8979 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" + 8980 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" ); 8981 group += calender; 8982 } 8983 html += group; 8984 } 8985 html += buttonPanel; 8986 inst._keyEvent = false; 8987 return html; 8988 }, 8989 8990 /* Generate the month and year header. */ 8991 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, 8992 secondary, monthNames, monthNamesShort ) { 8993 8994 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 8995 changeMonth = this._get( inst, "changeMonth" ), 8996 changeYear = this._get( inst, "changeYear" ), 8997 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ), 8998 html = "<div class='ui-datepicker-title'>", 8999 monthHtml = ""; 9000 9001 // Month selection 9002 if ( secondary || !changeMonth ) { 9003 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>"; 9004 } else { 9005 inMinYear = ( minDate && minDate.getFullYear() === drawYear ); 9006 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear ); 9007 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; 9008 for ( month = 0; month < 12; month++ ) { 9009 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) { 9010 monthHtml += "<option value='" + month + "'" + 9011 ( month === drawMonth ? " selected='selected'" : "" ) + 9012 ">" + monthNamesShort[ month ] + "</option>"; 9013 } 9014 } 9015 monthHtml += "</select>"; 9016 } 9017 9018 if ( !showMonthAfterYear ) { 9019 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" ); 9020 } 9021 9022 // Year selection 9023 if ( !inst.yearshtml ) { 9024 inst.yearshtml = ""; 9025 if ( secondary || !changeYear ) { 9026 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 9027 } else { 9028 9029 // determine range of years to display 9030 years = this._get( inst, "yearRange" ).split( ":" ); 9031 thisYear = new Date().getFullYear(); 9032 determineYear = function( value ) { 9033 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : 9034 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) : 9035 parseInt( value, 10 ) ) ); 9036 return ( isNaN( year ) ? thisYear : year ); 9037 }; 9038 year = determineYear( years[ 0 ] ); 9039 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) ); 9040 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year ); 9041 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear ); 9042 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; 9043 for ( ; year <= endYear; year++ ) { 9044 inst.yearshtml += "<option value='" + year + "'" + 9045 ( year === drawYear ? " selected='selected'" : "" ) + 9046 ">" + year + "</option>"; 9047 } 9048 inst.yearshtml += "</select>"; 9049 9050 html += inst.yearshtml; 9051 inst.yearshtml = null; 9052 } 9053 } 9054 9055 html += this._get( inst, "yearSuffix" ); 9056 if ( showMonthAfterYear ) { 9057 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml; 9058 } 9059 html += "</div>"; // Close datepicker_header 9060 return html; 9061 }, 9062 9063 /* Adjust one of the date sub-fields. */ 9064 _adjustInstDate: function( inst, offset, period ) { 9065 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ), 9066 month = inst.selectedMonth + ( period === "M" ? offset : 0 ), 9067 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ), 9068 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 9069 9070 inst.selectedDay = date.getDate(); 9071 inst.drawMonth = inst.selectedMonth = date.getMonth(); 9072 inst.drawYear = inst.selectedYear = date.getFullYear(); 9073 if ( period === "M" || period === "Y" ) { 9074 this._notifyChange( inst ); 9075 } 9076 }, 9077 9078 /* Ensure a date is within any min/max bounds. */ 9079 _restrictMinMax: function( inst, date ) { 9080 var minDate = this._getMinMaxDate( inst, "min" ), 9081 maxDate = this._getMinMaxDate( inst, "max" ), 9082 newDate = ( minDate && date < minDate ? minDate : date ); 9083 return ( maxDate && newDate > maxDate ? maxDate : newDate ); 9084 }, 9085 9086 /* Notify change of month/year. */ 9087 _notifyChange: function( inst ) { 9088 var onChange = this._get( inst, "onChangeMonthYear" ); 9089 if ( onChange ) { 9090 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ), 9091 [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 9092 } 9093 }, 9094 9095 /* Determine the number of months to show. */ 9096 _getNumberOfMonths: function( inst ) { 9097 var numMonths = this._get( inst, "numberOfMonths" ); 9098 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) ); 9099 }, 9100 9101 /* Determine the current maximum date - ensure no time components are set. */ 9102 _getMinMaxDate: function( inst, minMax ) { 9103 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null ); 9104 }, 9105 9106 /* Find the number of days in a given month. */ 9107 _getDaysInMonth: function( year, month ) { 9108 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 9109 }, 9110 9111 /* Find the day of the week of the first of a month. */ 9112 _getFirstDayOfMonth: function( year, month ) { 9113 return new Date( year, month, 1 ).getDay(); 9114 }, 9115 9116 /* Determines if we should allow a "next/prev" month display change. */ 9117 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 9118 var numMonths = this._getNumberOfMonths( inst ), 9119 date = this._daylightSavingAdjust( new Date( curYear, 9120 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 9121 9122 if ( offset < 0 ) { 9123 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 9124 } 9125 return this._isInRange( inst, date ); 9126 }, 9127 9128 /* Is the given date in the accepted range? */ 9129 _isInRange: function( inst, date ) { 9130 var yearSplit, currentYear, 9131 minDate = this._getMinMaxDate( inst, "min" ), 9132 maxDate = this._getMinMaxDate( inst, "max" ), 9133 minYear = null, 9134 maxYear = null, 9135 years = this._get( inst, "yearRange" ); 9136 if ( years ) { 9137 yearSplit = years.split( ":" ); 9138 currentYear = new Date().getFullYear(); 9139 minYear = parseInt( yearSplit[ 0 ], 10 ); 9140 maxYear = parseInt( yearSplit[ 1 ], 10 ); 9141 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) { 9142 minYear += currentYear; 9143 } 9144 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) { 9145 maxYear += currentYear; 9146 } 9147 } 9148 9149 return ( ( !minDate || date.getTime() >= minDate.getTime() ) && 9150 ( !maxDate || date.getTime() <= maxDate.getTime() ) && 9151 ( !minYear || date.getFullYear() >= minYear ) && 9152 ( !maxYear || date.getFullYear() <= maxYear ) ); 9153 }, 9154 9155 /* Provide the configuration settings for formatting/parsing. */ 9156 _getFormatConfig: function( inst ) { 9157 var shortYearCutoff = this._get( inst, "shortYearCutoff" ); 9158 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff : 9159 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) ); 9160 return { shortYearCutoff: shortYearCutoff, 9161 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ), 9162 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) }; 9163 }, 9164 9165 /* Format the given date for display. */ 9166 _formatDate: function( inst, day, month, year ) { 9167 if ( !day ) { 9168 inst.currentDay = inst.selectedDay; 9169 inst.currentMonth = inst.selectedMonth; 9170 inst.currentYear = inst.selectedYear; 9171 } 9172 var date = ( day ? ( typeof day === "object" ? day : 9173 this._daylightSavingAdjust( new Date( year, month, day ) ) ) : 9174 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 9175 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) ); 9176 } 9177 } ); 9178 9179 /* 9180 * Bind hover events for datepicker elements. 9181 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 9182 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 9183 */ 9184 function datepicker_bindHover( dpDiv ) { 9185 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 9186 return dpDiv.on( "mouseout", selector, function() { 9187 $( this ).removeClass( "ui-state-hover" ); 9188 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9189 $( this ).removeClass( "ui-datepicker-prev-hover" ); 9190 } 9191 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9192 $( this ).removeClass( "ui-datepicker-next-hover" ); 9193 } 9194 } ) 9195 .on( "mouseover", selector, datepicker_handleMouseover ); 9196 } 9197 9198 function datepicker_handleMouseover() { 9199 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 9200 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" ); 9201 $( this ).addClass( "ui-state-hover" ); 9202 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9203 $( this ).addClass( "ui-datepicker-prev-hover" ); 9204 } 9205 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9206 $( this ).addClass( "ui-datepicker-next-hover" ); 9207 } 9208 } 9209 } 9210 9211 /* jQuery extend now ignores nulls! */ 9212 function datepicker_extendRemove( target, props ) { 9213 $.extend( target, props ); 9214 for ( var name in props ) { 9215 if ( props[ name ] == null ) { 9216 target[ name ] = props[ name ]; 9217 } 9218 } 9219 return target; 9220 } 9221 9222 /* Invoke the datepicker functionality. 9223 @param options string - a command, optionally followed by additional parameters or 9224 Object - settings for attaching new datepicker functionality 9225 @return jQuery object */ 9226 $.fn.datepicker = function( options ) { 9227 9228 /* Verify an empty collection wasn't passed - Fixes #6976 */ 9229 if ( !this.length ) { 9230 return this; 9231 } 9232 9233 /* Initialise the date picker. */ 9234 if ( !$.datepicker.initialized ) { 9235 $( document ).on( "mousedown", $.datepicker._checkExternalClick ); 9236 $.datepicker.initialized = true; 9237 } 9238 9239 /* Append datepicker main container to body if not exist. */ 9240 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) { 9241 $( "body" ).append( $.datepicker.dpDiv ); 9242 } 9243 9244 var otherArgs = Array.prototype.slice.call( arguments, 1 ); 9245 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) { 9246 return $.datepicker[ "_" + options + "Datepicker" ]. 9247 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9248 } 9249 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) { 9250 return $.datepicker[ "_" + options + "Datepicker" ]. 9251 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9252 } 9253 return this.each( function() { 9254 typeof options === "string" ? 9255 $.datepicker[ "_" + options + "Datepicker" ]. 9256 apply( $.datepicker, [ this ].concat( otherArgs ) ) : 9257 $.datepicker._attachDatepicker( this, options ); 9258 } ); 9259 }; 9260 9261 $.datepicker = new Datepicker(); // singleton instance 9262 $.datepicker.initialized = false; 9263 $.datepicker.uuid = new Date().getTime(); 9264 $.datepicker.version = "1.12.1"; 9265 9266 var widgetsDatepicker = $.datepicker; 9267 9268 9269 9270 9271 // This file is deprecated 9272 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); 9273 9274 /*! 9275 * jQuery UI Mouse 1.12.1 9276 * http://jqueryui.com 9277 * 9278 * Copyright jQuery Foundation and other contributors 9279 * Released under the MIT license. 9280 * http://jquery.org/license 9281 */ 9282 9283 //>>label: Mouse 9284 //>>group: Widgets 9285 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets. 9286 //>>docs: http://api.jqueryui.com/mouse/ 9287 9288 9289 9290 var mouseHandled = false; 9291 $( document ).on( "mouseup", function() { 9292 mouseHandled = false; 9293 } ); 9294 9295 var widgetsMouse = $.widget( "ui.mouse", { 9296 version: "1.12.1", 9297 options: { 9298 cancel: "input, textarea, button, select, option", 9299 distance: 1, 9300 delay: 0 9301 }, 9302 _mouseInit: function() { 9303 var that = this; 9304 9305 this.element 9306 .on( "mousedown." + this.widgetName, function( event ) { 9307 return that._mouseDown( event ); 9308 } ) 9309 .on( "click." + this.widgetName, function( event ) { 9310 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { 9311 $.removeData( event.target, that.widgetName + ".preventClickEvent" ); 9312 event.stopImmediatePropagation(); 9313 return false; 9314 } 9315 } ); 9316 9317 this.started = false; 9318 }, 9319 9320 // TODO: make sure destroying one instance of mouse doesn't mess with 9321 // other instances of mouse 9322 _mouseDestroy: function() { 9323 this.element.off( "." + this.widgetName ); 9324 if ( this._mouseMoveDelegate ) { 9325 this.document 9326 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9327 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9328 } 9329 }, 9330 9331 _mouseDown: function( event ) { 9332 9333 // don't let more than one widget handle mouseStart 9334 if ( mouseHandled ) { 9335 return; 9336 } 9337 9338 this._mouseMoved = false; 9339 9340 // We may have missed mouseup (out of window) 9341 ( this._mouseStarted && this._mouseUp( event ) ); 9342 9343 this._mouseDownEvent = event; 9344 9345 var that = this, 9346 btnIsLeft = ( event.which === 1 ), 9347 9348 // event.target.nodeName works around a bug in IE 8 with 9349 // disabled inputs (#7620) 9350 elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ? 9351 $( event.target ).closest( this.options.cancel ).length : false ); 9352 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { 9353 return true; 9354 } 9355 9356 this.mouseDelayMet = !this.options.delay; 9357 if ( !this.mouseDelayMet ) { 9358 this._mouseDelayTimer = setTimeout( function() { 9359 that.mouseDelayMet = true; 9360 }, this.options.delay ); 9361 } 9362 9363 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9364 this._mouseStarted = ( this._mouseStart( event ) !== false ); 9365 if ( !this._mouseStarted ) { 9366 event.preventDefault(); 9367 return true; 9368 } 9369 } 9370 9371 // Click event may never have fired (Gecko & Opera) 9372 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { 9373 $.removeData( event.target, this.widgetName + ".preventClickEvent" ); 9374 } 9375 9376 // These delegates are required to keep context 9377 this._mouseMoveDelegate = function( event ) { 9378 return that._mouseMove( event ); 9379 }; 9380 this._mouseUpDelegate = function( event ) { 9381 return that._mouseUp( event ); 9382 }; 9383 9384 this.document 9385 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9386 .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9387 9388 event.preventDefault(); 9389 9390 mouseHandled = true; 9391 return true; 9392 }, 9393 9394 _mouseMove: function( event ) { 9395 9396 // Only check for mouseups outside the document if you've moved inside the document 9397 // at least once. This prevents the firing of mouseup in the case of IE<9, which will 9398 // fire a mousemove event if content is placed under the cursor. See #7778 9399 // Support: IE <9 9400 if ( this._mouseMoved ) { 9401 9402 // IE mouseup check - mouseup happened when mouse was out of window 9403 if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && 9404 !event.button ) { 9405 return this._mouseUp( event ); 9406 9407 // Iframe mouseup check - mouseup occurred in another document 9408 } else if ( !event.which ) { 9409 9410 // Support: Safari <=8 - 9 9411 // Safari sets which to 0 if you press any of the following keys 9412 // during a drag (#14461) 9413 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || 9414 event.originalEvent.metaKey || event.originalEvent.shiftKey ) { 9415 this.ignoreMissingWhich = true; 9416 } else if ( !this.ignoreMissingWhich ) { 9417 return this._mouseUp( event ); 9418 } 9419 } 9420 } 9421 9422 if ( event.which || event.button ) { 9423 this._mouseMoved = true; 9424 } 9425 9426 if ( this._mouseStarted ) { 9427 this._mouseDrag( event ); 9428 return event.preventDefault(); 9429 } 9430 9431 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9432 this._mouseStarted = 9433 ( this._mouseStart( this._mouseDownEvent, event ) !== false ); 9434 ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) ); 9435 } 9436 9437 return !this._mouseStarted; 9438 }, 9439 9440 _mouseUp: function( event ) { 9441 this.document 9442 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9443 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9444 9445 if ( this._mouseStarted ) { 9446 this._mouseStarted = false; 9447 9448 if ( event.target === this._mouseDownEvent.target ) { 9449 $.data( event.target, this.widgetName + ".preventClickEvent", true ); 9450 } 9451 9452 this._mouseStop( event ); 9453 } 9454 9455 if ( this._mouseDelayTimer ) { 9456 clearTimeout( this._mouseDelayTimer ); 9457 delete this._mouseDelayTimer; 9458 } 9459 9460 this.ignoreMissingWhich = false; 9461 mouseHandled = false; 9462 event.preventDefault(); 9463 }, 9464 9465 _mouseDistanceMet: function( event ) { 9466 return ( Math.max( 9467 Math.abs( this._mouseDownEvent.pageX - event.pageX ), 9468 Math.abs( this._mouseDownEvent.pageY - event.pageY ) 9469 ) >= this.options.distance 9470 ); 9471 }, 9472 9473 _mouseDelayMet: function( /* event */ ) { 9474 return this.mouseDelayMet; 9475 }, 9476 9477 // These are placeholder methods, to be overriden by extending plugin 9478 _mouseStart: function( /* event */ ) {}, 9479 _mouseDrag: function( /* event */ ) {}, 9480 _mouseStop: function( /* event */ ) {}, 9481 _mouseCapture: function( /* event */ ) { return true; } 9482 } ); 9483 9484 9485 9486 9487 // $.ui.plugin is deprecated. Use $.widget() extensions instead. 9488 var plugin = $.ui.plugin = { 9489 add: function( module, option, set ) { 9490 var i, 9491 proto = $.ui[ module ].prototype; 9492 for ( i in set ) { 9493 proto.plugins[ i ] = proto.plugins[ i ] || []; 9494 proto.plugins[ i ].push( [ option, set[ i ] ] ); 9495 } 9496 }, 9497 call: function( instance, name, args, allowDisconnected ) { 9498 var i, 9499 set = instance.plugins[ name ]; 9500 9501 if ( !set ) { 9502 return; 9503 } 9504 9505 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || 9506 instance.element[ 0 ].parentNode.nodeType === 11 ) ) { 9507 return; 9508 } 9509 9510 for ( i = 0; i < set.length; i++ ) { 9511 if ( instance.options[ set[ i ][ 0 ] ] ) { 9512 set[ i ][ 1 ].apply( instance.element, args ); 9513 } 9514 } 9515 } 9516 }; 9517 9518 9519 9520 var safeBlur = $.ui.safeBlur = function( element ) { 9521 9522 // Support: IE9 - 10 only 9523 // If the <body> is blurred, IE will switch windows, see #9420 9524 if ( element && element.nodeName.toLowerCase() !== "body" ) { 9525 $( element ).trigger( "blur" ); 9526 } 9527 }; 9528 9529 9530 /*! 9531 * jQuery UI Draggable 1.12.1 9532 * http://jqueryui.com 9533 * 9534 * Copyright jQuery Foundation and other contributors 9535 * Released under the MIT license. 9536 * http://jquery.org/license 9537 */ 9538 9539 //>>label: Draggable 9540 //>>group: Interactions 9541 //>>description: Enables dragging functionality for any element. 9542 //>>docs: http://api.jqueryui.com/draggable/ 9543 //>>demos: http://jqueryui.com/draggable/ 9544 //>>css.structure: ../../themes/base/draggable.css 9545 9546 9547 9548 $.widget( "ui.draggable", $.ui.mouse, { 9549 version: "1.12.1", 9550 widgetEventPrefix: "drag", 9551 options: { 9552 addClasses: true, 9553 appendTo: "parent", 9554 axis: false, 9555 connectToSortable: false, 9556 containment: false, 9557 cursor: "auto", 9558 cursorAt: false, 9559 grid: false, 9560 handle: false, 9561 helper: "original", 9562 iframeFix: false, 9563 opacity: false, 9564 refreshPositions: false, 9565 revert: false, 9566 revertDuration: 500, 9567 scope: "default", 9568 scroll: true, 9569 scrollSensitivity: 20, 9570 scrollSpeed: 20, 9571 snap: false, 9572 snapMode: "both", 9573 snapTolerance: 20, 9574 stack: false, 9575 zIndex: false, 9576 9577 // Callbacks 9578 drag: null, 9579 start: null, 9580 stop: null 9581 }, 9582 _create: function() { 9583 9584 if ( this.options.helper === "original" ) { 9585 this._setPositionRelative(); 9586 } 9587 if ( this.options.addClasses ) { 9588 this._addClass( "ui-draggable" ); 9589 } 9590 this._setHandleClassName(); 9591 9592 this._mouseInit(); 9593 }, 9594 9595 _setOption: function( key, value ) { 9596 this._super( key, value ); 9597 if ( key === "handle" ) { 9598 this._removeHandleClassName(); 9599 this._setHandleClassName(); 9600 } 9601 }, 9602 9603 _destroy: function() { 9604 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { 9605 this.destroyOnClear = true; 9606 return; 9607 } 9608 this._removeHandleClassName(); 9609 this._mouseDestroy(); 9610 }, 9611 9612 _mouseCapture: function( event ) { 9613 var o = this.options; 9614 9615 // Among others, prevent a drag on a resizable-handle 9616 if ( this.helper || o.disabled || 9617 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) { 9618 return false; 9619 } 9620 9621 //Quit if we're not on a valid handle 9622 this.handle = this._getHandle( event ); 9623 if ( !this.handle ) { 9624 return false; 9625 } 9626 9627 this._blurActiveElement( event ); 9628 9629 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); 9630 9631 return true; 9632 9633 }, 9634 9635 _blockFrames: function( selector ) { 9636 this.iframeBlocks = this.document.find( selector ).map( function() { 9637 var iframe = $( this ); 9638 9639 return $( "<div>" ) 9640 .css( "position", "absolute" ) 9641 .appendTo( iframe.parent() ) 9642 .outerWidth( iframe.outerWidth() ) 9643 .outerHeight( iframe.outerHeight() ) 9644 .offset( iframe.offset() )[ 0 ]; 9645 } ); 9646 }, 9647 9648 _unblockFrames: function() { 9649 if ( this.iframeBlocks ) { 9650 this.iframeBlocks.remove(); 9651 delete this.iframeBlocks; 9652 } 9653 }, 9654 9655 _blurActiveElement: function( event ) { 9656 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ), 9657 target = $( event.target ); 9658 9659 // Don't blur if the event occurred on an element that is within 9660 // the currently focused element 9661 // See #10527, #12472 9662 if ( target.closest( activeElement ).length ) { 9663 return; 9664 } 9665 9666 // Blur any element that currently has focus, see #4261 9667 $.ui.safeBlur( activeElement ); 9668 }, 9669 9670 _mouseStart: function( event ) { 9671 9672 var o = this.options; 9673 9674 //Create and append the visible helper 9675 this.helper = this._createHelper( event ); 9676 9677 this._addClass( this.helper, "ui-draggable-dragging" ); 9678 9679 //Cache the helper size 9680 this._cacheHelperProportions(); 9681 9682 //If ddmanager is used for droppables, set the global draggable 9683 if ( $.ui.ddmanager ) { 9684 $.ui.ddmanager.current = this; 9685 } 9686 9687 /* 9688 * - Position generation - 9689 * This block generates everything position related - it's the core of draggables. 9690 */ 9691 9692 //Cache the margins of the original element 9693 this._cacheMargins(); 9694 9695 //Store the helper's css position 9696 this.cssPosition = this.helper.css( "position" ); 9697 this.scrollParent = this.helper.scrollParent( true ); 9698 this.offsetParent = this.helper.offsetParent(); 9699 this.hasFixedAncestor = this.helper.parents().filter( function() { 9700 return $( this ).css( "position" ) === "fixed"; 9701 } ).length > 0; 9702 9703 //The element's absolute position on the page minus margins 9704 this.positionAbs = this.element.offset(); 9705 this._refreshOffsets( event ); 9706 9707 //Generate the original position 9708 this.originalPosition = this.position = this._generatePosition( event, false ); 9709 this.originalPageX = event.pageX; 9710 this.originalPageY = event.pageY; 9711 9712 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 9713 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) ); 9714 9715 //Set a containment if given in the options 9716 this._setContainment(); 9717 9718 //Trigger event + callbacks 9719 if ( this._trigger( "start", event ) === false ) { 9720 this._clear(); 9721 return false; 9722 } 9723 9724 //Recache the helper size 9725 this._cacheHelperProportions(); 9726 9727 //Prepare the droppable offsets 9728 if ( $.ui.ddmanager && !o.dropBehaviour ) { 9729 $.ui.ddmanager.prepareOffsets( this, event ); 9730 } 9731 9732 // Execute the drag once - this causes the helper not to be visible before getting its 9733 // correct position 9734 this._mouseDrag( event, true ); 9735 9736 // If the ddmanager is used for droppables, inform the manager that dragging has started 9737 // (see #5003) 9738 if ( $.ui.ddmanager ) { 9739 $.ui.ddmanager.dragStart( this, event ); 9740 } 9741 9742 return true; 9743 }, 9744 9745 _refreshOffsets: function( event ) { 9746 this.offset = { 9747 top: this.positionAbs.top - this.margins.top, 9748 left: this.positionAbs.left - this.margins.left, 9749 scroll: false, 9750 parent: this._getParentOffset(), 9751 relative: this._getRelativeOffset() 9752 }; 9753 9754 this.offset.click = { 9755 left: event.pageX - this.offset.left, 9756 top: event.pageY - this.offset.top 9757 }; 9758 }, 9759 9760 _mouseDrag: function( event, noPropagation ) { 9761 9762 // reset any necessary cached properties (see #5009) 9763 if ( this.hasFixedAncestor ) { 9764 this.offset.parent = this._getParentOffset(); 9765 } 9766 9767 //Compute the helpers position 9768 this.position = this._generatePosition( event, true ); 9769 this.positionAbs = this._convertPositionTo( "absolute" ); 9770 9771 //Call plugins and callbacks and use the resulting position if something is returned 9772 if ( !noPropagation ) { 9773 var ui = this._uiHash(); 9774 if ( this._trigger( "drag", event, ui ) === false ) { 9775 this._mouseUp( new $.Event( "mouseup", event ) ); 9776 return false; 9777 } 9778 this.position = ui.position; 9779 } 9780 9781 this.helper[ 0 ].style.left = this.position.left + "px"; 9782 this.helper[ 0 ].style.top = this.position.top + "px"; 9783 9784 if ( $.ui.ddmanager ) { 9785 $.ui.ddmanager.drag( this, event ); 9786 } 9787 9788 return false; 9789 }, 9790 9791 _mouseStop: function( event ) { 9792 9793 //If we are using droppables, inform the manager about the drop 9794 var that = this, 9795 dropped = false; 9796 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 9797 dropped = $.ui.ddmanager.drop( this, event ); 9798 } 9799 9800 //if a drop comes from outside (a sortable) 9801 if ( this.dropped ) { 9802 dropped = this.dropped; 9803 this.dropped = false; 9804 } 9805 9806 if ( ( this.options.revert === "invalid" && !dropped ) || 9807 ( this.options.revert === "valid" && dropped ) || 9808 this.options.revert === true || ( $.isFunction( this.options.revert ) && 9809 this.options.revert.call( this.element, dropped ) ) 9810 ) { 9811 $( this.helper ).animate( 9812 this.originalPosition, 9813 parseInt( this.options.revertDuration, 10 ), 9814 function() { 9815 if ( that._trigger( "stop", event ) !== false ) { 9816 that._clear(); 9817 } 9818 } 9819 ); 9820 } else { 9821 if ( this._trigger( "stop", event ) !== false ) { 9822 this._clear(); 9823 } 9824 } 9825 9826 return false; 9827 }, 9828 9829 _mouseUp: function( event ) { 9830 this._unblockFrames(); 9831 9832 // If the ddmanager is used for droppables, inform the manager that dragging has stopped 9833 // (see #5003) 9834 if ( $.ui.ddmanager ) { 9835 $.ui.ddmanager.dragStop( this, event ); 9836 } 9837 9838 // Only need to focus if the event occurred on the draggable itself, see #10527 9839 if ( this.handleElement.is( event.target ) ) { 9840 9841 // The interaction is over; whether or not the click resulted in a drag, 9842 // focus the element 9843 this.element.trigger( "focus" ); 9844 } 9845 9846 return $.ui.mouse.prototype._mouseUp.call( this, event ); 9847 }, 9848 9849 cancel: function() { 9850 9851 if ( this.helper.is( ".ui-draggable-dragging" ) ) { 9852 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) ); 9853 } else { 9854 this._clear(); 9855 } 9856 9857 return this; 9858 9859 }, 9860 9861 _getHandle: function( event ) { 9862 return this.options.handle ? 9863 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : 9864 true; 9865 }, 9866 9867 _setHandleClassName: function() { 9868 this.handleElement = this.options.handle ? 9869 this.element.find( this.options.handle ) : this.element; 9870 this._addClass( this.handleElement, "ui-draggable-handle" ); 9871 }, 9872 9873 _removeHandleClassName: function() { 9874 this._removeClass( this.handleElement, "ui-draggable-handle" ); 9875 }, 9876 9877 _createHelper: function( event ) { 9878 9879 var o = this.options, 9880 helperIsFunction = $.isFunction( o.helper ), 9881 helper = helperIsFunction ? 9882 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : 9883 ( o.helper === "clone" ? 9884 this.element.clone().removeAttr( "id" ) : 9885 this.element ); 9886 9887 if ( !helper.parents( "body" ).length ) { 9888 helper.appendTo( ( o.appendTo === "parent" ? 9889 this.element[ 0 ].parentNode : 9890 o.appendTo ) ); 9891 } 9892 9893 // Http://bugs.jqueryui.com/ticket/9446 9894 // a helper function can return the original element 9895 // which wouldn't have been set to relative in _create 9896 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { 9897 this._setPositionRelative(); 9898 } 9899 9900 if ( helper[ 0 ] !== this.element[ 0 ] && 9901 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) { 9902 helper.css( "position", "absolute" ); 9903 } 9904 9905 return helper; 9906 9907 }, 9908 9909 _setPositionRelative: function() { 9910 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { 9911 this.element[ 0 ].style.position = "relative"; 9912 } 9913 }, 9914 9915 _adjustOffsetFromHelper: function( obj ) { 9916 if ( typeof obj === "string" ) { 9917 obj = obj.split( " " ); 9918 } 9919 if ( $.isArray( obj ) ) { 9920 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 9921 } 9922 if ( "left" in obj ) { 9923 this.offset.click.left = obj.left + this.margins.left; 9924 } 9925 if ( "right" in obj ) { 9926 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 9927 } 9928 if ( "top" in obj ) { 9929 this.offset.click.top = obj.top + this.margins.top; 9930 } 9931 if ( "bottom" in obj ) { 9932 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 9933 } 9934 }, 9935 9936 _isRootNode: function( element ) { 9937 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; 9938 }, 9939 9940 _getParentOffset: function() { 9941 9942 //Get the offsetParent and cache its position 9943 var po = this.offsetParent.offset(), 9944 document = this.document[ 0 ]; 9945 9946 // This is a special case where we need to modify a offset calculated on start, since the 9947 // following happened: 9948 // 1. The position of the helper is absolute, so it's position is calculated based on the 9949 // next positioned parent 9950 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 9951 // the document, which means that the scroll is included in the initial calculation of the 9952 // offset of the parent, and never recalculated upon drag 9953 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document && 9954 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 9955 po.left += this.scrollParent.scrollLeft(); 9956 po.top += this.scrollParent.scrollTop(); 9957 } 9958 9959 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { 9960 po = { top: 0, left: 0 }; 9961 } 9962 9963 return { 9964 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 9965 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 9966 }; 9967 9968 }, 9969 9970 _getRelativeOffset: function() { 9971 if ( this.cssPosition !== "relative" ) { 9972 return { top: 0, left: 0 }; 9973 } 9974 9975 var p = this.element.position(), 9976 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 9977 9978 return { 9979 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 9980 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), 9981 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 9982 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) 9983 }; 9984 9985 }, 9986 9987 _cacheMargins: function() { 9988 this.margins = { 9989 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ), 9990 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ), 9991 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ), 9992 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 ) 9993 }; 9994 }, 9995 9996 _cacheHelperProportions: function() { 9997 this.helperProportions = { 9998 width: this.helper.outerWidth(), 9999 height: this.helper.outerHeight() 10000 }; 10001 }, 10002 10003 _setContainment: function() { 10004 10005 var isUserScrollable, c, ce, 10006 o = this.options, 10007 document = this.document[ 0 ]; 10008 10009 this.relativeContainer = null; 10010 10011 if ( !o.containment ) { 10012 this.containment = null; 10013 return; 10014 } 10015 10016 if ( o.containment === "window" ) { 10017 this.containment = [ 10018 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 10019 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, 10020 $( window ).scrollLeft() + $( window ).width() - 10021 this.helperProportions.width - this.margins.left, 10022 $( window ).scrollTop() + 10023 ( $( window ).height() || document.body.parentNode.scrollHeight ) - 10024 this.helperProportions.height - this.margins.top 10025 ]; 10026 return; 10027 } 10028 10029 if ( o.containment === "document" ) { 10030 this.containment = [ 10031 0, 10032 0, 10033 $( document ).width() - this.helperProportions.width - this.margins.left, 10034 ( $( document ).height() || document.body.parentNode.scrollHeight ) - 10035 this.helperProportions.height - this.margins.top 10036 ]; 10037 return; 10038 } 10039 10040 if ( o.containment.constructor === Array ) { 10041 this.containment = o.containment; 10042 return; 10043 } 10044 10045 if ( o.containment === "parent" ) { 10046 o.containment = this.helper[ 0 ].parentNode; 10047 } 10048 10049 c = $( o.containment ); 10050 ce = c[ 0 ]; 10051 10052 if ( !ce ) { 10053 return; 10054 } 10055 10056 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); 10057 10058 this.containment = [ 10059 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + 10060 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), 10061 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + 10062 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), 10063 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 10064 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - 10065 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - 10066 this.helperProportions.width - 10067 this.margins.left - 10068 this.margins.right, 10069 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 10070 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - 10071 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - 10072 this.helperProportions.height - 10073 this.margins.top - 10074 this.margins.bottom 10075 ]; 10076 this.relativeContainer = c; 10077 }, 10078 10079 _convertPositionTo: function( d, pos ) { 10080 10081 if ( !pos ) { 10082 pos = this.position; 10083 } 10084 10085 var mod = d === "absolute" ? 1 : -1, 10086 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 10087 10088 return { 10089 top: ( 10090 10091 // The absolute mouse position 10092 pos.top + 10093 10094 // Only for relative positioned nodes: Relative offset from element to offset parent 10095 this.offset.relative.top * mod + 10096 10097 // The offsetParent's offset without borders (offset + border) 10098 this.offset.parent.top * mod - 10099 ( ( this.cssPosition === "fixed" ? 10100 -this.offset.scroll.top : 10101 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod ) 10102 ), 10103 left: ( 10104 10105 // The absolute mouse position 10106 pos.left + 10107 10108 // Only for relative positioned nodes: Relative offset from element to offset parent 10109 this.offset.relative.left * mod + 10110 10111 // The offsetParent's offset without borders (offset + border) 10112 this.offset.parent.left * mod - 10113 ( ( this.cssPosition === "fixed" ? 10114 -this.offset.scroll.left : 10115 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod ) 10116 ) 10117 }; 10118 10119 }, 10120 10121 _generatePosition: function( event, constrainPosition ) { 10122 10123 var containment, co, top, left, 10124 o = this.options, 10125 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), 10126 pageX = event.pageX, 10127 pageY = event.pageY; 10128 10129 // Cache the scroll 10130 if ( !scrollIsRootNode || !this.offset.scroll ) { 10131 this.offset.scroll = { 10132 top: this.scrollParent.scrollTop(), 10133 left: this.scrollParent.scrollLeft() 10134 }; 10135 } 10136 10137 /* 10138 * - Position constraining - 10139 * Constrain the position to a mix of grid, containment. 10140 */ 10141 10142 // If we are not dragging yet, we won't check for options 10143 if ( constrainPosition ) { 10144 if ( this.containment ) { 10145 if ( this.relativeContainer ) { 10146 co = this.relativeContainer.offset(); 10147 containment = [ 10148 this.containment[ 0 ] + co.left, 10149 this.containment[ 1 ] + co.top, 10150 this.containment[ 2 ] + co.left, 10151 this.containment[ 3 ] + co.top 10152 ]; 10153 } else { 10154 containment = this.containment; 10155 } 10156 10157 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) { 10158 pageX = containment[ 0 ] + this.offset.click.left; 10159 } 10160 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) { 10161 pageY = containment[ 1 ] + this.offset.click.top; 10162 } 10163 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) { 10164 pageX = containment[ 2 ] + this.offset.click.left; 10165 } 10166 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) { 10167 pageY = containment[ 3 ] + this.offset.click.top; 10168 } 10169 } 10170 10171 if ( o.grid ) { 10172 10173 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid 10174 // argument errors in IE (see ticket #6950) 10175 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY - 10176 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY; 10177 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] || 10178 top - this.offset.click.top > containment[ 3 ] ) ? 10179 top : 10180 ( ( top - this.offset.click.top >= containment[ 1 ] ) ? 10181 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top; 10182 10183 left = o.grid[ 0 ] ? this.originalPageX + 10184 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] : 10185 this.originalPageX; 10186 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] || 10187 left - this.offset.click.left > containment[ 2 ] ) ? 10188 left : 10189 ( ( left - this.offset.click.left >= containment[ 0 ] ) ? 10190 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left; 10191 } 10192 10193 if ( o.axis === "y" ) { 10194 pageX = this.originalPageX; 10195 } 10196 10197 if ( o.axis === "x" ) { 10198 pageY = this.originalPageY; 10199 } 10200 } 10201 10202 return { 10203 top: ( 10204 10205 // The absolute mouse position 10206 pageY - 10207 10208 // Click offset (relative to the element) 10209 this.offset.click.top - 10210 10211 // Only for relative positioned nodes: Relative offset from element to offset parent 10212 this.offset.relative.top - 10213 10214 // The offsetParent's offset without borders (offset + border) 10215 this.offset.parent.top + 10216 ( this.cssPosition === "fixed" ? 10217 -this.offset.scroll.top : 10218 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) 10219 ), 10220 left: ( 10221 10222 // The absolute mouse position 10223 pageX - 10224 10225 // Click offset (relative to the element) 10226 this.offset.click.left - 10227 10228 // Only for relative positioned nodes: Relative offset from element to offset parent 10229 this.offset.relative.left - 10230 10231 // The offsetParent's offset without borders (offset + border) 10232 this.offset.parent.left + 10233 ( this.cssPosition === "fixed" ? 10234 -this.offset.scroll.left : 10235 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) 10236 ) 10237 }; 10238 10239 }, 10240 10241 _clear: function() { 10242 this._removeClass( this.helper, "ui-draggable-dragging" ); 10243 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) { 10244 this.helper.remove(); 10245 } 10246 this.helper = null; 10247 this.cancelHelperRemoval = false; 10248 if ( this.destroyOnClear ) { 10249 this.destroy(); 10250 } 10251 }, 10252 10253 // From now on bulk stuff - mainly helpers 10254 10255 _trigger: function( type, event, ui ) { 10256 ui = ui || this._uiHash(); 10257 $.ui.plugin.call( this, type, [ event, ui, this ], true ); 10258 10259 // Absolute position and offset (see #6884 ) have to be recalculated after plugins 10260 if ( /^(drag|start|stop)/.test( type ) ) { 10261 this.positionAbs = this._convertPositionTo( "absolute" ); 10262 ui.offset = this.positionAbs; 10263 } 10264 return $.Widget.prototype._trigger.call( this, type, event, ui ); 10265 }, 10266 10267 plugins: {}, 10268 10269 _uiHash: function() { 10270 return { 10271 helper: this.helper, 10272 position: this.position, 10273 originalPosition: this.originalPosition, 10274 offset: this.positionAbs 10275 }; 10276 } 10277 10278 } ); 10279 10280 $.ui.plugin.add( "draggable", "connectToSortable", { 10281 start: function( event, ui, draggable ) { 10282 var uiSortable = $.extend( {}, ui, { 10283 item: draggable.element 10284 } ); 10285 10286 draggable.sortables = []; 10287 $( draggable.options.connectToSortable ).each( function() { 10288 var sortable = $( this ).sortable( "instance" ); 10289 10290 if ( sortable && !sortable.options.disabled ) { 10291 draggable.sortables.push( sortable ); 10292 10293 // RefreshPositions is called at drag start to refresh the containerCache 10294 // which is used in drag. This ensures it's initialized and synchronized 10295 // with any changes that might have happened on the page since initialization. 10296 sortable.refreshPositions(); 10297 sortable._trigger( "activate", event, uiSortable ); 10298 } 10299 } ); 10300 }, 10301 stop: function( event, ui, draggable ) { 10302 var uiSortable = $.extend( {}, ui, { 10303 item: draggable.element 10304 } ); 10305 10306 draggable.cancelHelperRemoval = false; 10307 10308 $.each( draggable.sortables, function() { 10309 var sortable = this; 10310 10311 if ( sortable.isOver ) { 10312 sortable.isOver = 0; 10313 10314 // Allow this sortable to handle removing the helper 10315 draggable.cancelHelperRemoval = true; 10316 sortable.cancelHelperRemoval = false; 10317 10318 // Use _storedCSS To restore properties in the sortable, 10319 // as this also handles revert (#9675) since the draggable 10320 // may have modified them in unexpected ways (#8809) 10321 sortable._storedCSS = { 10322 position: sortable.placeholder.css( "position" ), 10323 top: sortable.placeholder.css( "top" ), 10324 left: sortable.placeholder.css( "left" ) 10325 }; 10326 10327 sortable._mouseStop( event ); 10328 10329 // Once drag has ended, the sortable should return to using 10330 // its original helper, not the shared helper from draggable 10331 sortable.options.helper = sortable.options._helper; 10332 } else { 10333 10334 // Prevent this Sortable from removing the helper. 10335 // However, don't set the draggable to remove the helper 10336 // either as another connected Sortable may yet handle the removal. 10337 sortable.cancelHelperRemoval = true; 10338 10339 sortable._trigger( "deactivate", event, uiSortable ); 10340 } 10341 } ); 10342 }, 10343 drag: function( event, ui, draggable ) { 10344 $.each( draggable.sortables, function() { 10345 var innermostIntersecting = false, 10346 sortable = this; 10347 10348 // Copy over variables that sortable's _intersectsWith uses 10349 sortable.positionAbs = draggable.positionAbs; 10350 sortable.helperProportions = draggable.helperProportions; 10351 sortable.offset.click = draggable.offset.click; 10352 10353 if ( sortable._intersectsWith( sortable.containerCache ) ) { 10354 innermostIntersecting = true; 10355 10356 $.each( draggable.sortables, function() { 10357 10358 // Copy over variables that sortable's _intersectsWith uses 10359 this.positionAbs = draggable.positionAbs; 10360 this.helperProportions = draggable.helperProportions; 10361 this.offset.click = draggable.offset.click; 10362 10363 if ( this !== sortable && 10364 this._intersectsWith( this.containerCache ) && 10365 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { 10366 innermostIntersecting = false; 10367 } 10368 10369 return innermostIntersecting; 10370 } ); 10371 } 10372 10373 if ( innermostIntersecting ) { 10374 10375 // If it intersects, we use a little isOver variable and set it once, 10376 // so that the move-in stuff gets fired only once. 10377 if ( !sortable.isOver ) { 10378 sortable.isOver = 1; 10379 10380 // Store draggable's parent in case we need to reappend to it later. 10381 draggable._parent = ui.helper.parent(); 10382 10383 sortable.currentItem = ui.helper 10384 .appendTo( sortable.element ) 10385 .data( "ui-sortable-item", true ); 10386 10387 // Store helper option to later restore it 10388 sortable.options._helper = sortable.options.helper; 10389 10390 sortable.options.helper = function() { 10391 return ui.helper[ 0 ]; 10392 }; 10393 10394 // Fire the start events of the sortable with our passed browser event, 10395 // and our own helper (so it doesn't create a new one) 10396 event.target = sortable.currentItem[ 0 ]; 10397 sortable._mouseCapture( event, true ); 10398 sortable._mouseStart( event, true, true ); 10399 10400 // Because the browser event is way off the new appended portlet, 10401 // modify necessary variables to reflect the changes 10402 sortable.offset.click.top = draggable.offset.click.top; 10403 sortable.offset.click.left = draggable.offset.click.left; 10404 sortable.offset.parent.left -= draggable.offset.parent.left - 10405 sortable.offset.parent.left; 10406 sortable.offset.parent.top -= draggable.offset.parent.top - 10407 sortable.offset.parent.top; 10408 10409 draggable._trigger( "toSortable", event ); 10410 10411 // Inform draggable that the helper is in a valid drop zone, 10412 // used solely in the revert option to handle "valid/invalid". 10413 draggable.dropped = sortable.element; 10414 10415 // Need to refreshPositions of all sortables in the case that 10416 // adding to one sortable changes the location of the other sortables (#9675) 10417 $.each( draggable.sortables, function() { 10418 this.refreshPositions(); 10419 } ); 10420 10421 // Hack so receive/update callbacks work (mostly) 10422 draggable.currentItem = draggable.element; 10423 sortable.fromOutside = draggable; 10424 } 10425 10426 if ( sortable.currentItem ) { 10427 sortable._mouseDrag( event ); 10428 10429 // Copy the sortable's position because the draggable's can potentially reflect 10430 // a relative position, while sortable is always absolute, which the dragged 10431 // element has now become. (#8809) 10432 ui.position = sortable.position; 10433 } 10434 } else { 10435 10436 // If it doesn't intersect with the sortable, and it intersected before, 10437 // we fake the drag stop of the sortable, but make sure it doesn't remove 10438 // the helper by using cancelHelperRemoval. 10439 if ( sortable.isOver ) { 10440 10441 sortable.isOver = 0; 10442 sortable.cancelHelperRemoval = true; 10443 10444 // Calling sortable's mouseStop would trigger a revert, 10445 // so revert must be temporarily false until after mouseStop is called. 10446 sortable.options._revert = sortable.options.revert; 10447 sortable.options.revert = false; 10448 10449 sortable._trigger( "out", event, sortable._uiHash( sortable ) ); 10450 sortable._mouseStop( event, true ); 10451 10452 // Restore sortable behaviors that were modfied 10453 // when the draggable entered the sortable area (#9481) 10454 sortable.options.revert = sortable.options._revert; 10455 sortable.options.helper = sortable.options._helper; 10456 10457 if ( sortable.placeholder ) { 10458 sortable.placeholder.remove(); 10459 } 10460 10461 // Restore and recalculate the draggable's offset considering the sortable 10462 // may have modified them in unexpected ways. (#8809, #10669) 10463 ui.helper.appendTo( draggable._parent ); 10464 draggable._refreshOffsets( event ); 10465 ui.position = draggable._generatePosition( event, true ); 10466 10467 draggable._trigger( "fromSortable", event ); 10468 10469 // Inform draggable that the helper is no longer in a valid drop zone 10470 draggable.dropped = false; 10471 10472 // Need to refreshPositions of all sortables just in case removing 10473 // from one sortable changes the location of other sortables (#9675) 10474 $.each( draggable.sortables, function() { 10475 this.refreshPositions(); 10476 } ); 10477 } 10478 } 10479 } ); 10480 } 10481 } ); 10482 10483 $.ui.plugin.add( "draggable", "cursor", { 10484 start: function( event, ui, instance ) { 10485 var t = $( "body" ), 10486 o = instance.options; 10487 10488 if ( t.css( "cursor" ) ) { 10489 o._cursor = t.css( "cursor" ); 10490 } 10491 t.css( "cursor", o.cursor ); 10492 }, 10493 stop: function( event, ui, instance ) { 10494 var o = instance.options; 10495 if ( o._cursor ) { 10496 $( "body" ).css( "cursor", o._cursor ); 10497 } 10498 } 10499 } ); 10500 10501 $.ui.plugin.add( "draggable", "opacity", { 10502 start: function( event, ui, instance ) { 10503 var t = $( ui.helper ), 10504 o = instance.options; 10505 if ( t.css( "opacity" ) ) { 10506 o._opacity = t.css( "opacity" ); 10507 } 10508 t.css( "opacity", o.opacity ); 10509 }, 10510 stop: function( event, ui, instance ) { 10511 var o = instance.options; 10512 if ( o._opacity ) { 10513 $( ui.helper ).css( "opacity", o._opacity ); 10514 } 10515 } 10516 } ); 10517 10518 $.ui.plugin.add( "draggable", "scroll", { 10519 start: function( event, ui, i ) { 10520 if ( !i.scrollParentNotHidden ) { 10521 i.scrollParentNotHidden = i.helper.scrollParent( false ); 10522 } 10523 10524 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && 10525 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { 10526 i.overflowOffset = i.scrollParentNotHidden.offset(); 10527 } 10528 }, 10529 drag: function( event, ui, i ) { 10530 10531 var o = i.options, 10532 scrolled = false, 10533 scrollParent = i.scrollParentNotHidden[ 0 ], 10534 document = i.document[ 0 ]; 10535 10536 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { 10537 if ( !o.axis || o.axis !== "x" ) { 10538 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < 10539 o.scrollSensitivity ) { 10540 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; 10541 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { 10542 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; 10543 } 10544 } 10545 10546 if ( !o.axis || o.axis !== "y" ) { 10547 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < 10548 o.scrollSensitivity ) { 10549 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; 10550 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { 10551 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; 10552 } 10553 } 10554 10555 } else { 10556 10557 if ( !o.axis || o.axis !== "x" ) { 10558 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) { 10559 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed ); 10560 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) < 10561 o.scrollSensitivity ) { 10562 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed ); 10563 } 10564 } 10565 10566 if ( !o.axis || o.axis !== "y" ) { 10567 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) { 10568 scrolled = $( document ).scrollLeft( 10569 $( document ).scrollLeft() - o.scrollSpeed 10570 ); 10571 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) < 10572 o.scrollSensitivity ) { 10573 scrolled = $( document ).scrollLeft( 10574 $( document ).scrollLeft() + o.scrollSpeed 10575 ); 10576 } 10577 } 10578 10579 } 10580 10581 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 10582 $.ui.ddmanager.prepareOffsets( i, event ); 10583 } 10584 10585 } 10586 } ); 10587 10588 $.ui.plugin.add( "draggable", "snap", { 10589 start: function( event, ui, i ) { 10590 10591 var o = i.options; 10592 10593 i.snapElements = []; 10594 10595 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap ) 10596 .each( function() { 10597 var $t = $( this ), 10598 $o = $t.offset(); 10599 if ( this !== i.element[ 0 ] ) { 10600 i.snapElements.push( { 10601 item: this, 10602 width: $t.outerWidth(), height: $t.outerHeight(), 10603 top: $o.top, left: $o.left 10604 } ); 10605 } 10606 } ); 10607 10608 }, 10609 drag: function( event, ui, inst ) { 10610 10611 var ts, bs, ls, rs, l, r, t, b, i, first, 10612 o = inst.options, 10613 d = o.snapTolerance, 10614 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 10615 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 10616 10617 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) { 10618 10619 l = inst.snapElements[ i ].left - inst.margins.left; 10620 r = l + inst.snapElements[ i ].width; 10621 t = inst.snapElements[ i ].top - inst.margins.top; 10622 b = t + inst.snapElements[ i ].height; 10623 10624 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || 10625 !$.contains( inst.snapElements[ i ].item.ownerDocument, 10626 inst.snapElements[ i ].item ) ) { 10627 if ( inst.snapElements[ i ].snapping ) { 10628 ( inst.options.snap.release && 10629 inst.options.snap.release.call( 10630 inst.element, 10631 event, 10632 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } ) 10633 ) ); 10634 } 10635 inst.snapElements[ i ].snapping = false; 10636 continue; 10637 } 10638 10639 if ( o.snapMode !== "inner" ) { 10640 ts = Math.abs( t - y2 ) <= d; 10641 bs = Math.abs( b - y1 ) <= d; 10642 ls = Math.abs( l - x2 ) <= d; 10643 rs = Math.abs( r - x1 ) <= d; 10644 if ( ts ) { 10645 ui.position.top = inst._convertPositionTo( "relative", { 10646 top: t - inst.helperProportions.height, 10647 left: 0 10648 } ).top; 10649 } 10650 if ( bs ) { 10651 ui.position.top = inst._convertPositionTo( "relative", { 10652 top: b, 10653 left: 0 10654 } ).top; 10655 } 10656 if ( ls ) { 10657 ui.position.left = inst._convertPositionTo( "relative", { 10658 top: 0, 10659 left: l - inst.helperProportions.width 10660 } ).left; 10661 } 10662 if ( rs ) { 10663 ui.position.left = inst._convertPositionTo( "relative", { 10664 top: 0, 10665 left: r 10666 } ).left; 10667 } 10668 } 10669 10670 first = ( ts || bs || ls || rs ); 10671 10672 if ( o.snapMode !== "outer" ) { 10673 ts = Math.abs( t - y1 ) <= d; 10674 bs = Math.abs( b - y2 ) <= d; 10675 ls = Math.abs( l - x1 ) <= d; 10676 rs = Math.abs( r - x2 ) <= d; 10677 if ( ts ) { 10678 ui.position.top = inst._convertPositionTo( "relative", { 10679 top: t, 10680 left: 0 10681 } ).top; 10682 } 10683 if ( bs ) { 10684 ui.position.top = inst._convertPositionTo( "relative", { 10685 top: b - inst.helperProportions.height, 10686 left: 0 10687 } ).top; 10688 } 10689 if ( ls ) { 10690 ui.position.left = inst._convertPositionTo( "relative", { 10691 top: 0, 10692 left: l 10693 } ).left; 10694 } 10695 if ( rs ) { 10696 ui.position.left = inst._convertPositionTo( "relative", { 10697 top: 0, 10698 left: r - inst.helperProportions.width 10699 } ).left; 10700 } 10701 } 10702 10703 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) { 10704 ( inst.options.snap.snap && 10705 inst.options.snap.snap.call( 10706 inst.element, 10707 event, 10708 $.extend( inst._uiHash(), { 10709 snapItem: inst.snapElements[ i ].item 10710 } ) ) ); 10711 } 10712 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first ); 10713 10714 } 10715 10716 } 10717 } ); 10718 10719 $.ui.plugin.add( "draggable", "stack", { 10720 start: function( event, ui, instance ) { 10721 var min, 10722 o = instance.options, 10723 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) { 10724 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) - 10725 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 ); 10726 } ); 10727 10728 if ( !group.length ) { return; } 10729 10730 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0; 10731 $( group ).each( function( i ) { 10732 $( this ).css( "zIndex", min + i ); 10733 } ); 10734 this.css( "zIndex", ( min + group.length ) ); 10735 } 10736 } ); 10737 10738 $.ui.plugin.add( "draggable", "zIndex", { 10739 start: function( event, ui, instance ) { 10740 var t = $( ui.helper ), 10741 o = instance.options; 10742 10743 if ( t.css( "zIndex" ) ) { 10744 o._zIndex = t.css( "zIndex" ); 10745 } 10746 t.css( "zIndex", o.zIndex ); 10747 }, 10748 stop: function( event, ui, instance ) { 10749 var o = instance.options; 10750 10751 if ( o._zIndex ) { 10752 $( ui.helper ).css( "zIndex", o._zIndex ); 10753 } 10754 } 10755 } ); 10756 10757 var widgetsDraggable = $.ui.draggable; 10758 10759 10760 /*! 10761 * jQuery UI Resizable 1.12.1 10762 * http://jqueryui.com 10763 * 10764 * Copyright jQuery Foundation and other contributors 10765 * Released under the MIT license. 10766 * http://jquery.org/license 10767 */ 10768 10769 //>>label: Resizable 10770 //>>group: Interactions 10771 //>>description: Enables resize functionality for any element. 10772 //>>docs: http://api.jqueryui.com/resizable/ 10773 //>>demos: http://jqueryui.com/resizable/ 10774 //>>css.structure: ../../themes/base/core.css 10775 //>>css.structure: ../../themes/base/resizable.css 10776 //>>css.theme: ../../themes/base/theme.css 10777 10778 10779 10780 $.widget( "ui.resizable", $.ui.mouse, { 10781 version: "1.12.1", 10782 widgetEventPrefix: "resize", 10783 options: { 10784 alsoResize: false, 10785 animate: false, 10786 animateDuration: "slow", 10787 animateEasing: "swing", 10788 aspectRatio: false, 10789 autoHide: false, 10790 classes: { 10791 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se" 10792 }, 10793 containment: false, 10794 ghost: false, 10795 grid: false, 10796 handles: "e,s,se", 10797 helper: false, 10798 maxHeight: null, 10799 maxWidth: null, 10800 minHeight: 10, 10801 minWidth: 10, 10802 10803 // See #7960 10804 zIndex: 90, 10805 10806 // Callbacks 10807 resize: null, 10808 start: null, 10809 stop: null 10810 }, 10811 10812 _num: function( value ) { 10813 return parseFloat( value ) || 0; 10814 }, 10815 10816 _isNumber: function( value ) { 10817 return !isNaN( parseFloat( value ) ); 10818 }, 10819 10820 _hasScroll: function( el, a ) { 10821 10822 if ( $( el ).css( "overflow" ) === "hidden" ) { 10823 return false; 10824 } 10825 10826 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", 10827 has = false; 10828 10829 if ( el[ scroll ] > 0 ) { 10830 return true; 10831 } 10832 10833 // TODO: determine which cases actually cause this to happen 10834 // if the element doesn't have the scroll set, see if it's possible to 10835 // set the scroll 10836 el[ scroll ] = 1; 10837 has = ( el[ scroll ] > 0 ); 10838 el[ scroll ] = 0; 10839 return has; 10840 }, 10841 10842 _create: function() { 10843 10844 var margins, 10845 o = this.options, 10846 that = this; 10847 this._addClass( "ui-resizable" ); 10848 10849 $.extend( this, { 10850 _aspectRatio: !!( o.aspectRatio ), 10851 aspectRatio: o.aspectRatio, 10852 originalElement: this.element, 10853 _proportionallyResizeElements: [], 10854 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null 10855 } ); 10856 10857 // Wrap the element if it cannot hold child nodes 10858 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) { 10859 10860 this.element.wrap( 10861 $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( { 10862 position: this.element.css( "position" ), 10863 width: this.element.outerWidth(), 10864 height: this.element.outerHeight(), 10865 top: this.element.css( "top" ), 10866 left: this.element.css( "left" ) 10867 } ) 10868 ); 10869 10870 this.element = this.element.parent().data( 10871 "ui-resizable", this.element.resizable( "instance" ) 10872 ); 10873 10874 this.elementIsWrapper = true; 10875 10876 margins = { 10877 marginTop: this.originalElement.css( "marginTop" ), 10878 marginRight: this.originalElement.css( "marginRight" ), 10879 marginBottom: this.originalElement.css( "marginBottom" ), 10880 marginLeft: this.originalElement.css( "marginLeft" ) 10881 }; 10882 10883 this.element.css( margins ); 10884 this.originalElement.css( "margin", 0 ); 10885 10886 // support: Safari 10887 // Prevent Safari textarea resize 10888 this.originalResizeStyle = this.originalElement.css( "resize" ); 10889 this.originalElement.css( "resize", "none" ); 10890 10891 this._proportionallyResizeElements.push( this.originalElement.css( { 10892 position: "static", 10893 zoom: 1, 10894 display: "block" 10895 } ) ); 10896 10897 // Support: IE9 10898 // avoid IE jump (hard set the margin) 10899 this.originalElement.css( margins ); 10900 10901 this._proportionallyResize(); 10902 } 10903 10904 this._setupHandles(); 10905 10906 if ( o.autoHide ) { 10907 $( this.element ) 10908 .on( "mouseenter", function() { 10909 if ( o.disabled ) { 10910 return; 10911 } 10912 that._removeClass( "ui-resizable-autohide" ); 10913 that._handles.show(); 10914 } ) 10915 .on( "mouseleave", function() { 10916 if ( o.disabled ) { 10917 return; 10918 } 10919 if ( !that.resizing ) { 10920 that._addClass( "ui-resizable-autohide" ); 10921 that._handles.hide(); 10922 } 10923 } ); 10924 } 10925 10926 this._mouseInit(); 10927 }, 10928 10929 _destroy: function() { 10930 10931 this._mouseDestroy(); 10932 10933 var wrapper, 10934 _destroy = function( exp ) { 10935 $( exp ) 10936 .removeData( "resizable" ) 10937 .removeData( "ui-resizable" ) 10938 .off( ".resizable" ) 10939 .find( ".ui-resizable-handle" ) 10940 .remove(); 10941 }; 10942 10943 // TODO: Unwrap at same DOM position 10944 if ( this.elementIsWrapper ) { 10945 _destroy( this.element ); 10946 wrapper = this.element; 10947 this.originalElement.css( { 10948 position: wrapper.css( "position" ), 10949 width: wrapper.outerWidth(), 10950 height: wrapper.outerHeight(), 10951 top: wrapper.css( "top" ), 10952 left: wrapper.css( "left" ) 10953 } ).insertAfter( wrapper ); 10954 wrapper.remove(); 10955 } 10956 10957 this.originalElement.css( "resize", this.originalResizeStyle ); 10958 _destroy( this.originalElement ); 10959 10960 return this; 10961 }, 10962 10963 _setOption: function( key, value ) { 10964 this._super( key, value ); 10965 10966 switch ( key ) { 10967 case "handles": 10968 this._removeHandles(); 10969 this._setupHandles(); 10970 break; 10971 default: 10972 break; 10973 } 10974 }, 10975 10976 _setupHandles: function() { 10977 var o = this.options, handle, i, n, hname, axis, that = this; 10978 this.handles = o.handles || 10979 ( !$( ".ui-resizable-handle", this.element ).length ? 10980 "e,s,se" : { 10981 n: ".ui-resizable-n", 10982 e: ".ui-resizable-e", 10983 s: ".ui-resizable-s", 10984 w: ".ui-resizable-w", 10985 se: ".ui-resizable-se", 10986 sw: ".ui-resizable-sw", 10987 ne: ".ui-resizable-ne", 10988 nw: ".ui-resizable-nw" 10989 } ); 10990 10991 this._handles = $(); 10992 if ( this.handles.constructor === String ) { 10993 10994 if ( this.handles === "all" ) { 10995 this.handles = "n,e,s,w,se,sw,ne,nw"; 10996 } 10997 10998 n = this.handles.split( "," ); 10999 this.handles = {}; 11000 11001 for ( i = 0; i < n.length; i++ ) { 11002 11003 handle = $.trim( n[ i ] ); 11004 hname = "ui-resizable-" + handle; 11005 axis = $( "<div>" ); 11006 this._addClass( axis, "ui-resizable-handle " + hname ); 11007 11008 axis.css( { zIndex: o.zIndex } ); 11009 11010 this.handles[ handle ] = ".ui-resizable-" + handle; 11011 this.element.append( axis ); 11012 } 11013 11014 } 11015 11016 this._renderAxis = function( target ) { 11017 11018 var i, axis, padPos, padWrapper; 11019 11020 target = target || this.element; 11021 11022 for ( i in this.handles ) { 11023 11024 if ( this.handles[ i ].constructor === String ) { 11025 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show(); 11026 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { 11027 this.handles[ i ] = $( this.handles[ i ] ); 11028 this._on( this.handles[ i ], { "mousedown": that._mouseDown } ); 11029 } 11030 11031 if ( this.elementIsWrapper && 11032 this.originalElement[ 0 ] 11033 .nodeName 11034 .match( /^(textarea|input|select|button)$/i ) ) { 11035 axis = $( this.handles[ i ], this.element ); 11036 11037 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ? 11038 axis.outerHeight() : 11039 axis.outerWidth(); 11040 11041 padPos = [ "padding", 11042 /ne|nw|n/.test( i ) ? "Top" : 11043 /se|sw|s/.test( i ) ? "Bottom" : 11044 /^e$/.test( i ) ? "Right" : "Left" ].join( "" ); 11045 11046 target.css( padPos, padWrapper ); 11047 11048 this._proportionallyResize(); 11049 } 11050 11051 this._handles = this._handles.add( this.handles[ i ] ); 11052 } 11053 }; 11054 11055 // TODO: make renderAxis a prototype function 11056 this._renderAxis( this.element ); 11057 11058 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); 11059 this._handles.disableSelection(); 11060 11061 this._handles.on( "mouseover", function() { 11062 if ( !that.resizing ) { 11063 if ( this.className ) { 11064 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i ); 11065 } 11066 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se"; 11067 } 11068 } ); 11069 11070 if ( o.autoHide ) { 11071 this._handles.hide(); 11072 this._addClass( "ui-resizable-autohide" ); 11073 } 11074 }, 11075 11076 _removeHandles: function() { 11077 this._handles.remove(); 11078 }, 11079 11080 _mouseCapture: function( event ) { 11081 var i, handle, 11082 capture = false; 11083 11084 for ( i in this.handles ) { 11085 handle = $( this.handles[ i ] )[ 0 ]; 11086 if ( handle === event.target || $.contains( handle, event.target ) ) { 11087 capture = true; 11088 } 11089 } 11090 11091 return !this.options.disabled && capture; 11092 }, 11093 11094 _mouseStart: function( event ) { 11095 11096 var curleft, curtop, cursor, 11097 o = this.options, 11098 el = this.element; 11099 11100 this.resizing = true; 11101 11102 this._renderProxy(); 11103 11104 curleft = this._num( this.helper.css( "left" ) ); 11105 curtop = this._num( this.helper.css( "top" ) ); 11106 11107 if ( o.containment ) { 11108 curleft += $( o.containment ).scrollLeft() || 0; 11109 curtop += $( o.containment ).scrollTop() || 0; 11110 } 11111 11112 this.offset = this.helper.offset(); 11113 this.position = { left: curleft, top: curtop }; 11114 11115 this.size = this._helper ? { 11116 width: this.helper.width(), 11117 height: this.helper.height() 11118 } : { 11119 width: el.width(), 11120 height: el.height() 11121 }; 11122 11123 this.originalSize = this._helper ? { 11124 width: el.outerWidth(), 11125 height: el.outerHeight() 11126 } : { 11127 width: el.width(), 11128 height: el.height() 11129 }; 11130 11131 this.sizeDiff = { 11132 width: el.outerWidth() - el.width(), 11133 height: el.outerHeight() - el.height() 11134 }; 11135 11136 this.originalPosition = { left: curleft, top: curtop }; 11137 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 11138 11139 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ? 11140 o.aspectRatio : 11141 ( ( this.originalSize.width / this.originalSize.height ) || 1 ); 11142 11143 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" ); 11144 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor ); 11145 11146 this._addClass( "ui-resizable-resizing" ); 11147 this._propagate( "start", event ); 11148 return true; 11149 }, 11150 11151 _mouseDrag: function( event ) { 11152 11153 var data, props, 11154 smp = this.originalMousePosition, 11155 a = this.axis, 11156 dx = ( event.pageX - smp.left ) || 0, 11157 dy = ( event.pageY - smp.top ) || 0, 11158 trigger = this._change[ a ]; 11159 11160 this._updatePrevProperties(); 11161 11162 if ( !trigger ) { 11163 return false; 11164 } 11165 11166 data = trigger.apply( this, [ event, dx, dy ] ); 11167 11168 this._updateVirtualBoundaries( event.shiftKey ); 11169 if ( this._aspectRatio || event.shiftKey ) { 11170 data = this._updateRatio( data, event ); 11171 } 11172 11173 data = this._respectSize( data, event ); 11174 11175 this._updateCache( data ); 11176 11177 this._propagate( "resize", event ); 11178 11179 props = this._applyChanges(); 11180 11181 if ( !this._helper && this._proportionallyResizeElements.length ) { 11182 this._proportionallyResize(); 11183 } 11184 11185 if ( !$.isEmptyObject( props ) ) { 11186 this._updatePrevProperties(); 11187 this._trigger( "resize", event, this.ui() ); 11188 this._applyChanges(); 11189 } 11190 11191 return false; 11192 }, 11193 11194 _mouseStop: function( event ) { 11195 11196 this.resizing = false; 11197 var pr, ista, soffseth, soffsetw, s, left, top, 11198 o = this.options, that = this; 11199 11200 if ( this._helper ) { 11201 11202 pr = this._proportionallyResizeElements; 11203 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ); 11204 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height; 11205 soffsetw = ista ? 0 : that.sizeDiff.width; 11206 11207 s = { 11208 width: ( that.helper.width() - soffsetw ), 11209 height: ( that.helper.height() - soffseth ) 11210 }; 11211 left = ( parseFloat( that.element.css( "left" ) ) + 11212 ( that.position.left - that.originalPosition.left ) ) || null; 11213 top = ( parseFloat( that.element.css( "top" ) ) + 11214 ( that.position.top - that.originalPosition.top ) ) || null; 11215 11216 if ( !o.animate ) { 11217 this.element.css( $.extend( s, { top: top, left: left } ) ); 11218 } 11219 11220 that.helper.height( that.size.height ); 11221 that.helper.width( that.size.width ); 11222 11223 if ( this._helper && !o.animate ) { 11224 this._proportionallyResize(); 11225 } 11226 } 11227 11228 $( "body" ).css( "cursor", "auto" ); 11229 11230 this._removeClass( "ui-resizable-resizing" ); 11231 11232 this._propagate( "stop", event ); 11233 11234 if ( this._helper ) { 11235 this.helper.remove(); 11236 } 11237 11238 return false; 11239 11240 }, 11241 11242 _updatePrevProperties: function() { 11243 this.prevPosition = { 11244 top: this.position.top, 11245 left: this.position.left 11246 }; 11247 this.prevSize = { 11248 width: this.size.width, 11249 height: this.size.height 11250 }; 11251 }, 11252 11253 _applyChanges: function() { 11254 var props = {}; 11255 11256 if ( this.position.top !== this.prevPosition.top ) { 11257 props.top = this.position.top + "px"; 11258 } 11259 if ( this.position.left !== this.prevPosition.left ) { 11260 props.left = this.position.left + "px"; 11261 } 11262 if ( this.size.width !== this.prevSize.width ) { 11263 props.width = this.size.width + "px"; 11264 } 11265 if ( this.size.height !== this.prevSize.height ) { 11266 props.height = this.size.height + "px"; 11267 } 11268 11269 this.helper.css( props ); 11270 11271 return props; 11272 }, 11273 11274 _updateVirtualBoundaries: function( forceAspectRatio ) { 11275 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, 11276 o = this.options; 11277 11278 b = { 11279 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0, 11280 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity, 11281 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0, 11282 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity 11283 }; 11284 11285 if ( this._aspectRatio || forceAspectRatio ) { 11286 pMinWidth = b.minHeight * this.aspectRatio; 11287 pMinHeight = b.minWidth / this.aspectRatio; 11288 pMaxWidth = b.maxHeight * this.aspectRatio; 11289 pMaxHeight = b.maxWidth / this.aspectRatio; 11290 11291 if ( pMinWidth > b.minWidth ) { 11292 b.minWidth = pMinWidth; 11293 } 11294 if ( pMinHeight > b.minHeight ) { 11295 b.minHeight = pMinHeight; 11296 } 11297 if ( pMaxWidth < b.maxWidth ) { 11298 b.maxWidth = pMaxWidth; 11299 } 11300 if ( pMaxHeight < b.maxHeight ) { 11301 b.maxHeight = pMaxHeight; 11302 } 11303 } 11304 this._vBoundaries = b; 11305 }, 11306 11307 _updateCache: function( data ) { 11308 this.offset = this.helper.offset(); 11309 if ( this._isNumber( data.left ) ) { 11310 this.position.left = data.left; 11311 } 11312 if ( this._isNumber( data.top ) ) { 11313 this.position.top = data.top; 11314 } 11315 if ( this._isNumber( data.height ) ) { 11316 this.size.height = data.height; 11317 } 11318 if ( this._isNumber( data.width ) ) { 11319 this.size.width = data.width; 11320 } 11321 }, 11322 11323 _updateRatio: function( data ) { 11324 11325 var cpos = this.position, 11326 csize = this.size, 11327 a = this.axis; 11328 11329 if ( this._isNumber( data.height ) ) { 11330 data.width = ( data.height * this.aspectRatio ); 11331 } else if ( this._isNumber( data.width ) ) { 11332 data.height = ( data.width / this.aspectRatio ); 11333 } 11334 11335 if ( a === "sw" ) { 11336 data.left = cpos.left + ( csize.width - data.width ); 11337 data.top = null; 11338 } 11339 if ( a === "nw" ) { 11340 data.top = cpos.top + ( csize.height - data.height ); 11341 data.left = cpos.left + ( csize.width - data.width ); 11342 } 11343 11344 return data; 11345 }, 11346 11347 _respectSize: function( data ) { 11348 11349 var o = this._vBoundaries, 11350 a = this.axis, 11351 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ), 11352 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ), 11353 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ), 11354 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ), 11355 dw = this.originalPosition.left + this.originalSize.width, 11356 dh = this.originalPosition.top + this.originalSize.height, 11357 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a ); 11358 if ( isminw ) { 11359 data.width = o.minWidth; 11360 } 11361 if ( isminh ) { 11362 data.height = o.minHeight; 11363 } 11364 if ( ismaxw ) { 11365 data.width = o.maxWidth; 11366 } 11367 if ( ismaxh ) { 11368 data.height = o.maxHeight; 11369 } 11370 11371 if ( isminw && cw ) { 11372 data.left = dw - o.minWidth; 11373 } 11374 if ( ismaxw && cw ) { 11375 data.left = dw - o.maxWidth; 11376 } 11377 if ( isminh && ch ) { 11378 data.top = dh - o.minHeight; 11379 } 11380 if ( ismaxh && ch ) { 11381 data.top = dh - o.maxHeight; 11382 } 11383 11384 // Fixing jump error on top/left - bug #2330 11385 if ( !data.width && !data.height && !data.left && data.top ) { 11386 data.top = null; 11387 } else if ( !data.width && !data.height && !data.top && data.left ) { 11388 data.left = null; 11389 } 11390 11391 return data; 11392 }, 11393 11394 _getPaddingPlusBorderDimensions: function( element ) { 11395 var i = 0, 11396 widths = [], 11397 borders = [ 11398 element.css( "borderTopWidth" ), 11399 element.css( "borderRightWidth" ), 11400 element.css( "borderBottomWidth" ), 11401 element.css( "borderLeftWidth" ) 11402 ], 11403 paddings = [ 11404 element.css( "paddingTop" ), 11405 element.css( "paddingRight" ), 11406 element.css( "paddingBottom" ), 11407 element.css( "paddingLeft" ) 11408 ]; 11409 11410 for ( ; i < 4; i++ ) { 11411 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 ); 11412 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 ); 11413 } 11414 11415 return { 11416 height: widths[ 0 ] + widths[ 2 ], 11417 width: widths[ 1 ] + widths[ 3 ] 11418 }; 11419 }, 11420 11421 _proportionallyResize: function() { 11422 11423 if ( !this._proportionallyResizeElements.length ) { 11424 return; 11425 } 11426 11427 var prel, 11428 i = 0, 11429 element = this.helper || this.element; 11430 11431 for ( ; i < this._proportionallyResizeElements.length; i++ ) { 11432 11433 prel = this._proportionallyResizeElements[ i ]; 11434 11435 // TODO: Seems like a bug to cache this.outerDimensions 11436 // considering that we are in a loop. 11437 if ( !this.outerDimensions ) { 11438 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); 11439 } 11440 11441 prel.css( { 11442 height: ( element.height() - this.outerDimensions.height ) || 0, 11443 width: ( element.width() - this.outerDimensions.width ) || 0 11444 } ); 11445 11446 } 11447 11448 }, 11449 11450 _renderProxy: function() { 11451 11452 var el = this.element, o = this.options; 11453 this.elementOffset = el.offset(); 11454 11455 if ( this._helper ) { 11456 11457 this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" ); 11458 11459 this._addClass( this.helper, this._helper ); 11460 this.helper.css( { 11461 width: this.element.outerWidth(), 11462 height: this.element.outerHeight(), 11463 position: "absolute", 11464 left: this.elementOffset.left + "px", 11465 top: this.elementOffset.top + "px", 11466 zIndex: ++o.zIndex //TODO: Don't modify option 11467 } ); 11468 11469 this.helper 11470 .appendTo( "body" ) 11471 .disableSelection(); 11472 11473 } else { 11474 this.helper = this.element; 11475 } 11476 11477 }, 11478 11479 _change: { 11480 e: function( event, dx ) { 11481 return { width: this.originalSize.width + dx }; 11482 }, 11483 w: function( event, dx ) { 11484 var cs = this.originalSize, sp = this.originalPosition; 11485 return { left: sp.left + dx, width: cs.width - dx }; 11486 }, 11487 n: function( event, dx, dy ) { 11488 var cs = this.originalSize, sp = this.originalPosition; 11489 return { top: sp.top + dy, height: cs.height - dy }; 11490 }, 11491 s: function( event, dx, dy ) { 11492 return { height: this.originalSize.height + dy }; 11493 }, 11494 se: function( event, dx, dy ) { 11495 return $.extend( this._change.s.apply( this, arguments ), 11496 this._change.e.apply( this, [ event, dx, dy ] ) ); 11497 }, 11498 sw: function( event, dx, dy ) { 11499 return $.extend( this._change.s.apply( this, arguments ), 11500 this._change.w.apply( this, [ event, dx, dy ] ) ); 11501 }, 11502 ne: function( event, dx, dy ) { 11503 return $.extend( this._change.n.apply( this, arguments ), 11504 this._change.e.apply( this, [ event, dx, dy ] ) ); 11505 }, 11506 nw: function( event, dx, dy ) { 11507 return $.extend( this._change.n.apply( this, arguments ), 11508 this._change.w.apply( this, [ event, dx, dy ] ) ); 11509 } 11510 }, 11511 11512 _propagate: function( n, event ) { 11513 $.ui.plugin.call( this, n, [ event, this.ui() ] ); 11514 ( n !== "resize" && this._trigger( n, event, this.ui() ) ); 11515 }, 11516 11517 plugins: {}, 11518 11519 ui: function() { 11520 return { 11521 originalElement: this.originalElement, 11522 element: this.element, 11523 helper: this.helper, 11524 position: this.position, 11525 size: this.size, 11526 originalSize: this.originalSize, 11527 originalPosition: this.originalPosition 11528 }; 11529 } 11530 11531 } ); 11532 11533 /* 11534 * Resizable Extensions 11535 */ 11536 11537 $.ui.plugin.add( "resizable", "animate", { 11538 11539 stop: function( event ) { 11540 var that = $( this ).resizable( "instance" ), 11541 o = that.options, 11542 pr = that._proportionallyResizeElements, 11543 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ), 11544 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height, 11545 soffsetw = ista ? 0 : that.sizeDiff.width, 11546 style = { 11547 width: ( that.size.width - soffsetw ), 11548 height: ( that.size.height - soffseth ) 11549 }, 11550 left = ( parseFloat( that.element.css( "left" ) ) + 11551 ( that.position.left - that.originalPosition.left ) ) || null, 11552 top = ( parseFloat( that.element.css( "top" ) ) + 11553 ( that.position.top - that.originalPosition.top ) ) || null; 11554 11555 that.element.animate( 11556 $.extend( style, top && left ? { top: top, left: left } : {} ), { 11557 duration: o.animateDuration, 11558 easing: o.animateEasing, 11559 step: function() { 11560 11561 var data = { 11562 width: parseFloat( that.element.css( "width" ) ), 11563 height: parseFloat( that.element.css( "height" ) ), 11564 top: parseFloat( that.element.css( "top" ) ), 11565 left: parseFloat( that.element.css( "left" ) ) 11566 }; 11567 11568 if ( pr && pr.length ) { 11569 $( pr[ 0 ] ).css( { width: data.width, height: data.height } ); 11570 } 11571 11572 // Propagating resize, and updating values for each animation step 11573 that._updateCache( data ); 11574 that._propagate( "resize", event ); 11575 11576 } 11577 } 11578 ); 11579 } 11580 11581 } ); 11582 11583 $.ui.plugin.add( "resizable", "containment", { 11584 11585 start: function() { 11586 var element, p, co, ch, cw, width, height, 11587 that = $( this ).resizable( "instance" ), 11588 o = that.options, 11589 el = that.element, 11590 oc = o.containment, 11591 ce = ( oc instanceof $ ) ? 11592 oc.get( 0 ) : 11593 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; 11594 11595 if ( !ce ) { 11596 return; 11597 } 11598 11599 that.containerElement = $( ce ); 11600 11601 if ( /document/.test( oc ) || oc === document ) { 11602 that.containerOffset = { 11603 left: 0, 11604 top: 0 11605 }; 11606 that.containerPosition = { 11607 left: 0, 11608 top: 0 11609 }; 11610 11611 that.parentData = { 11612 element: $( document ), 11613 left: 0, 11614 top: 0, 11615 width: $( document ).width(), 11616 height: $( document ).height() || document.body.parentNode.scrollHeight 11617 }; 11618 } else { 11619 element = $( ce ); 11620 p = []; 11621 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) { 11622 p[ i ] = that._num( element.css( "padding" + name ) ); 11623 } ); 11624 11625 that.containerOffset = element.offset(); 11626 that.containerPosition = element.position(); 11627 that.containerSize = { 11628 height: ( element.innerHeight() - p[ 3 ] ), 11629 width: ( element.innerWidth() - p[ 1 ] ) 11630 }; 11631 11632 co = that.containerOffset; 11633 ch = that.containerSize.height; 11634 cw = that.containerSize.width; 11635 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw ); 11636 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ; 11637 11638 that.parentData = { 11639 element: ce, 11640 left: co.left, 11641 top: co.top, 11642 width: width, 11643 height: height 11644 }; 11645 } 11646 }, 11647 11648 resize: function( event ) { 11649 var woset, hoset, isParent, isOffsetRelative, 11650 that = $( this ).resizable( "instance" ), 11651 o = that.options, 11652 co = that.containerOffset, 11653 cp = that.position, 11654 pRatio = that._aspectRatio || event.shiftKey, 11655 cop = { 11656 top: 0, 11657 left: 0 11658 }, 11659 ce = that.containerElement, 11660 continueResize = true; 11661 11662 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { 11663 cop = co; 11664 } 11665 11666 if ( cp.left < ( that._helper ? co.left : 0 ) ) { 11667 that.size.width = that.size.width + 11668 ( that._helper ? 11669 ( that.position.left - co.left ) : 11670 ( that.position.left - cop.left ) ); 11671 11672 if ( pRatio ) { 11673 that.size.height = that.size.width / that.aspectRatio; 11674 continueResize = false; 11675 } 11676 that.position.left = o.helper ? co.left : 0; 11677 } 11678 11679 if ( cp.top < ( that._helper ? co.top : 0 ) ) { 11680 that.size.height = that.size.height + 11681 ( that._helper ? 11682 ( that.position.top - co.top ) : 11683 that.position.top ); 11684 11685 if ( pRatio ) { 11686 that.size.width = that.size.height * that.aspectRatio; 11687 continueResize = false; 11688 } 11689 that.position.top = that._helper ? co.top : 0; 11690 } 11691 11692 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); 11693 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); 11694 11695 if ( isParent && isOffsetRelative ) { 11696 that.offset.left = that.parentData.left + that.position.left; 11697 that.offset.top = that.parentData.top + that.position.top; 11698 } else { 11699 that.offset.left = that.element.offset().left; 11700 that.offset.top = that.element.offset().top; 11701 } 11702 11703 woset = Math.abs( that.sizeDiff.width + 11704 ( that._helper ? 11705 that.offset.left - cop.left : 11706 ( that.offset.left - co.left ) ) ); 11707 11708 hoset = Math.abs( that.sizeDiff.height + 11709 ( that._helper ? 11710 that.offset.top - cop.top : 11711 ( that.offset.top - co.top ) ) ); 11712 11713 if ( woset + that.size.width >= that.parentData.width ) { 11714 that.size.width = that.parentData.width - woset; 11715 if ( pRatio ) { 11716 that.size.height = that.size.width / that.aspectRatio; 11717 continueResize = false; 11718 } 11719 } 11720 11721 if ( hoset + that.size.height >= that.parentData.height ) { 11722 that.size.height = that.parentData.height - hoset; 11723 if ( pRatio ) { 11724 that.size.width = that.size.height * that.aspectRatio; 11725 continueResize = false; 11726 } 11727 } 11728 11729 if ( !continueResize ) { 11730 that.position.left = that.prevPosition.left; 11731 that.position.top = that.prevPosition.top; 11732 that.size.width = that.prevSize.width; 11733 that.size.height = that.prevSize.height; 11734 } 11735 }, 11736 11737 stop: function() { 11738 var that = $( this ).resizable( "instance" ), 11739 o = that.options, 11740 co = that.containerOffset, 11741 cop = that.containerPosition, 11742 ce = that.containerElement, 11743 helper = $( that.helper ), 11744 ho = helper.offset(), 11745 w = helper.outerWidth() - that.sizeDiff.width, 11746 h = helper.outerHeight() - that.sizeDiff.height; 11747 11748 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { 11749 $( this ).css( { 11750 left: ho.left - cop.left - co.left, 11751 width: w, 11752 height: h 11753 } ); 11754 } 11755 11756 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { 11757 $( this ).css( { 11758 left: ho.left - cop.left - co.left, 11759 width: w, 11760 height: h 11761 } ); 11762 } 11763 } 11764 } ); 11765 11766 $.ui.plugin.add( "resizable", "alsoResize", { 11767 11768 start: function() { 11769 var that = $( this ).resizable( "instance" ), 11770 o = that.options; 11771 11772 $( o.alsoResize ).each( function() { 11773 var el = $( this ); 11774 el.data( "ui-resizable-alsoresize", { 11775 width: parseFloat( el.width() ), height: parseFloat( el.height() ), 11776 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) 11777 } ); 11778 } ); 11779 }, 11780 11781 resize: function( event, ui ) { 11782 var that = $( this ).resizable( "instance" ), 11783 o = that.options, 11784 os = that.originalSize, 11785 op = that.originalPosition, 11786 delta = { 11787 height: ( that.size.height - os.height ) || 0, 11788 width: ( that.size.width - os.width ) || 0, 11789 top: ( that.position.top - op.top ) || 0, 11790 left: ( that.position.left - op.left ) || 0 11791 }; 11792 11793 $( o.alsoResize ).each( function() { 11794 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {}, 11795 css = el.parents( ui.originalElement[ 0 ] ).length ? 11796 [ "width", "height" ] : 11797 [ "width", "height", "top", "left" ]; 11798 11799 $.each( css, function( i, prop ) { 11800 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 ); 11801 if ( sum && sum >= 0 ) { 11802 style[ prop ] = sum || null; 11803 } 11804 } ); 11805 11806 el.css( style ); 11807 } ); 11808 }, 11809 11810 stop: function() { 11811 $( this ).removeData( "ui-resizable-alsoresize" ); 11812 } 11813 } ); 11814 11815 $.ui.plugin.add( "resizable", "ghost", { 11816 11817 start: function() { 11818 11819 var that = $( this ).resizable( "instance" ), cs = that.size; 11820 11821 that.ghost = that.originalElement.clone(); 11822 that.ghost.css( { 11823 opacity: 0.25, 11824 display: "block", 11825 position: "relative", 11826 height: cs.height, 11827 width: cs.width, 11828 margin: 0, 11829 left: 0, 11830 top: 0 11831 } ); 11832 11833 that._addClass( that.ghost, "ui-resizable-ghost" ); 11834 11835 // DEPRECATED 11836 // TODO: remove after 1.12 11837 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) { 11838 11839 // Ghost option 11840 that.ghost.addClass( this.options.ghost ); 11841 } 11842 11843 that.ghost.appendTo( that.helper ); 11844 11845 }, 11846 11847 resize: function() { 11848 var that = $( this ).resizable( "instance" ); 11849 if ( that.ghost ) { 11850 that.ghost.css( { 11851 position: "relative", 11852 height: that.size.height, 11853 width: that.size.width 11854 } ); 11855 } 11856 }, 11857 11858 stop: function() { 11859 var that = $( this ).resizable( "instance" ); 11860 if ( that.ghost && that.helper ) { 11861 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) ); 11862 } 11863 } 11864 11865 } ); 11866 11867 $.ui.plugin.add( "resizable", "grid", { 11868 11869 resize: function() { 11870 var outerDimensions, 11871 that = $( this ).resizable( "instance" ), 11872 o = that.options, 11873 cs = that.size, 11874 os = that.originalSize, 11875 op = that.originalPosition, 11876 a = that.axis, 11877 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, 11878 gridX = ( grid[ 0 ] || 1 ), 11879 gridY = ( grid[ 1 ] || 1 ), 11880 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX, 11881 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY, 11882 newWidth = os.width + ox, 11883 newHeight = os.height + oy, 11884 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ), 11885 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ), 11886 isMinWidth = o.minWidth && ( o.minWidth > newWidth ), 11887 isMinHeight = o.minHeight && ( o.minHeight > newHeight ); 11888 11889 o.grid = grid; 11890 11891 if ( isMinWidth ) { 11892 newWidth += gridX; 11893 } 11894 if ( isMinHeight ) { 11895 newHeight += gridY; 11896 } 11897 if ( isMaxWidth ) { 11898 newWidth -= gridX; 11899 } 11900 if ( isMaxHeight ) { 11901 newHeight -= gridY; 11902 } 11903 11904 if ( /^(se|s|e)$/.test( a ) ) { 11905 that.size.width = newWidth; 11906 that.size.height = newHeight; 11907 } else if ( /^(ne)$/.test( a ) ) { 11908 that.size.width = newWidth; 11909 that.size.height = newHeight; 11910 that.position.top = op.top - oy; 11911 } else if ( /^(sw)$/.test( a ) ) { 11912 that.size.width = newWidth; 11913 that.size.height = newHeight; 11914 that.position.left = op.left - ox; 11915 } else { 11916 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) { 11917 outerDimensions = that._getPaddingPlusBorderDimensions( this ); 11918 } 11919 11920 if ( newHeight - gridY > 0 ) { 11921 that.size.height = newHeight; 11922 that.position.top = op.top - oy; 11923 } else { 11924 newHeight = gridY - outerDimensions.height; 11925 that.size.height = newHeight; 11926 that.position.top = op.top + os.height - newHeight; 11927 } 11928 if ( newWidth - gridX > 0 ) { 11929 that.size.width = newWidth; 11930 that.position.left = op.left - ox; 11931 } else { 11932 newWidth = gridX - outerDimensions.width; 11933 that.size.width = newWidth; 11934 that.position.left = op.left + os.width - newWidth; 11935 } 11936 } 11937 } 11938 11939 } ); 11940 11941 var widgetsResizable = $.ui.resizable; 11942 11943 11944 /*! 11945 * jQuery UI Dialog 1.12.1 11946 * http://jqueryui.com 11947 * 11948 * Copyright jQuery Foundation and other contributors 11949 * Released under the MIT license. 11950 * http://jquery.org/license 11951 */ 11952 11953 //>>label: Dialog 11954 //>>group: Widgets 11955 //>>description: Displays customizable dialog windows. 11956 //>>docs: http://api.jqueryui.com/dialog/ 11957 //>>demos: http://jqueryui.com/dialog/ 11958 //>>css.structure: ../../themes/base/core.css 11959 //>>css.structure: ../../themes/base/dialog.css 11960 //>>css.theme: ../../themes/base/theme.css 11961 11962 11963 11964 $.widget( "ui.dialog", { 11965 version: "1.12.1", 11966 options: { 11967 appendTo: "body", 11968 autoOpen: true, 11969 buttons: [], 11970 classes: { 11971 "ui-dialog": "ui-corner-all", 11972 "ui-dialog-titlebar": "ui-corner-all" 11973 }, 11974 closeOnEscape: true, 11975 closeText: "Close", 11976 draggable: true, 11977 hide: null, 11978 height: "auto", 11979 maxHeight: null, 11980 maxWidth: null, 11981 minHeight: 150, 11982 minWidth: 150, 11983 modal: false, 11984 position: { 11985 my: "center", 11986 at: "center", 11987 of: window, 11988 collision: "fit", 11989 11990 // Ensure the titlebar is always visible 11991 using: function( pos ) { 11992 var topOffset = $( this ).css( pos ).offset().top; 11993 if ( topOffset < 0 ) { 11994 $( this ).css( "top", pos.top - topOffset ); 11995 } 11996 } 11997 }, 11998 resizable: true, 11999 show: null, 12000 title: null, 12001 width: 300, 12002 12003 // Callbacks 12004 beforeClose: null, 12005 close: null, 12006 drag: null, 12007 dragStart: null, 12008 dragStop: null, 12009 focus: null, 12010 open: null, 12011 resize: null, 12012 resizeStart: null, 12013 resizeStop: null 12014 }, 12015 12016 sizeRelatedOptions: { 12017 buttons: true, 12018 height: true, 12019 maxHeight: true, 12020 maxWidth: true, 12021 minHeight: true, 12022 minWidth: true, 12023 width: true 12024 }, 12025 12026 resizableRelatedOptions: { 12027 maxHeight: true, 12028 maxWidth: true, 12029 minHeight: true, 12030 minWidth: true 12031 }, 12032 12033 _create: function() { 12034 this.originalCss = { 12035 display: this.element[ 0 ].style.display, 12036 width: this.element[ 0 ].style.width, 12037 minHeight: this.element[ 0 ].style.minHeight, 12038 maxHeight: this.element[ 0 ].style.maxHeight, 12039 height: this.element[ 0 ].style.height 12040 }; 12041 this.originalPosition = { 12042 parent: this.element.parent(), 12043 index: this.element.parent().children().index( this.element ) 12044 }; 12045 this.originalTitle = this.element.attr( "title" ); 12046 if ( this.options.title == null && this.originalTitle != null ) { 12047 this.options.title = this.originalTitle; 12048 } 12049 12050 // Dialogs can't be disabled 12051 if ( this.options.disabled ) { 12052 this.options.disabled = false; 12053 } 12054 12055 this._createWrapper(); 12056 12057 this.element 12058 .show() 12059 .removeAttr( "title" ) 12060 .appendTo( this.uiDialog ); 12061 12062 this._addClass( "ui-dialog-content", "ui-widget-content" ); 12063 12064 this._createTitlebar(); 12065 this._createButtonPane(); 12066 12067 if ( this.options.draggable && $.fn.draggable ) { 12068 this._makeDraggable(); 12069 } 12070 if ( this.options.resizable && $.fn.resizable ) { 12071 this._makeResizable(); 12072 } 12073 12074 this._isOpen = false; 12075 12076 this._trackFocus(); 12077 }, 12078 12079 _init: function() { 12080 if ( this.options.autoOpen ) { 12081 this.open(); 12082 } 12083 }, 12084 12085 _appendTo: function() { 12086 var element = this.options.appendTo; 12087 if ( element && ( element.jquery || element.nodeType ) ) { 12088 return $( element ); 12089 } 12090 return this.document.find( element || "body" ).eq( 0 ); 12091 }, 12092 12093 _destroy: function() { 12094 var next, 12095 originalPosition = this.originalPosition; 12096 12097 this._untrackInstance(); 12098 this._destroyOverlay(); 12099 12100 this.element 12101 .removeUniqueId() 12102 .css( this.originalCss ) 12103 12104 // Without detaching first, the following becomes really slow 12105 .detach(); 12106 12107 this.uiDialog.remove(); 12108 12109 if ( this.originalTitle ) { 12110 this.element.attr( "title", this.originalTitle ); 12111 } 12112 12113 next = originalPosition.parent.children().eq( originalPosition.index ); 12114 12115 // Don't try to place the dialog next to itself (#8613) 12116 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { 12117 next.before( this.element ); 12118 } else { 12119 originalPosition.parent.append( this.element ); 12120 } 12121 }, 12122 12123 widget: function() { 12124 return this.uiDialog; 12125 }, 12126 12127 disable: $.noop, 12128 enable: $.noop, 12129 12130 close: function( event ) { 12131 var that = this; 12132 12133 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { 12134 return; 12135 } 12136 12137 this._isOpen = false; 12138 this._focusedElement = null; 12139 this._destroyOverlay(); 12140 this._untrackInstance(); 12141 12142 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) { 12143 12144 // Hiding a focused element doesn't trigger blur in WebKit 12145 // so in case we have nothing to focus on, explicitly blur the active element 12146 // https://bugs.webkit.org/show_bug.cgi?id=47182 12147 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) ); 12148 } 12149 12150 this._hide( this.uiDialog, this.options.hide, function() { 12151 that._trigger( "close", event ); 12152 } ); 12153 }, 12154 12155 isOpen: function() { 12156 return this._isOpen; 12157 }, 12158 12159 moveToTop: function() { 12160 this._moveToTop(); 12161 }, 12162 12163 _moveToTop: function( event, silent ) { 12164 var moved = false, 12165 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() { 12166 return +$( this ).css( "z-index" ); 12167 } ).get(), 12168 zIndexMax = Math.max.apply( null, zIndices ); 12169 12170 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { 12171 this.uiDialog.css( "z-index", zIndexMax + 1 ); 12172 moved = true; 12173 } 12174 12175 if ( moved && !silent ) { 12176 this._trigger( "focus", event ); 12177 } 12178 return moved; 12179 }, 12180 12181 open: function() { 12182 var that = this; 12183 if ( this._isOpen ) { 12184 if ( this._moveToTop() ) { 12185 this._focusTabbable(); 12186 } 12187 return; 12188 } 12189 12190 this._isOpen = true; 12191 this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); 12192 12193 this._size(); 12194 this._position(); 12195 this._createOverlay(); 12196 this._moveToTop( null, true ); 12197 12198 // Ensure the overlay is moved to the top with the dialog, but only when 12199 // opening. The overlay shouldn't move after the dialog is open so that 12200 // modeless dialogs opened after the modal dialog stack properly. 12201 if ( this.overlay ) { 12202 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); 12203 } 12204 12205 this._show( this.uiDialog, this.options.show, function() { 12206 that._focusTabbable(); 12207 that._trigger( "focus" ); 12208 } ); 12209 12210 // Track the dialog immediately upon openening in case a focus event 12211 // somehow occurs outside of the dialog before an element inside the 12212 // dialog is focused (#10152) 12213 this._makeFocusTarget(); 12214 12215 this._trigger( "open" ); 12216 }, 12217 12218 _focusTabbable: function() { 12219 12220 // Set focus to the first match: 12221 // 1. An element that was focused previously 12222 // 2. First element inside the dialog matching [autofocus] 12223 // 3. Tabbable element inside the content element 12224 // 4. Tabbable element inside the buttonpane 12225 // 5. The close button 12226 // 6. The dialog itself 12227 var hasFocus = this._focusedElement; 12228 if ( !hasFocus ) { 12229 hasFocus = this.element.find( "[autofocus]" ); 12230 } 12231 if ( !hasFocus.length ) { 12232 hasFocus = this.element.find( ":tabbable" ); 12233 } 12234 if ( !hasFocus.length ) { 12235 hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); 12236 } 12237 if ( !hasFocus.length ) { 12238 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); 12239 } 12240 if ( !hasFocus.length ) { 12241 hasFocus = this.uiDialog; 12242 } 12243 hasFocus.eq( 0 ).trigger( "focus" ); 12244 }, 12245 12246 _keepFocus: function( event ) { 12247 function checkFocus() { 12248 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ), 12249 isActive = this.uiDialog[ 0 ] === activeElement || 12250 $.contains( this.uiDialog[ 0 ], activeElement ); 12251 if ( !isActive ) { 12252 this._focusTabbable(); 12253 } 12254 } 12255 event.preventDefault(); 12256 checkFocus.call( this ); 12257 12258 // support: IE 12259 // IE <= 8 doesn't prevent moving focus even with event.preventDefault() 12260 // so we check again later 12261 this._delay( checkFocus ); 12262 }, 12263 12264 _createWrapper: function() { 12265 this.uiDialog = $( "<div>" ) 12266 .hide() 12267 .attr( { 12268 12269 // Setting tabIndex makes the div focusable 12270 tabIndex: -1, 12271 role: "dialog" 12272 } ) 12273 .appendTo( this._appendTo() ); 12274 12275 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" ); 12276 this._on( this.uiDialog, { 12277 keydown: function( event ) { 12278 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 12279 event.keyCode === $.ui.keyCode.ESCAPE ) { 12280 event.preventDefault(); 12281 this.close( event ); 12282 return; 12283 } 12284 12285 // Prevent tabbing out of dialogs 12286 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { 12287 return; 12288 } 12289 var tabbables = this.uiDialog.find( ":tabbable" ), 12290 first = tabbables.filter( ":first" ), 12291 last = tabbables.filter( ":last" ); 12292 12293 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) && 12294 !event.shiftKey ) { 12295 this._delay( function() { 12296 first.trigger( "focus" ); 12297 } ); 12298 event.preventDefault(); 12299 } else if ( ( event.target === first[ 0 ] || 12300 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) { 12301 this._delay( function() { 12302 last.trigger( "focus" ); 12303 } ); 12304 event.preventDefault(); 12305 } 12306 }, 12307 mousedown: function( event ) { 12308 if ( this._moveToTop( event ) ) { 12309 this._focusTabbable(); 12310 } 12311 } 12312 } ); 12313 12314 // We assume that any existing aria-describedby attribute means 12315 // that the dialog content is marked up properly 12316 // otherwise we brute force the content as the description 12317 if ( !this.element.find( "[aria-describedby]" ).length ) { 12318 this.uiDialog.attr( { 12319 "aria-describedby": this.element.uniqueId().attr( "id" ) 12320 } ); 12321 } 12322 }, 12323 12324 _createTitlebar: function() { 12325 var uiDialogTitle; 12326 12327 this.uiDialogTitlebar = $( "<div>" ); 12328 this._addClass( this.uiDialogTitlebar, 12329 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" ); 12330 this._on( this.uiDialogTitlebar, { 12331 mousedown: function( event ) { 12332 12333 // Don't prevent click on close button (#8838) 12334 // Focusing a dialog that is partially scrolled out of view 12335 // causes the browser to scroll it into view, preventing the click event 12336 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { 12337 12338 // Dialog isn't getting focus when dragging (#8063) 12339 this.uiDialog.trigger( "focus" ); 12340 } 12341 } 12342 } ); 12343 12344 // Support: IE 12345 // Use type="button" to prevent enter keypresses in textboxes from closing the 12346 // dialog in IE (#9312) 12347 this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) 12348 .button( { 12349 label: $( "<a>" ).text( this.options.closeText ).html(), 12350 icon: "ui-icon-closethick", 12351 showLabel: false 12352 } ) 12353 .appendTo( this.uiDialogTitlebar ); 12354 12355 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" ); 12356 this._on( this.uiDialogTitlebarClose, { 12357 click: function( event ) { 12358 event.preventDefault(); 12359 this.close( event ); 12360 } 12361 } ); 12362 12363 uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar ); 12364 this._addClass( uiDialogTitle, "ui-dialog-title" ); 12365 this._title( uiDialogTitle ); 12366 12367 this.uiDialogTitlebar.prependTo( this.uiDialog ); 12368 12369 this.uiDialog.attr( { 12370 "aria-labelledby": uiDialogTitle.attr( "id" ) 12371 } ); 12372 }, 12373 12374 _title: function( title ) { 12375 if ( this.options.title ) { 12376 title.text( this.options.title ); 12377 } else { 12378 title.html( " " ); 12379 } 12380 }, 12381 12382 _createButtonPane: function() { 12383 this.uiDialogButtonPane = $( "<div>" ); 12384 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane", 12385 "ui-widget-content ui-helper-clearfix" ); 12386 12387 this.uiButtonSet = $( "<div>" ) 12388 .appendTo( this.uiDialogButtonPane ); 12389 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" ); 12390 12391 this._createButtons(); 12392 }, 12393 12394 _createButtons: function() { 12395 var that = this, 12396 buttons = this.options.buttons; 12397 12398 // If we already have a button pane, remove it 12399 this.uiDialogButtonPane.remove(); 12400 this.uiButtonSet.empty(); 12401 12402 if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) { 12403 this._removeClass( this.uiDialog, "ui-dialog-buttons" ); 12404 return; 12405 } 12406 12407 $.each( buttons, function( name, props ) { 12408 var click, buttonOptions; 12409 props = $.isFunction( props ) ? 12410 { click: props, text: name } : 12411 props; 12412 12413 // Default to a non-submitting button 12414 props = $.extend( { type: "button" }, props ); 12415 12416 // Change the context for the click callback to be the main element 12417 click = props.click; 12418 buttonOptions = { 12419 icon: props.icon, 12420 iconPosition: props.iconPosition, 12421 showLabel: props.showLabel, 12422 12423 // Deprecated options 12424 icons: props.icons, 12425 text: props.text 12426 }; 12427 12428 delete props.click; 12429 delete props.icon; 12430 delete props.iconPosition; 12431 delete props.showLabel; 12432 12433 // Deprecated options 12434 delete props.icons; 12435 if ( typeof props.text === "boolean" ) { 12436 delete props.text; 12437 } 12438 12439 $( "<button></button>", props ) 12440 .button( buttonOptions ) 12441 .appendTo( that.uiButtonSet ) 12442 .on( "click", function() { 12443 click.apply( that.element[ 0 ], arguments ); 12444 } ); 12445 } ); 12446 this._addClass( this.uiDialog, "ui-dialog-buttons" ); 12447 this.uiDialogButtonPane.appendTo( this.uiDialog ); 12448 }, 12449 12450 _makeDraggable: function() { 12451 var that = this, 12452 options = this.options; 12453 12454 function filteredUi( ui ) { 12455 return { 12456 position: ui.position, 12457 offset: ui.offset 12458 }; 12459 } 12460 12461 this.uiDialog.draggable( { 12462 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", 12463 handle: ".ui-dialog-titlebar", 12464 containment: "document", 12465 start: function( event, ui ) { 12466 that._addClass( $( this ), "ui-dialog-dragging" ); 12467 that._blockFrames(); 12468 that._trigger( "dragStart", event, filteredUi( ui ) ); 12469 }, 12470 drag: function( event, ui ) { 12471 that._trigger( "drag", event, filteredUi( ui ) ); 12472 }, 12473 stop: function( event, ui ) { 12474 var left = ui.offset.left - that.document.scrollLeft(), 12475 top = ui.offset.top - that.document.scrollTop(); 12476 12477 options.position = { 12478 my: "left top", 12479 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12480 "top" + ( top >= 0 ? "+" : "" ) + top, 12481 of: that.window 12482 }; 12483 that._removeClass( $( this ), "ui-dialog-dragging" ); 12484 that._unblockFrames(); 12485 that._trigger( "dragStop", event, filteredUi( ui ) ); 12486 } 12487 } ); 12488 }, 12489 12490 _makeResizable: function() { 12491 var that = this, 12492 options = this.options, 12493 handles = options.resizable, 12494 12495 // .ui-resizable has position: relative defined in the stylesheet 12496 // but dialogs have to use absolute or fixed positioning 12497 position = this.uiDialog.css( "position" ), 12498 resizeHandles = typeof handles === "string" ? 12499 handles : 12500 "n,e,s,w,se,sw,ne,nw"; 12501 12502 function filteredUi( ui ) { 12503 return { 12504 originalPosition: ui.originalPosition, 12505 originalSize: ui.originalSize, 12506 position: ui.position, 12507 size: ui.size 12508 }; 12509 } 12510 12511 this.uiDialog.resizable( { 12512 cancel: ".ui-dialog-content", 12513 containment: "document", 12514 alsoResize: this.element, 12515 maxWidth: options.maxWidth, 12516 maxHeight: options.maxHeight, 12517 minWidth: options.minWidth, 12518 minHeight: this._minHeight(), 12519 handles: resizeHandles, 12520 start: function( event, ui ) { 12521 that._addClass( $( this ), "ui-dialog-resizing" ); 12522 that._blockFrames(); 12523 that._trigger( "resizeStart", event, filteredUi( ui ) ); 12524 }, 12525 resize: function( event, ui ) { 12526 that._trigger( "resize", event, filteredUi( ui ) ); 12527 }, 12528 stop: function( event, ui ) { 12529 var offset = that.uiDialog.offset(), 12530 left = offset.left - that.document.scrollLeft(), 12531 top = offset.top - that.document.scrollTop(); 12532 12533 options.height = that.uiDialog.height(); 12534 options.width = that.uiDialog.width(); 12535 options.position = { 12536 my: "left top", 12537 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12538 "top" + ( top >= 0 ? "+" : "" ) + top, 12539 of: that.window 12540 }; 12541 that._removeClass( $( this ), "ui-dialog-resizing" ); 12542 that._unblockFrames(); 12543 that._trigger( "resizeStop", event, filteredUi( ui ) ); 12544 } 12545 } ) 12546 .css( "position", position ); 12547 }, 12548 12549 _trackFocus: function() { 12550 this._on( this.widget(), { 12551 focusin: function( event ) { 12552 this._makeFocusTarget(); 12553 this._focusedElement = $( event.target ); 12554 } 12555 } ); 12556 }, 12557 12558 _makeFocusTarget: function() { 12559 this._untrackInstance(); 12560 this._trackingInstances().unshift( this ); 12561 }, 12562 12563 _untrackInstance: function() { 12564 var instances = this._trackingInstances(), 12565 exists = $.inArray( this, instances ); 12566 if ( exists !== -1 ) { 12567 instances.splice( exists, 1 ); 12568 } 12569 }, 12570 12571 _trackingInstances: function() { 12572 var instances = this.document.data( "ui-dialog-instances" ); 12573 if ( !instances ) { 12574 instances = []; 12575 this.document.data( "ui-dialog-instances", instances ); 12576 } 12577 return instances; 12578 }, 12579 12580 _minHeight: function() { 12581 var options = this.options; 12582 12583 return options.height === "auto" ? 12584 options.minHeight : 12585 Math.min( options.minHeight, options.height ); 12586 }, 12587 12588 _position: function() { 12589 12590 // Need to show the dialog to get the actual offset in the position plugin 12591 var isVisible = this.uiDialog.is( ":visible" ); 12592 if ( !isVisible ) { 12593 this.uiDialog.show(); 12594 } 12595 this.uiDialog.position( this.options.position ); 12596 if ( !isVisible ) { 12597 this.uiDialog.hide(); 12598 } 12599 }, 12600 12601 _setOptions: function( options ) { 12602 var that = this, 12603 resize = false, 12604 resizableOptions = {}; 12605 12606 $.each( options, function( key, value ) { 12607 that._setOption( key, value ); 12608 12609 if ( key in that.sizeRelatedOptions ) { 12610 resize = true; 12611 } 12612 if ( key in that.resizableRelatedOptions ) { 12613 resizableOptions[ key ] = value; 12614 } 12615 } ); 12616 12617 if ( resize ) { 12618 this._size(); 12619 this._position(); 12620 } 12621 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12622 this.uiDialog.resizable( "option", resizableOptions ); 12623 } 12624 }, 12625 12626 _setOption: function( key, value ) { 12627 var isDraggable, isResizable, 12628 uiDialog = this.uiDialog; 12629 12630 if ( key === "disabled" ) { 12631 return; 12632 } 12633 12634 this._super( key, value ); 12635 12636 if ( key === "appendTo" ) { 12637 this.uiDialog.appendTo( this._appendTo() ); 12638 } 12639 12640 if ( key === "buttons" ) { 12641 this._createButtons(); 12642 } 12643 12644 if ( key === "closeText" ) { 12645 this.uiDialogTitlebarClose.button( { 12646 12647 // Ensure that we always pass a string 12648 label: $( "<a>" ).text( "" + this.options.closeText ).html() 12649 } ); 12650 } 12651 12652 if ( key === "draggable" ) { 12653 isDraggable = uiDialog.is( ":data(ui-draggable)" ); 12654 if ( isDraggable && !value ) { 12655 uiDialog.draggable( "destroy" ); 12656 } 12657 12658 if ( !isDraggable && value ) { 12659 this._makeDraggable(); 12660 } 12661 } 12662 12663 if ( key === "position" ) { 12664 this._position(); 12665 } 12666 12667 if ( key === "resizable" ) { 12668 12669 // currently resizable, becoming non-resizable 12670 isResizable = uiDialog.is( ":data(ui-resizable)" ); 12671 if ( isResizable && !value ) { 12672 uiDialog.resizable( "destroy" ); 12673 } 12674 12675 // Currently resizable, changing handles 12676 if ( isResizable && typeof value === "string" ) { 12677 uiDialog.resizable( "option", "handles", value ); 12678 } 12679 12680 // Currently non-resizable, becoming resizable 12681 if ( !isResizable && value !== false ) { 12682 this._makeResizable(); 12683 } 12684 } 12685 12686 if ( key === "title" ) { 12687 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); 12688 } 12689 }, 12690 12691 _size: function() { 12692 12693 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 12694 // divs will both have width and height set, so we need to reset them 12695 var nonContentHeight, minContentHeight, maxContentHeight, 12696 options = this.options; 12697 12698 // Reset content sizing 12699 this.element.show().css( { 12700 width: "auto", 12701 minHeight: 0, 12702 maxHeight: "none", 12703 height: 0 12704 } ); 12705 12706 if ( options.minWidth > options.width ) { 12707 options.width = options.minWidth; 12708 } 12709 12710 // Reset wrapper sizing 12711 // determine the height of all the non-content elements 12712 nonContentHeight = this.uiDialog.css( { 12713 height: "auto", 12714 width: options.width 12715 } ) 12716 .outerHeight(); 12717 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 12718 maxContentHeight = typeof options.maxHeight === "number" ? 12719 Math.max( 0, options.maxHeight - nonContentHeight ) : 12720 "none"; 12721 12722 if ( options.height === "auto" ) { 12723 this.element.css( { 12724 minHeight: minContentHeight, 12725 maxHeight: maxContentHeight, 12726 height: "auto" 12727 } ); 12728 } else { 12729 this.element.height( Math.max( 0, options.height - nonContentHeight ) ); 12730 } 12731 12732 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12733 this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); 12734 } 12735 }, 12736 12737 _blockFrames: function() { 12738 this.iframeBlocks = this.document.find( "iframe" ).map( function() { 12739 var iframe = $( this ); 12740 12741 return $( "<div>" ) 12742 .css( { 12743 position: "absolute", 12744 width: iframe.outerWidth(), 12745 height: iframe.outerHeight() 12746 } ) 12747 .appendTo( iframe.parent() ) 12748 .offset( iframe.offset() )[ 0 ]; 12749 } ); 12750 }, 12751 12752 _unblockFrames: function() { 12753 if ( this.iframeBlocks ) { 12754 this.iframeBlocks.remove(); 12755 delete this.iframeBlocks; 12756 } 12757 }, 12758 12759 _allowInteraction: function( event ) { 12760 if ( $( event.target ).closest( ".ui-dialog" ).length ) { 12761 return true; 12762 } 12763 12764 // TODO: Remove hack when datepicker implements 12765 // the .ui-front logic (#8989) 12766 return !!$( event.target ).closest( ".ui-datepicker" ).length; 12767 }, 12768 12769 _createOverlay: function() { 12770 if ( !this.options.modal ) { 12771 return; 12772 } 12773 12774 // We use a delay in case the overlay is created from an 12775 // event that we're going to be cancelling (#2804) 12776 var isOpening = true; 12777 this._delay( function() { 12778 isOpening = false; 12779 } ); 12780 12781 if ( !this.document.data( "ui-dialog-overlays" ) ) { 12782 12783 // Prevent use of anchors and inputs 12784 // Using _on() for an event handler shared across many instances is 12785 // safe because the dialogs stack and must be closed in reverse order 12786 this._on( this.document, { 12787 focusin: function( event ) { 12788 if ( isOpening ) { 12789 return; 12790 } 12791 12792 if ( !this._allowInteraction( event ) ) { 12793 event.preventDefault(); 12794 this._trackingInstances()[ 0 ]._focusTabbable(); 12795 } 12796 } 12797 } ); 12798 } 12799 12800 this.overlay = $( "<div>" ) 12801 .appendTo( this._appendTo() ); 12802 12803 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" ); 12804 this._on( this.overlay, { 12805 mousedown: "_keepFocus" 12806 } ); 12807 this.document.data( "ui-dialog-overlays", 12808 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 ); 12809 }, 12810 12811 _destroyOverlay: function() { 12812 if ( !this.options.modal ) { 12813 return; 12814 } 12815 12816 if ( this.overlay ) { 12817 var overlays = this.document.data( "ui-dialog-overlays" ) - 1; 12818 12819 if ( !overlays ) { 12820 this._off( this.document, "focusin" ); 12821 this.document.removeData( "ui-dialog-overlays" ); 12822 } else { 12823 this.document.data( "ui-dialog-overlays", overlays ); 12824 } 12825 12826 this.overlay.remove(); 12827 this.overlay = null; 12828 } 12829 } 12830 } ); 12831 12832 // DEPRECATED 12833 // TODO: switch return back to widget declaration at top of file when this is removed 12834 if ( $.uiBackCompat !== false ) { 12835 12836 // Backcompat for dialogClass option 12837 $.widget( "ui.dialog", $.ui.dialog, { 12838 options: { 12839 dialogClass: "" 12840 }, 12841 _createWrapper: function() { 12842 this._super(); 12843 this.uiDialog.addClass( this.options.dialogClass ); 12844 }, 12845 _setOption: function( key, value ) { 12846 if ( key === "dialogClass" ) { 12847 this.uiDialog 12848 .removeClass( this.options.dialogClass ) 12849 .addClass( value ); 12850 } 12851 this._superApply( arguments ); 12852 } 12853 } ); 12854 } 12855 12856 var widgetsDialog = $.ui.dialog; 12857 12858 12859 /*! 12860 * jQuery UI Droppable 1.12.1 12861 * http://jqueryui.com 12862 * 12863 * Copyright jQuery Foundation and other contributors 12864 * Released under the MIT license. 12865 * http://jquery.org/license 12866 */ 12867 12868 //>>label: Droppable 12869 //>>group: Interactions 12870 //>>description: Enables drop targets for draggable elements. 12871 //>>docs: http://api.jqueryui.com/droppable/ 12872 //>>demos: http://jqueryui.com/droppable/ 12873 12874 12875 12876 $.widget( "ui.droppable", { 12877 version: "1.12.1", 12878 widgetEventPrefix: "drop", 12879 options: { 12880 accept: "*", 12881 addClasses: true, 12882 greedy: false, 12883 scope: "default", 12884 tolerance: "intersect", 12885 12886 // Callbacks 12887 activate: null, 12888 deactivate: null, 12889 drop: null, 12890 out: null, 12891 over: null 12892 }, 12893 _create: function() { 12894 12895 var proportions, 12896 o = this.options, 12897 accept = o.accept; 12898 12899 this.isover = false; 12900 this.isout = true; 12901 12902 this.accept = $.isFunction( accept ) ? accept : function( d ) { 12903 return d.is( accept ); 12904 }; 12905 12906 this.proportions = function( /* valueToWrite */ ) { 12907 if ( arguments.length ) { 12908 12909 // Store the droppable's proportions 12910 proportions = arguments[ 0 ]; 12911 } else { 12912 12913 // Retrieve or derive the droppable's proportions 12914 return proportions ? 12915 proportions : 12916 proportions = { 12917 width: this.element[ 0 ].offsetWidth, 12918 height: this.element[ 0 ].offsetHeight 12919 }; 12920 } 12921 }; 12922 12923 this._addToManager( o.scope ); 12924 12925 o.addClasses && this._addClass( "ui-droppable" ); 12926 12927 }, 12928 12929 _addToManager: function( scope ) { 12930 12931 // Add the reference and positions to the manager 12932 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; 12933 $.ui.ddmanager.droppables[ scope ].push( this ); 12934 }, 12935 12936 _splice: function( drop ) { 12937 var i = 0; 12938 for ( ; i < drop.length; i++ ) { 12939 if ( drop[ i ] === this ) { 12940 drop.splice( i, 1 ); 12941 } 12942 } 12943 }, 12944 12945 _destroy: function() { 12946 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 12947 12948 this._splice( drop ); 12949 }, 12950 12951 _setOption: function( key, value ) { 12952 12953 if ( key === "accept" ) { 12954 this.accept = $.isFunction( value ) ? value : function( d ) { 12955 return d.is( value ); 12956 }; 12957 } else if ( key === "scope" ) { 12958 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 12959 12960 this._splice( drop ); 12961 this._addToManager( value ); 12962 } 12963 12964 this._super( key, value ); 12965 }, 12966 12967 _activate: function( event ) { 12968 var draggable = $.ui.ddmanager.current; 12969 12970 this._addActiveClass(); 12971 if ( draggable ) { 12972 this._trigger( "activate", event, this.ui( draggable ) ); 12973 } 12974 }, 12975 12976 _deactivate: function( event ) { 12977 var draggable = $.ui.ddmanager.current; 12978 12979 this._removeActiveClass(); 12980 if ( draggable ) { 12981 this._trigger( "deactivate", event, this.ui( draggable ) ); 12982 } 12983 }, 12984 12985 _over: function( event ) { 12986 12987 var draggable = $.ui.ddmanager.current; 12988 12989 // Bail if draggable and droppable are same element 12990 if ( !draggable || ( draggable.currentItem || 12991 draggable.element )[ 0 ] === this.element[ 0 ] ) { 12992 return; 12993 } 12994 12995 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 12996 draggable.element ) ) ) { 12997 this._addHoverClass(); 12998 this._trigger( "over", event, this.ui( draggable ) ); 12999 } 13000 13001 }, 13002 13003 _out: function( event ) { 13004 13005 var draggable = $.ui.ddmanager.current; 13006 13007 // Bail if draggable and droppable are same element 13008 if ( !draggable || ( draggable.currentItem || 13009 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13010 return; 13011 } 13012 13013 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 13014 draggable.element ) ) ) { 13015 this._removeHoverClass(); 13016 this._trigger( "out", event, this.ui( draggable ) ); 13017 } 13018 13019 }, 13020 13021 _drop: function( event, custom ) { 13022 13023 var draggable = custom || $.ui.ddmanager.current, 13024 childrenIntersection = false; 13025 13026 // Bail if draggable and droppable are same element 13027 if ( !draggable || ( draggable.currentItem || 13028 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13029 return false; 13030 } 13031 13032 this.element 13033 .find( ":data(ui-droppable)" ) 13034 .not( ".ui-draggable-dragging" ) 13035 .each( function() { 13036 var inst = $( this ).droppable( "instance" ); 13037 if ( 13038 inst.options.greedy && 13039 !inst.options.disabled && 13040 inst.options.scope === draggable.options.scope && 13041 inst.accept.call( 13042 inst.element[ 0 ], ( draggable.currentItem || draggable.element ) 13043 ) && 13044 intersect( 13045 draggable, 13046 $.extend( inst, { offset: inst.element.offset() } ), 13047 inst.options.tolerance, event 13048 ) 13049 ) { 13050 childrenIntersection = true; 13051 return false; } 13052 } ); 13053 if ( childrenIntersection ) { 13054 return false; 13055 } 13056 13057 if ( this.accept.call( this.element[ 0 ], 13058 ( draggable.currentItem || draggable.element ) ) ) { 13059 this._removeActiveClass(); 13060 this._removeHoverClass(); 13061 13062 this._trigger( "drop", event, this.ui( draggable ) ); 13063 return this.element; 13064 } 13065 13066 return false; 13067 13068 }, 13069 13070 ui: function( c ) { 13071 return { 13072 draggable: ( c.currentItem || c.element ), 13073 helper: c.helper, 13074 position: c.position, 13075 offset: c.positionAbs 13076 }; 13077 }, 13078 13079 // Extension points just to make backcompat sane and avoid duplicating logic 13080 // TODO: Remove in 1.13 along with call to it below 13081 _addHoverClass: function() { 13082 this._addClass( "ui-droppable-hover" ); 13083 }, 13084 13085 _removeHoverClass: function() { 13086 this._removeClass( "ui-droppable-hover" ); 13087 }, 13088 13089 _addActiveClass: function() { 13090 this._addClass( "ui-droppable-active" ); 13091 }, 13092 13093 _removeActiveClass: function() { 13094 this._removeClass( "ui-droppable-active" ); 13095 } 13096 } ); 13097 13098 var intersect = $.ui.intersect = ( function() { 13099 function isOverAxis( x, reference, size ) { 13100 return ( x >= reference ) && ( x < ( reference + size ) ); 13101 } 13102 13103 return function( draggable, droppable, toleranceMode, event ) { 13104 13105 if ( !droppable.offset ) { 13106 return false; 13107 } 13108 13109 var x1 = ( draggable.positionAbs || 13110 draggable.position.absolute ).left + draggable.margins.left, 13111 y1 = ( draggable.positionAbs || 13112 draggable.position.absolute ).top + draggable.margins.top, 13113 x2 = x1 + draggable.helperProportions.width, 13114 y2 = y1 + draggable.helperProportions.height, 13115 l = droppable.offset.left, 13116 t = droppable.offset.top, 13117 r = l + droppable.proportions().width, 13118 b = t + droppable.proportions().height; 13119 13120 switch ( toleranceMode ) { 13121 case "fit": 13122 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); 13123 case "intersect": 13124 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half 13125 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half 13126 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half 13127 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half 13128 case "pointer": 13129 return isOverAxis( event.pageY, t, droppable.proportions().height ) && 13130 isOverAxis( event.pageX, l, droppable.proportions().width ); 13131 case "touch": 13132 return ( 13133 ( y1 >= t && y1 <= b ) || // Top edge touching 13134 ( y2 >= t && y2 <= b ) || // Bottom edge touching 13135 ( y1 < t && y2 > b ) // Surrounded vertically 13136 ) && ( 13137 ( x1 >= l && x1 <= r ) || // Left edge touching 13138 ( x2 >= l && x2 <= r ) || // Right edge touching 13139 ( x1 < l && x2 > r ) // Surrounded horizontally 13140 ); 13141 default: 13142 return false; 13143 } 13144 }; 13145 } )(); 13146 13147 /* 13148 This manager tracks offsets of draggables and droppables 13149 */ 13150 $.ui.ddmanager = { 13151 current: null, 13152 droppables: { "default": [] }, 13153 prepareOffsets: function( t, event ) { 13154 13155 var i, j, 13156 m = $.ui.ddmanager.droppables[ t.options.scope ] || [], 13157 type = event ? event.type : null, // workaround for #2317 13158 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); 13159 13160 droppablesLoop: for ( i = 0; i < m.length; i++ ) { 13161 13162 // No disabled and non-accepted 13163 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], 13164 ( t.currentItem || t.element ) ) ) ) { 13165 continue; 13166 } 13167 13168 // Filter out elements in the current dragged item 13169 for ( j = 0; j < list.length; j++ ) { 13170 if ( list[ j ] === m[ i ].element[ 0 ] ) { 13171 m[ i ].proportions().height = 0; 13172 continue droppablesLoop; 13173 } 13174 } 13175 13176 m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; 13177 if ( !m[ i ].visible ) { 13178 continue; 13179 } 13180 13181 // Activate the droppable if used directly from draggables 13182 if ( type === "mousedown" ) { 13183 m[ i ]._activate.call( m[ i ], event ); 13184 } 13185 13186 m[ i ].offset = m[ i ].element.offset(); 13187 m[ i ].proportions( { 13188 width: m[ i ].element[ 0 ].offsetWidth, 13189 height: m[ i ].element[ 0 ].offsetHeight 13190 } ); 13191 13192 } 13193 13194 }, 13195 drop: function( draggable, event ) { 13196 13197 var dropped = false; 13198 13199 // Create a copy of the droppables in case the list changes during the drop (#9116) 13200 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { 13201 13202 if ( !this.options ) { 13203 return; 13204 } 13205 if ( !this.options.disabled && this.visible && 13206 intersect( draggable, this, this.options.tolerance, event ) ) { 13207 dropped = this._drop.call( this, event ) || dropped; 13208 } 13209 13210 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], 13211 ( draggable.currentItem || draggable.element ) ) ) { 13212 this.isout = true; 13213 this.isover = false; 13214 this._deactivate.call( this, event ); 13215 } 13216 13217 } ); 13218 return dropped; 13219 13220 }, 13221 dragStart: function( draggable, event ) { 13222 13223 // Listen for scrolling so that if the dragging causes scrolling the position of the 13224 // droppables can be recalculated (see #5003) 13225 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() { 13226 if ( !draggable.options.refreshPositions ) { 13227 $.ui.ddmanager.prepareOffsets( draggable, event ); 13228 } 13229 } ); 13230 }, 13231 drag: function( draggable, event ) { 13232 13233 // If you have a highly dynamic page, you might try this option. It renders positions 13234 // every time you move the mouse. 13235 if ( draggable.options.refreshPositions ) { 13236 $.ui.ddmanager.prepareOffsets( draggable, event ); 13237 } 13238 13239 // Run through all droppables and check their positions based on specific tolerance options 13240 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { 13241 13242 if ( this.options.disabled || this.greedyChild || !this.visible ) { 13243 return; 13244 } 13245 13246 var parentInstance, scope, parent, 13247 intersects = intersect( draggable, this, this.options.tolerance, event ), 13248 c = !intersects && this.isover ? 13249 "isout" : 13250 ( intersects && !this.isover ? "isover" : null ); 13251 if ( !c ) { 13252 return; 13253 } 13254 13255 if ( this.options.greedy ) { 13256 13257 // find droppable parents with same scope 13258 scope = this.options.scope; 13259 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() { 13260 return $( this ).droppable( "instance" ).options.scope === scope; 13261 } ); 13262 13263 if ( parent.length ) { 13264 parentInstance = $( parent[ 0 ] ).droppable( "instance" ); 13265 parentInstance.greedyChild = ( c === "isover" ); 13266 } 13267 } 13268 13269 // We just moved into a greedy child 13270 if ( parentInstance && c === "isover" ) { 13271 parentInstance.isover = false; 13272 parentInstance.isout = true; 13273 parentInstance._out.call( parentInstance, event ); 13274 } 13275 13276 this[ c ] = true; 13277 this[ c === "isout" ? "isover" : "isout" ] = false; 13278 this[ c === "isover" ? "_over" : "_out" ].call( this, event ); 13279 13280 // We just moved out of a greedy child 13281 if ( parentInstance && c === "isout" ) { 13282 parentInstance.isout = false; 13283 parentInstance.isover = true; 13284 parentInstance._over.call( parentInstance, event ); 13285 } 13286 } ); 13287 13288 }, 13289 dragStop: function( draggable, event ) { 13290 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" ); 13291 13292 // Call prepareOffsets one final time since IE does not fire return scroll events when 13293 // overflow was caused by drag (see #5003) 13294 if ( !draggable.options.refreshPositions ) { 13295 $.ui.ddmanager.prepareOffsets( draggable, event ); 13296 } 13297 } 13298 }; 13299 13300 // DEPRECATED 13301 // TODO: switch return back to widget declaration at top of file when this is removed 13302 if ( $.uiBackCompat !== false ) { 13303 13304 // Backcompat for activeClass and hoverClass options 13305 $.widget( "ui.droppable", $.ui.droppable, { 13306 options: { 13307 hoverClass: false, 13308 activeClass: false 13309 }, 13310 _addActiveClass: function() { 13311 this._super(); 13312 if ( this.options.activeClass ) { 13313 this.element.addClass( this.options.activeClass ); 13314 } 13315 }, 13316 _removeActiveClass: function() { 13317 this._super(); 13318 if ( this.options.activeClass ) { 13319 this.element.removeClass( this.options.activeClass ); 13320 } 13321 }, 13322 _addHoverClass: function() { 13323 this._super(); 13324 if ( this.options.hoverClass ) { 13325 this.element.addClass( this.options.hoverClass ); 13326 } 13327 }, 13328 _removeHoverClass: function() { 13329 this._super(); 13330 if ( this.options.hoverClass ) { 13331 this.element.removeClass( this.options.hoverClass ); 13332 } 13333 } 13334 } ); 13335 } 13336 13337 var widgetsDroppable = $.ui.droppable; 13338 13339 13340 /*! 13341 * jQuery UI Progressbar 1.12.1 13342 * http://jqueryui.com 13343 * 13344 * Copyright jQuery Foundation and other contributors 13345 * Released under the MIT license. 13346 * http://jquery.org/license 13347 */ 13348 13349 //>>label: Progressbar 13350 //>>group: Widgets 13351 // jscs:disable maximumLineLength 13352 //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators. 13353 // jscs:enable maximumLineLength 13354 //>>docs: http://api.jqueryui.com/progressbar/ 13355 //>>demos: http://jqueryui.com/progressbar/ 13356 //>>css.structure: ../../themes/base/core.css 13357 //>>css.structure: ../../themes/base/progressbar.css 13358 //>>css.theme: ../../themes/base/theme.css 13359 13360 13361 13362 var widgetsProgressbar = $.widget( "ui.progressbar", { 13363 version: "1.12.1", 13364 options: { 13365 classes: { 13366 "ui-progressbar": "ui-corner-all", 13367 "ui-progressbar-value": "ui-corner-left", 13368 "ui-progressbar-complete": "ui-corner-right" 13369 }, 13370 max: 100, 13371 value: 0, 13372 13373 change: null, 13374 complete: null 13375 }, 13376 13377 min: 0, 13378 13379 _create: function() { 13380 13381 // Constrain initial value 13382 this.oldValue = this.options.value = this._constrainedValue(); 13383 13384 this.element.attr( { 13385 13386 // Only set static values; aria-valuenow and aria-valuemax are 13387 // set inside _refreshValue() 13388 role: "progressbar", 13389 "aria-valuemin": this.min 13390 } ); 13391 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" ); 13392 13393 this.valueDiv = $( "<div>" ).appendTo( this.element ); 13394 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" ); 13395 this._refreshValue(); 13396 }, 13397 13398 _destroy: function() { 13399 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" ); 13400 13401 this.valueDiv.remove(); 13402 }, 13403 13404 value: function( newValue ) { 13405 if ( newValue === undefined ) { 13406 return this.options.value; 13407 } 13408 13409 this.options.value = this._constrainedValue( newValue ); 13410 this._refreshValue(); 13411 }, 13412 13413 _constrainedValue: function( newValue ) { 13414 if ( newValue === undefined ) { 13415 newValue = this.options.value; 13416 } 13417 13418 this.indeterminate = newValue === false; 13419 13420 // Sanitize value 13421 if ( typeof newValue !== "number" ) { 13422 newValue = 0; 13423 } 13424 13425 return this.indeterminate ? false : 13426 Math.min( this.options.max, Math.max( this.min, newValue ) ); 13427 }, 13428 13429 _setOptions: function( options ) { 13430 13431 // Ensure "value" option is set after other values (like max) 13432 var value = options.value; 13433 delete options.value; 13434 13435 this._super( options ); 13436 13437 this.options.value = this._constrainedValue( value ); 13438 this._refreshValue(); 13439 }, 13440 13441 _setOption: function( key, value ) { 13442 if ( key === "max" ) { 13443 13444 // Don't allow a max less than min 13445 value = Math.max( this.min, value ); 13446 } 13447 this._super( key, value ); 13448 }, 13449 13450 _setOptionDisabled: function( value ) { 13451 this._super( value ); 13452 13453 this.element.attr( "aria-disabled", value ); 13454 this._toggleClass( null, "ui-state-disabled", !!value ); 13455 }, 13456 13457 _percentage: function() { 13458 return this.indeterminate ? 13459 100 : 13460 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); 13461 }, 13462 13463 _refreshValue: function() { 13464 var value = this.options.value, 13465 percentage = this._percentage(); 13466 13467 this.valueDiv 13468 .toggle( this.indeterminate || value > this.min ) 13469 .width( percentage.toFixed( 0 ) + "%" ); 13470 13471 this 13472 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null, 13473 value === this.options.max ) 13474 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate ); 13475 13476 if ( this.indeterminate ) { 13477 this.element.removeAttr( "aria-valuenow" ); 13478 if ( !this.overlayDiv ) { 13479 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv ); 13480 this._addClass( this.overlayDiv, "ui-progressbar-overlay" ); 13481 } 13482 } else { 13483 this.element.attr( { 13484 "aria-valuemax": this.options.max, 13485 "aria-valuenow": value 13486 } ); 13487 if ( this.overlayDiv ) { 13488 this.overlayDiv.remove(); 13489 this.overlayDiv = null; 13490 } 13491 } 13492 13493 if ( this.oldValue !== value ) { 13494 this.oldValue = value; 13495 this._trigger( "change" ); 13496 } 13497 if ( value === this.options.max ) { 13498 this._trigger( "complete" ); 13499 } 13500 } 13501 } ); 13502 13503 13504 /*! 13505 * jQuery UI Selectable 1.12.1 13506 * http://jqueryui.com 13507 * 13508 * Copyright jQuery Foundation and other contributors 13509 * Released under the MIT license. 13510 * http://jquery.org/license 13511 */ 13512 13513 //>>label: Selectable 13514 //>>group: Interactions 13515 //>>description: Allows groups of elements to be selected with the mouse. 13516 //>>docs: http://api.jqueryui.com/selectable/ 13517 //>>demos: http://jqueryui.com/selectable/ 13518 //>>css.structure: ../../themes/base/selectable.css 13519 13520 13521 13522 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, { 13523 version: "1.12.1", 13524 options: { 13525 appendTo: "body", 13526 autoRefresh: true, 13527 distance: 0, 13528 filter: "*", 13529 tolerance: "touch", 13530 13531 // Callbacks 13532 selected: null, 13533 selecting: null, 13534 start: null, 13535 stop: null, 13536 unselected: null, 13537 unselecting: null 13538 }, 13539 _create: function() { 13540 var that = this; 13541 13542 this._addClass( "ui-selectable" ); 13543 13544 this.dragged = false; 13545 13546 // Cache selectee children based on filter 13547 this.refresh = function() { 13548 that.elementPos = $( that.element[ 0 ] ).offset(); 13549 that.selectees = $( that.options.filter, that.element[ 0 ] ); 13550 that._addClass( that.selectees, "ui-selectee" ); 13551 that.selectees.each( function() { 13552 var $this = $( this ), 13553 selecteeOffset = $this.offset(), 13554 pos = { 13555 left: selecteeOffset.left - that.elementPos.left, 13556 top: selecteeOffset.top - that.elementPos.top 13557 }; 13558 $.data( this, "selectable-item", { 13559 element: this, 13560 $element: $this, 13561 left: pos.left, 13562 top: pos.top, 13563 right: pos.left + $this.outerWidth(), 13564 bottom: pos.top + $this.outerHeight(), 13565 startselected: false, 13566 selected: $this.hasClass( "ui-selected" ), 13567 selecting: $this.hasClass( "ui-selecting" ), 13568 unselecting: $this.hasClass( "ui-unselecting" ) 13569 } ); 13570 } ); 13571 }; 13572 this.refresh(); 13573 13574 this._mouseInit(); 13575 13576 this.helper = $( "<div>" ); 13577 this._addClass( this.helper, "ui-selectable-helper" ); 13578 }, 13579 13580 _destroy: function() { 13581 this.selectees.removeData( "selectable-item" ); 13582 this._mouseDestroy(); 13583 }, 13584 13585 _mouseStart: function( event ) { 13586 var that = this, 13587 options = this.options; 13588 13589 this.opos = [ event.pageX, event.pageY ]; 13590 this.elementPos = $( this.element[ 0 ] ).offset(); 13591 13592 if ( this.options.disabled ) { 13593 return; 13594 } 13595 13596 this.selectees = $( options.filter, this.element[ 0 ] ); 13597 13598 this._trigger( "start", event ); 13599 13600 $( options.appendTo ).append( this.helper ); 13601 13602 // position helper (lasso) 13603 this.helper.css( { 13604 "left": event.pageX, 13605 "top": event.pageY, 13606 "width": 0, 13607 "height": 0 13608 } ); 13609 13610 if ( options.autoRefresh ) { 13611 this.refresh(); 13612 } 13613 13614 this.selectees.filter( ".ui-selected" ).each( function() { 13615 var selectee = $.data( this, "selectable-item" ); 13616 selectee.startselected = true; 13617 if ( !event.metaKey && !event.ctrlKey ) { 13618 that._removeClass( selectee.$element, "ui-selected" ); 13619 selectee.selected = false; 13620 that._addClass( selectee.$element, "ui-unselecting" ); 13621 selectee.unselecting = true; 13622 13623 // selectable UNSELECTING callback 13624 that._trigger( "unselecting", event, { 13625 unselecting: selectee.element 13626 } ); 13627 } 13628 } ); 13629 13630 $( event.target ).parents().addBack().each( function() { 13631 var doSelect, 13632 selectee = $.data( this, "selectable-item" ); 13633 if ( selectee ) { 13634 doSelect = ( !event.metaKey && !event.ctrlKey ) || 13635 !selectee.$element.hasClass( "ui-selected" ); 13636 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" ) 13637 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" ); 13638 selectee.unselecting = !doSelect; 13639 selectee.selecting = doSelect; 13640 selectee.selected = doSelect; 13641 13642 // selectable (UN)SELECTING callback 13643 if ( doSelect ) { 13644 that._trigger( "selecting", event, { 13645 selecting: selectee.element 13646 } ); 13647 } else { 13648 that._trigger( "unselecting", event, { 13649 unselecting: selectee.element 13650 } ); 13651 } 13652 return false; 13653 } 13654 } ); 13655 13656 }, 13657 13658 _mouseDrag: function( event ) { 13659 13660 this.dragged = true; 13661 13662 if ( this.options.disabled ) { 13663 return; 13664 } 13665 13666 var tmp, 13667 that = this, 13668 options = this.options, 13669 x1 = this.opos[ 0 ], 13670 y1 = this.opos[ 1 ], 13671 x2 = event.pageX, 13672 y2 = event.pageY; 13673 13674 if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; } 13675 if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; } 13676 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } ); 13677 13678 this.selectees.each( function() { 13679 var selectee = $.data( this, "selectable-item" ), 13680 hit = false, 13681 offset = {}; 13682 13683 //prevent helper from being selected if appendTo: selectable 13684 if ( !selectee || selectee.element === that.element[ 0 ] ) { 13685 return; 13686 } 13687 13688 offset.left = selectee.left + that.elementPos.left; 13689 offset.right = selectee.right + that.elementPos.left; 13690 offset.top = selectee.top + that.elementPos.top; 13691 offset.bottom = selectee.bottom + that.elementPos.top; 13692 13693 if ( options.tolerance === "touch" ) { 13694 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 || 13695 offset.bottom < y1 ) ); 13696 } else if ( options.tolerance === "fit" ) { 13697 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 && 13698 offset.bottom < y2 ); 13699 } 13700 13701 if ( hit ) { 13702 13703 // SELECT 13704 if ( selectee.selected ) { 13705 that._removeClass( selectee.$element, "ui-selected" ); 13706 selectee.selected = false; 13707 } 13708 if ( selectee.unselecting ) { 13709 that._removeClass( selectee.$element, "ui-unselecting" ); 13710 selectee.unselecting = false; 13711 } 13712 if ( !selectee.selecting ) { 13713 that._addClass( selectee.$element, "ui-selecting" ); 13714 selectee.selecting = true; 13715 13716 // selectable SELECTING callback 13717 that._trigger( "selecting", event, { 13718 selecting: selectee.element 13719 } ); 13720 } 13721 } else { 13722 13723 // UNSELECT 13724 if ( selectee.selecting ) { 13725 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) { 13726 that._removeClass( selectee.$element, "ui-selecting" ); 13727 selectee.selecting = false; 13728 that._addClass( selectee.$element, "ui-selected" ); 13729 selectee.selected = true; 13730 } else { 13731 that._removeClass( selectee.$element, "ui-selecting" ); 13732 selectee.selecting = false; 13733 if ( selectee.startselected ) { 13734 that._addClass( selectee.$element, "ui-unselecting" ); 13735 selectee.unselecting = true; 13736 } 13737 13738 // selectable UNSELECTING callback 13739 that._trigger( "unselecting", event, { 13740 unselecting: selectee.element 13741 } ); 13742 } 13743 } 13744 if ( selectee.selected ) { 13745 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) { 13746 that._removeClass( selectee.$element, "ui-selected" ); 13747 selectee.selected = false; 13748 13749 that._addClass( selectee.$element, "ui-unselecting" ); 13750 selectee.unselecting = true; 13751 13752 // selectable UNSELECTING callback 13753 that._trigger( "unselecting", event, { 13754 unselecting: selectee.element 13755 } ); 13756 } 13757 } 13758 } 13759 } ); 13760 13761 return false; 13762 }, 13763 13764 _mouseStop: function( event ) { 13765 var that = this; 13766 13767 this.dragged = false; 13768 13769 $( ".ui-unselecting", this.element[ 0 ] ).each( function() { 13770 var selectee = $.data( this, "selectable-item" ); 13771 that._removeClass( selectee.$element, "ui-unselecting" ); 13772 selectee.unselecting = false; 13773 selectee.startselected = false; 13774 that._trigger( "unselected", event, { 13775 unselected: selectee.element 13776 } ); 13777 } ); 13778 $( ".ui-selecting", this.element[ 0 ] ).each( function() { 13779 var selectee = $.data( this, "selectable-item" ); 13780 that._removeClass( selectee.$element, "ui-selecting" ) 13781 ._addClass( selectee.$element, "ui-selected" ); 13782 selectee.selecting = false; 13783 selectee.selected = true; 13784 selectee.startselected = true; 13785 that._trigger( "selected", event, { 13786 selected: selectee.element 13787 } ); 13788 } ); 13789 this._trigger( "stop", event ); 13790 13791 this.helper.remove(); 13792 13793 return false; 13794 } 13795 13796 } ); 13797 13798 13799 /*! 13800 * jQuery UI Selectmenu 1.12.1 13801 * http://jqueryui.com 13802 * 13803 * Copyright jQuery Foundation and other contributors 13804 * Released under the MIT license. 13805 * http://jquery.org/license 13806 */ 13807 13808 //>>label: Selectmenu 13809 //>>group: Widgets 13810 // jscs:disable maximumLineLength 13811 //>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select. 13812 // jscs:enable maximumLineLength 13813 //>>docs: http://api.jqueryui.com/selectmenu/ 13814 //>>demos: http://jqueryui.com/selectmenu/ 13815 //>>css.structure: ../../themes/base/core.css 13816 //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css 13817 //>>css.theme: ../../themes/base/theme.css 13818 13819 13820 13821 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, { 13822 version: "1.12.1", 13823 defaultElement: "<select>", 13824 options: { 13825 appendTo: null, 13826 classes: { 13827 "ui-selectmenu-button-open": "ui-corner-top", 13828 "ui-selectmenu-button-closed": "ui-corner-all" 13829 }, 13830 disabled: null, 13831 icons: { 13832 button: "ui-icon-triangle-1-s" 13833 }, 13834 position: { 13835 my: "left top", 13836 at: "left bottom", 13837 collision: "none" 13838 }, 13839 width: false, 13840 13841 // Callbacks 13842 change: null, 13843 close: null, 13844 focus: null, 13845 open: null, 13846 select: null 13847 }, 13848 13849 _create: function() { 13850 var selectmenuId = this.element.uniqueId().attr( "id" ); 13851 this.ids = { 13852 element: selectmenuId, 13853 button: selectmenuId + "-button", 13854 menu: selectmenuId + "-menu" 13855 }; 13856 13857 this._drawButton(); 13858 this._drawMenu(); 13859 this._bindFormResetHandler(); 13860 13861 this._rendered = false; 13862 this.menuItems = $(); 13863 }, 13864 13865 _drawButton: function() { 13866 var icon, 13867 that = this, 13868 item = this._parseOption( 13869 this.element.find( "option:selected" ), 13870 this.element[ 0 ].selectedIndex 13871 ); 13872 13873 // Associate existing label with the new button 13874 this.labels = this.element.labels().attr( "for", this.ids.button ); 13875 this._on( this.labels, { 13876 click: function( event ) { 13877 this.button.focus(); 13878 event.preventDefault(); 13879 } 13880 } ); 13881 13882 // Hide original select element 13883 this.element.hide(); 13884 13885 // Create button 13886 this.button = $( "<span>", { 13887 tabindex: this.options.disabled ? -1 : 0, 13888 id: this.ids.button, 13889 role: "combobox", 13890 "aria-expanded": "false", 13891 "aria-autocomplete": "list", 13892 "aria-owns": this.ids.menu, 13893 "aria-haspopup": "true", 13894 title: this.element.attr( "title" ) 13895 } ) 13896 .insertAfter( this.element ); 13897 13898 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed", 13899 "ui-button ui-widget" ); 13900 13901 icon = $( "<span>" ).appendTo( this.button ); 13902 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button ); 13903 this.buttonItem = this._renderButtonItem( item ) 13904 .appendTo( this.button ); 13905 13906 if ( this.options.width !== false ) { 13907 this._resizeButton(); 13908 } 13909 13910 this._on( this.button, this._buttonEvents ); 13911 this.button.one( "focusin", function() { 13912 13913 // Delay rendering the menu items until the button receives focus. 13914 // The menu may have already been rendered via a programmatic open. 13915 if ( !that._rendered ) { 13916 that._refreshMenu(); 13917 } 13918 } ); 13919 }, 13920 13921 _drawMenu: function() { 13922 var that = this; 13923 13924 // Create menu 13925 this.menu = $( "<ul>", { 13926 "aria-hidden": "true", 13927 "aria-labelledby": this.ids.button, 13928 id: this.ids.menu 13929 } ); 13930 13931 // Wrap menu 13932 this.menuWrap = $( "<div>" ).append( this.menu ); 13933 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" ); 13934 this.menuWrap.appendTo( this._appendTo() ); 13935 13936 // Initialize menu widget 13937 this.menuInstance = this.menu 13938 .menu( { 13939 classes: { 13940 "ui-menu": "ui-corner-bottom" 13941 }, 13942 role: "listbox", 13943 select: function( event, ui ) { 13944 event.preventDefault(); 13945 13946 // Support: IE8 13947 // If the item was selected via a click, the text selection 13948 // will be destroyed in IE 13949 that._setSelection(); 13950 13951 that._select( ui.item.data( "ui-selectmenu-item" ), event ); 13952 }, 13953 focus: function( event, ui ) { 13954 var item = ui.item.data( "ui-selectmenu-item" ); 13955 13956 // Prevent inital focus from firing and check if its a newly focused item 13957 if ( that.focusIndex != null && item.index !== that.focusIndex ) { 13958 that._trigger( "focus", event, { item: item } ); 13959 if ( !that.isOpen ) { 13960 that._select( item, event ); 13961 } 13962 } 13963 that.focusIndex = item.index; 13964 13965 that.button.attr( "aria-activedescendant", 13966 that.menuItems.eq( item.index ).attr( "id" ) ); 13967 } 13968 } ) 13969 .menu( "instance" ); 13970 13971 // Don't close the menu on mouseleave 13972 this.menuInstance._off( this.menu, "mouseleave" ); 13973 13974 // Cancel the menu's collapseAll on document click 13975 this.menuInstance._closeOnDocumentClick = function() { 13976 return false; 13977 }; 13978 13979 // Selects often contain empty items, but never contain dividers 13980 this.menuInstance._isDivider = function() { 13981 return false; 13982 }; 13983 }, 13984 13985 refresh: function() { 13986 this._refreshMenu(); 13987 this.buttonItem.replaceWith( 13988 this.buttonItem = this._renderButtonItem( 13989 13990 // Fall back to an empty object in case there are no options 13991 this._getSelectedItem().data( "ui-selectmenu-item" ) || {} 13992 ) 13993 ); 13994 if ( this.options.width === null ) { 13995 this._resizeButton(); 13996 } 13997 }, 13998 13999 _refreshMenu: function() { 14000 var item, 14001 options = this.element.find( "option" ); 14002 14003 this.menu.empty(); 14004 14005 this._parseOptions( options ); 14006 this._renderMenu( this.menu, this.items ); 14007 14008 this.menuInstance.refresh(); 14009 this.menuItems = this.menu.find( "li" ) 14010 .not( ".ui-selectmenu-optgroup" ) 14011 .find( ".ui-menu-item-wrapper" ); 14012 14013 this._rendered = true; 14014 14015 if ( !options.length ) { 14016 return; 14017 } 14018 14019 item = this._getSelectedItem(); 14020 14021 // Update the menu to have the correct item focused 14022 this.menuInstance.focus( null, item ); 14023 this._setAria( item.data( "ui-selectmenu-item" ) ); 14024 14025 // Set disabled state 14026 this._setOption( "disabled", this.element.prop( "disabled" ) ); 14027 }, 14028 14029 open: function( event ) { 14030 if ( this.options.disabled ) { 14031 return; 14032 } 14033 14034 // If this is the first time the menu is being opened, render the items 14035 if ( !this._rendered ) { 14036 this._refreshMenu(); 14037 } else { 14038 14039 // Menu clears focus on close, reset focus to selected item 14040 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" ); 14041 this.menuInstance.focus( null, this._getSelectedItem() ); 14042 } 14043 14044 // If there are no options, don't open the menu 14045 if ( !this.menuItems.length ) { 14046 return; 14047 } 14048 14049 this.isOpen = true; 14050 this._toggleAttr(); 14051 this._resizeMenu(); 14052 this._position(); 14053 14054 this._on( this.document, this._documentClick ); 14055 14056 this._trigger( "open", event ); 14057 }, 14058 14059 _position: function() { 14060 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); 14061 }, 14062 14063 close: function( event ) { 14064 if ( !this.isOpen ) { 14065 return; 14066 } 14067 14068 this.isOpen = false; 14069 this._toggleAttr(); 14070 14071 this.range = null; 14072 this._off( this.document ); 14073 14074 this._trigger( "close", event ); 14075 }, 14076 14077 widget: function() { 14078 return this.button; 14079 }, 14080 14081 menuWidget: function() { 14082 return this.menu; 14083 }, 14084 14085 _renderButtonItem: function( item ) { 14086 var buttonItem = $( "<span>" ); 14087 14088 this._setText( buttonItem, item.label ); 14089 this._addClass( buttonItem, "ui-selectmenu-text" ); 14090 14091 return buttonItem; 14092 }, 14093 14094 _renderMenu: function( ul, items ) { 14095 var that = this, 14096 currentOptgroup = ""; 14097 14098 $.each( items, function( index, item ) { 14099 var li; 14100 14101 if ( item.optgroup !== currentOptgroup ) { 14102 li = $( "<li>", { 14103 text: item.optgroup 14104 } ); 14105 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" + 14106 ( item.element.parent( "optgroup" ).prop( "disabled" ) ? 14107 " ui-state-disabled" : 14108 "" ) ); 14109 14110 li.appendTo( ul ); 14111 14112 currentOptgroup = item.optgroup; 14113 } 14114 14115 that._renderItemData( ul, item ); 14116 } ); 14117 }, 14118 14119 _renderItemData: function( ul, item ) { 14120 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); 14121 }, 14122 14123 _renderItem: function( ul, item ) { 14124 var li = $( "<li>" ), 14125 wrapper = $( "<div>", { 14126 title: item.element.attr( "title" ) 14127 } ); 14128 14129 if ( item.disabled ) { 14130 this._addClass( li, null, "ui-state-disabled" ); 14131 } 14132 this._setText( wrapper, item.label ); 14133 14134 return li.append( wrapper ).appendTo( ul ); 14135 }, 14136 14137 _setText: function( element, value ) { 14138 if ( value ) { 14139 element.text( value ); 14140 } else { 14141 element.html( " " ); 14142 } 14143 }, 14144 14145 _move: function( direction, event ) { 14146 var item, next, 14147 filter = ".ui-menu-item"; 14148 14149 if ( this.isOpen ) { 14150 item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14151 } else { 14152 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14153 filter += ":not(.ui-state-disabled)"; 14154 } 14155 14156 if ( direction === "first" || direction === "last" ) { 14157 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); 14158 } else { 14159 next = item[ direction + "All" ]( filter ).eq( 0 ); 14160 } 14161 14162 if ( next.length ) { 14163 this.menuInstance.focus( event, next ); 14164 } 14165 }, 14166 14167 _getSelectedItem: function() { 14168 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14169 }, 14170 14171 _toggle: function( event ) { 14172 this[ this.isOpen ? "close" : "open" ]( event ); 14173 }, 14174 14175 _setSelection: function() { 14176 var selection; 14177 14178 if ( !this.range ) { 14179 return; 14180 } 14181 14182 if ( window.getSelection ) { 14183 selection = window.getSelection(); 14184 selection.removeAllRanges(); 14185 selection.addRange( this.range ); 14186 14187 // Support: IE8 14188 } else { 14189 this.range.select(); 14190 } 14191 14192 // Support: IE 14193 // Setting the text selection kills the button focus in IE, but 14194 // restoring the focus doesn't kill the selection. 14195 this.button.focus(); 14196 }, 14197 14198 _documentClick: { 14199 mousedown: function( event ) { 14200 if ( !this.isOpen ) { 14201 return; 14202 } 14203 14204 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + 14205 $.ui.escapeSelector( this.ids.button ) ).length ) { 14206 this.close( event ); 14207 } 14208 } 14209 }, 14210 14211 _buttonEvents: { 14212 14213 // Prevent text selection from being reset when interacting with the selectmenu (#10144) 14214 mousedown: function() { 14215 var selection; 14216 14217 if ( window.getSelection ) { 14218 selection = window.getSelection(); 14219 if ( selection.rangeCount ) { 14220 this.range = selection.getRangeAt( 0 ); 14221 } 14222 14223 // Support: IE8 14224 } else { 14225 this.range = document.selection.createRange(); 14226 } 14227 }, 14228 14229 click: function( event ) { 14230 this._setSelection(); 14231 this._toggle( event ); 14232 }, 14233 14234 keydown: function( event ) { 14235 var preventDefault = true; 14236 switch ( event.keyCode ) { 14237 case $.ui.keyCode.TAB: 14238 case $.ui.keyCode.ESCAPE: 14239 this.close( event ); 14240 preventDefault = false; 14241 break; 14242 case $.ui.keyCode.ENTER: 14243 if ( this.isOpen ) { 14244 this._selectFocusedItem( event ); 14245 } 14246 break; 14247 case $.ui.keyCode.UP: 14248 if ( event.altKey ) { 14249 this._toggle( event ); 14250 } else { 14251 this._move( "prev", event ); 14252 } 14253 break; 14254 case $.ui.keyCode.DOWN: 14255 if ( event.altKey ) { 14256 this._toggle( event ); 14257 } else { 14258 this._move( "next", event ); 14259 } 14260 break; 14261 case $.ui.keyCode.SPACE: 14262 if ( this.isOpen ) { 14263 this._selectFocusedItem( event ); 14264 } else { 14265 this._toggle( event ); 14266 } 14267 break; 14268 case $.ui.keyCode.LEFT: 14269 this._move( "prev", event ); 14270 break; 14271 case $.ui.keyCode.RIGHT: 14272 this._move( "next", event ); 14273 break; 14274 case $.ui.keyCode.HOME: 14275 case $.ui.keyCode.PAGE_UP: 14276 this._move( "first", event ); 14277 break; 14278 case $.ui.keyCode.END: 14279 case $.ui.keyCode.PAGE_DOWN: 14280 this._move( "last", event ); 14281 break; 14282 default: 14283 this.menu.trigger( event ); 14284 preventDefault = false; 14285 } 14286 14287 if ( preventDefault ) { 14288 event.preventDefault(); 14289 } 14290 } 14291 }, 14292 14293 _selectFocusedItem: function( event ) { 14294 var item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14295 if ( !item.hasClass( "ui-state-disabled" ) ) { 14296 this._select( item.data( "ui-selectmenu-item" ), event ); 14297 } 14298 }, 14299 14300 _select: function( item, event ) { 14301 var oldIndex = this.element[ 0 ].selectedIndex; 14302 14303 // Change native select element 14304 this.element[ 0 ].selectedIndex = item.index; 14305 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) ); 14306 this._setAria( item ); 14307 this._trigger( "select", event, { item: item } ); 14308 14309 if ( item.index !== oldIndex ) { 14310 this._trigger( "change", event, { item: item } ); 14311 } 14312 14313 this.close( event ); 14314 }, 14315 14316 _setAria: function( item ) { 14317 var id = this.menuItems.eq( item.index ).attr( "id" ); 14318 14319 this.button.attr( { 14320 "aria-labelledby": id, 14321 "aria-activedescendant": id 14322 } ); 14323 this.menu.attr( "aria-activedescendant", id ); 14324 }, 14325 14326 _setOption: function( key, value ) { 14327 if ( key === "icons" ) { 14328 var icon = this.button.find( "span.ui-icon" ); 14329 this._removeClass( icon, null, this.options.icons.button ) 14330 ._addClass( icon, null, value.button ); 14331 } 14332 14333 this._super( key, value ); 14334 14335 if ( key === "appendTo" ) { 14336 this.menuWrap.appendTo( this._appendTo() ); 14337 } 14338 14339 if ( key === "width" ) { 14340 this._resizeButton(); 14341 } 14342 }, 14343 14344 _setOptionDisabled: function( value ) { 14345 this._super( value ); 14346 14347 this.menuInstance.option( "disabled", value ); 14348 this.button.attr( "aria-disabled", value ); 14349 this._toggleClass( this.button, null, "ui-state-disabled", value ); 14350 14351 this.element.prop( "disabled", value ); 14352 if ( value ) { 14353 this.button.attr( "tabindex", -1 ); 14354 this.close(); 14355 } else { 14356 this.button.attr( "tabindex", 0 ); 14357 } 14358 }, 14359 14360 _appendTo: function() { 14361 var element = this.options.appendTo; 14362 14363 if ( element ) { 14364 element = element.jquery || element.nodeType ? 14365 $( element ) : 14366 this.document.find( element ).eq( 0 ); 14367 } 14368 14369 if ( !element || !element[ 0 ] ) { 14370 element = this.element.closest( ".ui-front, dialog" ); 14371 } 14372 14373 if ( !element.length ) { 14374 element = this.document[ 0 ].body; 14375 } 14376 14377 return element; 14378 }, 14379 14380 _toggleAttr: function() { 14381 this.button.attr( "aria-expanded", this.isOpen ); 14382 14383 // We can't use two _toggleClass() calls here, because we need to make sure 14384 // we always remove classes first and add them second, otherwise if both classes have the 14385 // same theme class, it will be removed after we add it. 14386 this._removeClass( this.button, "ui-selectmenu-button-" + 14387 ( this.isOpen ? "closed" : "open" ) ) 14388 ._addClass( this.button, "ui-selectmenu-button-" + 14389 ( this.isOpen ? "open" : "closed" ) ) 14390 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen ); 14391 14392 this.menu.attr( "aria-hidden", !this.isOpen ); 14393 }, 14394 14395 _resizeButton: function() { 14396 var width = this.options.width; 14397 14398 // For `width: false`, just remove inline style and stop 14399 if ( width === false ) { 14400 this.button.css( "width", "" ); 14401 return; 14402 } 14403 14404 // For `width: null`, match the width of the original element 14405 if ( width === null ) { 14406 width = this.element.show().outerWidth(); 14407 this.element.hide(); 14408 } 14409 14410 this.button.outerWidth( width ); 14411 }, 14412 14413 _resizeMenu: function() { 14414 this.menu.outerWidth( Math.max( 14415 this.button.outerWidth(), 14416 14417 // Support: IE10 14418 // IE10 wraps long text (possibly a rounding bug) 14419 // so we add 1px to avoid the wrapping 14420 this.menu.width( "" ).outerWidth() + 1 14421 ) ); 14422 }, 14423 14424 _getCreateOptions: function() { 14425 var options = this._super(); 14426 14427 options.disabled = this.element.prop( "disabled" ); 14428 14429 return options; 14430 }, 14431 14432 _parseOptions: function( options ) { 14433 var that = this, 14434 data = []; 14435 options.each( function( index, item ) { 14436 data.push( that._parseOption( $( item ), index ) ); 14437 } ); 14438 this.items = data; 14439 }, 14440 14441 _parseOption: function( option, index ) { 14442 var optgroup = option.parent( "optgroup" ); 14443 14444 return { 14445 element: option, 14446 index: index, 14447 value: option.val(), 14448 label: option.text(), 14449 optgroup: optgroup.attr( "label" ) || "", 14450 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) 14451 }; 14452 }, 14453 14454 _destroy: function() { 14455 this._unbindFormResetHandler(); 14456 this.menuWrap.remove(); 14457 this.button.remove(); 14458 this.element.show(); 14459 this.element.removeUniqueId(); 14460 this.labels.attr( "for", this.ids.element ); 14461 } 14462 } ] ); 14463 14464 14465 /*! 14466 * jQuery UI Slider 1.12.1 14467 * http://jqueryui.com 14468 * 14469 * Copyright jQuery Foundation and other contributors 14470 * Released under the MIT license. 14471 * http://jquery.org/license 14472 */ 14473 14474 //>>label: Slider 14475 //>>group: Widgets 14476 //>>description: Displays a flexible slider with ranges and accessibility via keyboard. 14477 //>>docs: http://api.jqueryui.com/slider/ 14478 //>>demos: http://jqueryui.com/slider/ 14479 //>>css.structure: ../../themes/base/core.css 14480 //>>css.structure: ../../themes/base/slider.css 14481 //>>css.theme: ../../themes/base/theme.css 14482 14483 14484 14485 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, { 14486 version: "1.12.1", 14487 widgetEventPrefix: "slide", 14488 14489 options: { 14490 animate: false, 14491 classes: { 14492 "ui-slider": "ui-corner-all", 14493 "ui-slider-handle": "ui-corner-all", 14494 14495 // Note: ui-widget-header isn't the most fittingly semantic framework class for this 14496 // element, but worked best visually with a variety of themes 14497 "ui-slider-range": "ui-corner-all ui-widget-header" 14498 }, 14499 distance: 0, 14500 max: 100, 14501 min: 0, 14502 orientation: "horizontal", 14503 range: false, 14504 step: 1, 14505 value: 0, 14506 values: null, 14507 14508 // Callbacks 14509 change: null, 14510 slide: null, 14511 start: null, 14512 stop: null 14513 }, 14514 14515 // Number of pages in a slider 14516 // (how many times can you page up/down to go through the whole range) 14517 numPages: 5, 14518 14519 _create: function() { 14520 this._keySliding = false; 14521 this._mouseSliding = false; 14522 this._animateOff = true; 14523 this._handleIndex = null; 14524 this._detectOrientation(); 14525 this._mouseInit(); 14526 this._calculateNewMax(); 14527 14528 this._addClass( "ui-slider ui-slider-" + this.orientation, 14529 "ui-widget ui-widget-content" ); 14530 14531 this._refresh(); 14532 14533 this._animateOff = false; 14534 }, 14535 14536 _refresh: function() { 14537 this._createRange(); 14538 this._createHandles(); 14539 this._setupEvents(); 14540 this._refreshValue(); 14541 }, 14542 14543 _createHandles: function() { 14544 var i, handleCount, 14545 options = this.options, 14546 existingHandles = this.element.find( ".ui-slider-handle" ), 14547 handle = "<span tabindex='0'></span>", 14548 handles = []; 14549 14550 handleCount = ( options.values && options.values.length ) || 1; 14551 14552 if ( existingHandles.length > handleCount ) { 14553 existingHandles.slice( handleCount ).remove(); 14554 existingHandles = existingHandles.slice( 0, handleCount ); 14555 } 14556 14557 for ( i = existingHandles.length; i < handleCount; i++ ) { 14558 handles.push( handle ); 14559 } 14560 14561 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 14562 14563 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" ); 14564 14565 this.handle = this.handles.eq( 0 ); 14566 14567 this.handles.each( function( i ) { 14568 $( this ) 14569 .data( "ui-slider-handle-index", i ) 14570 .attr( "tabIndex", 0 ); 14571 } ); 14572 }, 14573 14574 _createRange: function() { 14575 var options = this.options; 14576 14577 if ( options.range ) { 14578 if ( options.range === true ) { 14579 if ( !options.values ) { 14580 options.values = [ this._valueMin(), this._valueMin() ]; 14581 } else if ( options.values.length && options.values.length !== 2 ) { 14582 options.values = [ options.values[ 0 ], options.values[ 0 ] ]; 14583 } else if ( $.isArray( options.values ) ) { 14584 options.values = options.values.slice( 0 ); 14585 } 14586 } 14587 14588 if ( !this.range || !this.range.length ) { 14589 this.range = $( "<div>" ) 14590 .appendTo( this.element ); 14591 14592 this._addClass( this.range, "ui-slider-range" ); 14593 } else { 14594 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" ); 14595 14596 // Handle range switching from true to min/max 14597 this.range.css( { 14598 "left": "", 14599 "bottom": "" 14600 } ); 14601 } 14602 if ( options.range === "min" || options.range === "max" ) { 14603 this._addClass( this.range, "ui-slider-range-" + options.range ); 14604 } 14605 } else { 14606 if ( this.range ) { 14607 this.range.remove(); 14608 } 14609 this.range = null; 14610 } 14611 }, 14612 14613 _setupEvents: function() { 14614 this._off( this.handles ); 14615 this._on( this.handles, this._handleEvents ); 14616 this._hoverable( this.handles ); 14617 this._focusable( this.handles ); 14618 }, 14619 14620 _destroy: function() { 14621 this.handles.remove(); 14622 if ( this.range ) { 14623 this.range.remove(); 14624 } 14625 14626 this._mouseDestroy(); 14627 }, 14628 14629 _mouseCapture: function( event ) { 14630 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 14631 that = this, 14632 o = this.options; 14633 14634 if ( o.disabled ) { 14635 return false; 14636 } 14637 14638 this.elementSize = { 14639 width: this.element.outerWidth(), 14640 height: this.element.outerHeight() 14641 }; 14642 this.elementOffset = this.element.offset(); 14643 14644 position = { x: event.pageX, y: event.pageY }; 14645 normValue = this._normValueFromMouse( position ); 14646 distance = this._valueMax() - this._valueMin() + 1; 14647 this.handles.each( function( i ) { 14648 var thisDistance = Math.abs( normValue - that.values( i ) ); 14649 if ( ( distance > thisDistance ) || 14650 ( distance === thisDistance && 14651 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) { 14652 distance = thisDistance; 14653 closestHandle = $( this ); 14654 index = i; 14655 } 14656 } ); 14657 14658 allowed = this._start( event, index ); 14659 if ( allowed === false ) { 14660 return false; 14661 } 14662 this._mouseSliding = true; 14663 14664 this._handleIndex = index; 14665 14666 this._addClass( closestHandle, null, "ui-state-active" ); 14667 closestHandle.trigger( "focus" ); 14668 14669 offset = closestHandle.offset(); 14670 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 14671 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 14672 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 14673 top: event.pageY - offset.top - 14674 ( closestHandle.height() / 2 ) - 14675 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) - 14676 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) + 14677 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 ) 14678 }; 14679 14680 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 14681 this._slide( event, index, normValue ); 14682 } 14683 this._animateOff = true; 14684 return true; 14685 }, 14686 14687 _mouseStart: function() { 14688 return true; 14689 }, 14690 14691 _mouseDrag: function( event ) { 14692 var position = { x: event.pageX, y: event.pageY }, 14693 normValue = this._normValueFromMouse( position ); 14694 14695 this._slide( event, this._handleIndex, normValue ); 14696 14697 return false; 14698 }, 14699 14700 _mouseStop: function( event ) { 14701 this._removeClass( this.handles, null, "ui-state-active" ); 14702 this._mouseSliding = false; 14703 14704 this._stop( event, this._handleIndex ); 14705 this._change( event, this._handleIndex ); 14706 14707 this._handleIndex = null; 14708 this._clickOffset = null; 14709 this._animateOff = false; 14710 14711 return false; 14712 }, 14713 14714 _detectOrientation: function() { 14715 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 14716 }, 14717 14718 _normValueFromMouse: function( position ) { 14719 var pixelTotal, 14720 pixelMouse, 14721 percentMouse, 14722 valueTotal, 14723 valueMouse; 14724 14725 if ( this.orientation === "horizontal" ) { 14726 pixelTotal = this.elementSize.width; 14727 pixelMouse = position.x - this.elementOffset.left - 14728 ( this._clickOffset ? this._clickOffset.left : 0 ); 14729 } else { 14730 pixelTotal = this.elementSize.height; 14731 pixelMouse = position.y - this.elementOffset.top - 14732 ( this._clickOffset ? this._clickOffset.top : 0 ); 14733 } 14734 14735 percentMouse = ( pixelMouse / pixelTotal ); 14736 if ( percentMouse > 1 ) { 14737 percentMouse = 1; 14738 } 14739 if ( percentMouse < 0 ) { 14740 percentMouse = 0; 14741 } 14742 if ( this.orientation === "vertical" ) { 14743 percentMouse = 1 - percentMouse; 14744 } 14745 14746 valueTotal = this._valueMax() - this._valueMin(); 14747 valueMouse = this._valueMin() + percentMouse * valueTotal; 14748 14749 return this._trimAlignValue( valueMouse ); 14750 }, 14751 14752 _uiHash: function( index, value, values ) { 14753 var uiHash = { 14754 handle: this.handles[ index ], 14755 handleIndex: index, 14756 value: value !== undefined ? value : this.value() 14757 }; 14758 14759 if ( this._hasMultipleValues() ) { 14760 uiHash.value = value !== undefined ? value : this.values( index ); 14761 uiHash.values = values || this.values(); 14762 } 14763 14764 return uiHash; 14765 }, 14766 14767 _hasMultipleValues: function() { 14768 return this.options.values && this.options.values.length; 14769 }, 14770 14771 _start: function( event, index ) { 14772 return this._trigger( "start", event, this._uiHash( index ) ); 14773 }, 14774 14775 _slide: function( event, index, newVal ) { 14776 var allowed, otherVal, 14777 currentValue = this.value(), 14778 newValues = this.values(); 14779 14780 if ( this._hasMultipleValues() ) { 14781 otherVal = this.values( index ? 0 : 1 ); 14782 currentValue = this.values( index ); 14783 14784 if ( this.options.values.length === 2 && this.options.range === true ) { 14785 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal ); 14786 } 14787 14788 newValues[ index ] = newVal; 14789 } 14790 14791 if ( newVal === currentValue ) { 14792 return; 14793 } 14794 14795 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) ); 14796 14797 // A slide can be canceled by returning false from the slide callback 14798 if ( allowed === false ) { 14799 return; 14800 } 14801 14802 if ( this._hasMultipleValues() ) { 14803 this.values( index, newVal ); 14804 } else { 14805 this.value( newVal ); 14806 } 14807 }, 14808 14809 _stop: function( event, index ) { 14810 this._trigger( "stop", event, this._uiHash( index ) ); 14811 }, 14812 14813 _change: function( event, index ) { 14814 if ( !this._keySliding && !this._mouseSliding ) { 14815 14816 //store the last changed value index for reference when handles overlap 14817 this._lastChangedValue = index; 14818 this._trigger( "change", event, this._uiHash( index ) ); 14819 } 14820 }, 14821 14822 value: function( newValue ) { 14823 if ( arguments.length ) { 14824 this.options.value = this._trimAlignValue( newValue ); 14825 this._refreshValue(); 14826 this._change( null, 0 ); 14827 return; 14828 } 14829 14830 return this._value(); 14831 }, 14832 14833 values: function( index, newValue ) { 14834 var vals, 14835 newValues, 14836 i; 14837 14838 if ( arguments.length > 1 ) { 14839 this.options.values[ index ] = this._trimAlignValue( newValue ); 14840 this._refreshValue(); 14841 this._change( null, index ); 14842 return; 14843 } 14844 14845 if ( arguments.length ) { 14846 if ( $.isArray( arguments[ 0 ] ) ) { 14847 vals = this.options.values; 14848 newValues = arguments[ 0 ]; 14849 for ( i = 0; i < vals.length; i += 1 ) { 14850 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 14851 this._change( null, i ); 14852 } 14853 this._refreshValue(); 14854 } else { 14855 if ( this._hasMultipleValues() ) { 14856 return this._values( index ); 14857 } else { 14858 return this.value(); 14859 } 14860 } 14861 } else { 14862 return this._values(); 14863 } 14864 }, 14865 14866 _setOption: function( key, value ) { 14867 var i, 14868 valsLength = 0; 14869 14870 if ( key === "range" && this.options.range === true ) { 14871 if ( value === "min" ) { 14872 this.options.value = this._values( 0 ); 14873 this.options.values = null; 14874 } else if ( value === "max" ) { 14875 this.options.value = this._values( this.options.values.length - 1 ); 14876 this.options.values = null; 14877 } 14878 } 14879 14880 if ( $.isArray( this.options.values ) ) { 14881 valsLength = this.options.values.length; 14882 } 14883 14884 this._super( key, value ); 14885 14886 switch ( key ) { 14887 case "orientation": 14888 this._detectOrientation(); 14889 this._removeClass( "ui-slider-horizontal ui-slider-vertical" ) 14890 ._addClass( "ui-slider-" + this.orientation ); 14891 this._refreshValue(); 14892 if ( this.options.range ) { 14893 this._refreshRange( value ); 14894 } 14895 14896 // Reset positioning from previous orientation 14897 this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); 14898 break; 14899 case "value": 14900 this._animateOff = true; 14901 this._refreshValue(); 14902 this._change( null, 0 ); 14903 this._animateOff = false; 14904 break; 14905 case "values": 14906 this._animateOff = true; 14907 this._refreshValue(); 14908 14909 // Start from the last handle to prevent unreachable handles (#9046) 14910 for ( i = valsLength - 1; i >= 0; i-- ) { 14911 this._change( null, i ); 14912 } 14913 this._animateOff = false; 14914 break; 14915 case "step": 14916 case "min": 14917 case "max": 14918 this._animateOff = true; 14919 this._calculateNewMax(); 14920 this._refreshValue(); 14921 this._animateOff = false; 14922 break; 14923 case "range": 14924 this._animateOff = true; 14925 this._refresh(); 14926 this._animateOff = false; 14927 break; 14928 } 14929 }, 14930 14931 _setOptionDisabled: function( value ) { 14932 this._super( value ); 14933 14934 this._toggleClass( null, "ui-state-disabled", !!value ); 14935 }, 14936 14937 //internal value getter 14938 // _value() returns value trimmed by min and max, aligned by step 14939 _value: function() { 14940 var val = this.options.value; 14941 val = this._trimAlignValue( val ); 14942 14943 return val; 14944 }, 14945 14946 //internal values getter 14947 // _values() returns array of values trimmed by min and max, aligned by step 14948 // _values( index ) returns single value trimmed by min and max, aligned by step 14949 _values: function( index ) { 14950 var val, 14951 vals, 14952 i; 14953 14954 if ( arguments.length ) { 14955 val = this.options.values[ index ]; 14956 val = this._trimAlignValue( val ); 14957 14958 return val; 14959 } else if ( this._hasMultipleValues() ) { 14960 14961 // .slice() creates a copy of the array 14962 // this copy gets trimmed by min and max and then returned 14963 vals = this.options.values.slice(); 14964 for ( i = 0; i < vals.length; i += 1 ) { 14965 vals[ i ] = this._trimAlignValue( vals[ i ] ); 14966 } 14967 14968 return vals; 14969 } else { 14970 return []; 14971 } 14972 }, 14973 14974 // Returns the step-aligned value that val is closest to, between (inclusive) min and max 14975 _trimAlignValue: function( val ) { 14976 if ( val <= this._valueMin() ) { 14977 return this._valueMin(); 14978 } 14979 if ( val >= this._valueMax() ) { 14980 return this._valueMax(); 14981 } 14982 var step = ( this.options.step > 0 ) ? this.options.step : 1, 14983 valModStep = ( val - this._valueMin() ) % step, 14984 alignValue = val - valModStep; 14985 14986 if ( Math.abs( valModStep ) * 2 >= step ) { 14987 alignValue += ( valModStep > 0 ) ? step : ( -step ); 14988 } 14989 14990 // Since JavaScript has problems with large floats, round 14991 // the final value to 5 digits after the decimal point (see #4124) 14992 return parseFloat( alignValue.toFixed( 5 ) ); 14993 }, 14994 14995 _calculateNewMax: function() { 14996 var max = this.options.max, 14997 min = this._valueMin(), 14998 step = this.options.step, 14999 aboveMin = Math.round( ( max - min ) / step ) * step; 15000 max = aboveMin + min; 15001 if ( max > this.options.max ) { 15002 15003 //If max is not divisible by step, rounding off may increase its value 15004 max -= step; 15005 } 15006 this.max = parseFloat( max.toFixed( this._precision() ) ); 15007 }, 15008 15009 _precision: function() { 15010 var precision = this._precisionOf( this.options.step ); 15011 if ( this.options.min !== null ) { 15012 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 15013 } 15014 return precision; 15015 }, 15016 15017 _precisionOf: function( num ) { 15018 var str = num.toString(), 15019 decimal = str.indexOf( "." ); 15020 return decimal === -1 ? 0 : str.length - decimal - 1; 15021 }, 15022 15023 _valueMin: function() { 15024 return this.options.min; 15025 }, 15026 15027 _valueMax: function() { 15028 return this.max; 15029 }, 15030 15031 _refreshRange: function( orientation ) { 15032 if ( orientation === "vertical" ) { 15033 this.range.css( { "width": "", "left": "" } ); 15034 } 15035 if ( orientation === "horizontal" ) { 15036 this.range.css( { "height": "", "bottom": "" } ); 15037 } 15038 }, 15039 15040 _refreshValue: function() { 15041 var lastValPercent, valPercent, value, valueMin, valueMax, 15042 oRange = this.options.range, 15043 o = this.options, 15044 that = this, 15045 animate = ( !this._animateOff ) ? o.animate : false, 15046 _set = {}; 15047 15048 if ( this._hasMultipleValues() ) { 15049 this.handles.each( function( i ) { 15050 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() - 15051 that._valueMin() ) * 100; 15052 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15053 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15054 if ( that.options.range === true ) { 15055 if ( that.orientation === "horizontal" ) { 15056 if ( i === 0 ) { 15057 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15058 left: valPercent + "%" 15059 }, o.animate ); 15060 } 15061 if ( i === 1 ) { 15062 that.range[ animate ? "animate" : "css" ]( { 15063 width: ( valPercent - lastValPercent ) + "%" 15064 }, { 15065 queue: false, 15066 duration: o.animate 15067 } ); 15068 } 15069 } else { 15070 if ( i === 0 ) { 15071 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15072 bottom: ( valPercent ) + "%" 15073 }, o.animate ); 15074 } 15075 if ( i === 1 ) { 15076 that.range[ animate ? "animate" : "css" ]( { 15077 height: ( valPercent - lastValPercent ) + "%" 15078 }, { 15079 queue: false, 15080 duration: o.animate 15081 } ); 15082 } 15083 } 15084 } 15085 lastValPercent = valPercent; 15086 } ); 15087 } else { 15088 value = this.value(); 15089 valueMin = this._valueMin(); 15090 valueMax = this._valueMax(); 15091 valPercent = ( valueMax !== valueMin ) ? 15092 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 15093 0; 15094 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15095 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15096 15097 if ( oRange === "min" && this.orientation === "horizontal" ) { 15098 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15099 width: valPercent + "%" 15100 }, o.animate ); 15101 } 15102 if ( oRange === "max" && this.orientation === "horizontal" ) { 15103 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15104 width: ( 100 - valPercent ) + "%" 15105 }, o.animate ); 15106 } 15107 if ( oRange === "min" && this.orientation === "vertical" ) { 15108 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15109 height: valPercent + "%" 15110 }, o.animate ); 15111 } 15112 if ( oRange === "max" && this.orientation === "vertical" ) { 15113 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15114 height: ( 100 - valPercent ) + "%" 15115 }, o.animate ); 15116 } 15117 } 15118 }, 15119 15120 _handleEvents: { 15121 keydown: function( event ) { 15122 var allowed, curVal, newVal, step, 15123 index = $( event.target ).data( "ui-slider-handle-index" ); 15124 15125 switch ( event.keyCode ) { 15126 case $.ui.keyCode.HOME: 15127 case $.ui.keyCode.END: 15128 case $.ui.keyCode.PAGE_UP: 15129 case $.ui.keyCode.PAGE_DOWN: 15130 case $.ui.keyCode.UP: 15131 case $.ui.keyCode.RIGHT: 15132 case $.ui.keyCode.DOWN: 15133 case $.ui.keyCode.LEFT: 15134 event.preventDefault(); 15135 if ( !this._keySliding ) { 15136 this._keySliding = true; 15137 this._addClass( $( event.target ), null, "ui-state-active" ); 15138 allowed = this._start( event, index ); 15139 if ( allowed === false ) { 15140 return; 15141 } 15142 } 15143 break; 15144 } 15145 15146 step = this.options.step; 15147 if ( this._hasMultipleValues() ) { 15148 curVal = newVal = this.values( index ); 15149 } else { 15150 curVal = newVal = this.value(); 15151 } 15152 15153 switch ( event.keyCode ) { 15154 case $.ui.keyCode.HOME: 15155 newVal = this._valueMin(); 15156 break; 15157 case $.ui.keyCode.END: 15158 newVal = this._valueMax(); 15159 break; 15160 case $.ui.keyCode.PAGE_UP: 15161 newVal = this._trimAlignValue( 15162 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) 15163 ); 15164 break; 15165 case $.ui.keyCode.PAGE_DOWN: 15166 newVal = this._trimAlignValue( 15167 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); 15168 break; 15169 case $.ui.keyCode.UP: 15170 case $.ui.keyCode.RIGHT: 15171 if ( curVal === this._valueMax() ) { 15172 return; 15173 } 15174 newVal = this._trimAlignValue( curVal + step ); 15175 break; 15176 case $.ui.keyCode.DOWN: 15177 case $.ui.keyCode.LEFT: 15178 if ( curVal === this._valueMin() ) { 15179 return; 15180 } 15181 newVal = this._trimAlignValue( curVal - step ); 15182 break; 15183 } 15184 15185 this._slide( event, index, newVal ); 15186 }, 15187 keyup: function( event ) { 15188 var index = $( event.target ).data( "ui-slider-handle-index" ); 15189 15190 if ( this._keySliding ) { 15191 this._keySliding = false; 15192 this._stop( event, index ); 15193 this._change( event, index ); 15194 this._removeClass( $( event.target ), null, "ui-state-active" ); 15195 } 15196 } 15197 } 15198 } ); 15199 15200 15201 /*! 15202 * jQuery UI Sortable 1.12.1 15203 * http://jqueryui.com 15204 * 15205 * Copyright jQuery Foundation and other contributors 15206 * Released under the MIT license. 15207 * http://jquery.org/license 15208 */ 15209 15210 //>>label: Sortable 15211 //>>group: Interactions 15212 //>>description: Enables items in a list to be sorted using the mouse. 15213 //>>docs: http://api.jqueryui.com/sortable/ 15214 //>>demos: http://jqueryui.com/sortable/ 15215 //>>css.structure: ../../themes/base/sortable.css 15216 15217 15218 15219 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, { 15220 version: "1.12.1", 15221 widgetEventPrefix: "sort", 15222 ready: false, 15223 options: { 15224 appendTo: "parent", 15225 axis: false, 15226 connectWith: false, 15227 containment: false, 15228 cursor: "auto", 15229 cursorAt: false, 15230 dropOnEmpty: true, 15231 forcePlaceholderSize: false, 15232 forceHelperSize: false, 15233 grid: false, 15234 handle: false, 15235 helper: "original", 15236 items: "> *", 15237 opacity: false, 15238 placeholder: false, 15239 revert: false, 15240 scroll: true, 15241 scrollSensitivity: 20, 15242 scrollSpeed: 20, 15243 scope: "default", 15244 tolerance: "intersect", 15245 zIndex: 1000, 15246 15247 // Callbacks 15248 activate: null, 15249 beforeStop: null, 15250 change: null, 15251 deactivate: null, 15252 out: null, 15253 over: null, 15254 receive: null, 15255 remove: null, 15256 sort: null, 15257 start: null, 15258 stop: null, 15259 update: null 15260 }, 15261 15262 _isOverAxis: function( x, reference, size ) { 15263 return ( x >= reference ) && ( x < ( reference + size ) ); 15264 }, 15265 15266 _isFloating: function( item ) { 15267 return ( /left|right/ ).test( item.css( "float" ) ) || 15268 ( /inline|table-cell/ ).test( item.css( "display" ) ); 15269 }, 15270 15271 _create: function() { 15272 this.containerCache = {}; 15273 this._addClass( "ui-sortable" ); 15274 15275 //Get the items 15276 this.refresh(); 15277 15278 //Let's determine the parent's offset 15279 this.offset = this.element.offset(); 15280 15281 //Initialize mouse events for interaction 15282 this._mouseInit(); 15283 15284 this._setHandleClassName(); 15285 15286 //We're ready to go 15287 this.ready = true; 15288 15289 }, 15290 15291 _setOption: function( key, value ) { 15292 this._super( key, value ); 15293 15294 if ( key === "handle" ) { 15295 this._setHandleClassName(); 15296 } 15297 }, 15298 15299 _setHandleClassName: function() { 15300 var that = this; 15301 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" ); 15302 $.each( this.items, function() { 15303 that._addClass( 15304 this.instance.options.handle ? 15305 this.item.find( this.instance.options.handle ) : 15306 this.item, 15307 "ui-sortable-handle" 15308 ); 15309 } ); 15310 }, 15311 15312 _destroy: function() { 15313 this._mouseDestroy(); 15314 15315 for ( var i = this.items.length - 1; i >= 0; i-- ) { 15316 this.items[ i ].item.removeData( this.widgetName + "-item" ); 15317 } 15318 15319 return this; 15320 }, 15321 15322 _mouseCapture: function( event, overrideHandle ) { 15323 var currentItem = null, 15324 validHandle = false, 15325 that = this; 15326 15327 if ( this.reverting ) { 15328 return false; 15329 } 15330 15331 if ( this.options.disabled || this.options.type === "static" ) { 15332 return false; 15333 } 15334 15335 //We have to refresh the items data once first 15336 this._refreshItems( event ); 15337 15338 //Find out if the clicked node (or one of its parents) is a actual item in this.items 15339 $( event.target ).parents().each( function() { 15340 if ( $.data( this, that.widgetName + "-item" ) === that ) { 15341 currentItem = $( this ); 15342 return false; 15343 } 15344 } ); 15345 if ( $.data( event.target, that.widgetName + "-item" ) === that ) { 15346 currentItem = $( event.target ); 15347 } 15348 15349 if ( !currentItem ) { 15350 return false; 15351 } 15352 if ( this.options.handle && !overrideHandle ) { 15353 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() { 15354 if ( this === event.target ) { 15355 validHandle = true; 15356 } 15357 } ); 15358 if ( !validHandle ) { 15359 return false; 15360 } 15361 } 15362 15363 this.currentItem = currentItem; 15364 this._removeCurrentsFromItems(); 15365 return true; 15366 15367 }, 15368 15369 _mouseStart: function( event, overrideHandle, noActivation ) { 15370 15371 var i, body, 15372 o = this.options; 15373 15374 this.currentContainer = this; 15375 15376 //We only need to call refreshPositions, because the refreshItems call has been moved to 15377 // mouseCapture 15378 this.refreshPositions(); 15379 15380 //Create and append the visible helper 15381 this.helper = this._createHelper( event ); 15382 15383 //Cache the helper size 15384 this._cacheHelperProportions(); 15385 15386 /* 15387 * - Position generation - 15388 * This block generates everything position related - it's the core of draggables. 15389 */ 15390 15391 //Cache the margins of the original element 15392 this._cacheMargins(); 15393 15394 //Get the next scrolling parent 15395 this.scrollParent = this.helper.scrollParent(); 15396 15397 //The element's absolute position on the page minus margins 15398 this.offset = this.currentItem.offset(); 15399 this.offset = { 15400 top: this.offset.top - this.margins.top, 15401 left: this.offset.left - this.margins.left 15402 }; 15403 15404 $.extend( this.offset, { 15405 click: { //Where the click happened, relative to the element 15406 left: event.pageX - this.offset.left, 15407 top: event.pageY - this.offset.top 15408 }, 15409 parent: this._getParentOffset(), 15410 15411 // This is a relative to absolute position minus the actual position calculation - 15412 // only used for relative positioned helper 15413 relative: this._getRelativeOffset() 15414 } ); 15415 15416 // Only after we got the offset, we can change the helper's position to absolute 15417 // TODO: Still need to figure out a way to make relative sorting possible 15418 this.helper.css( "position", "absolute" ); 15419 this.cssPosition = this.helper.css( "position" ); 15420 15421 //Generate the original position 15422 this.originalPosition = this._generatePosition( event ); 15423 this.originalPageX = event.pageX; 15424 this.originalPageY = event.pageY; 15425 15426 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 15427 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) ); 15428 15429 //Cache the former DOM position 15430 this.domPosition = { 15431 prev: this.currentItem.prev()[ 0 ], 15432 parent: this.currentItem.parent()[ 0 ] 15433 }; 15434 15435 // If the helper is not the original, hide the original so it's not playing any role during 15436 // the drag, won't cause anything bad this way 15437 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 15438 this.currentItem.hide(); 15439 } 15440 15441 //Create the placeholder 15442 this._createPlaceholder(); 15443 15444 //Set a containment if given in the options 15445 if ( o.containment ) { 15446 this._setContainment(); 15447 } 15448 15449 if ( o.cursor && o.cursor !== "auto" ) { // cursor option 15450 body = this.document.find( "body" ); 15451 15452 // Support: IE 15453 this.storedCursor = body.css( "cursor" ); 15454 body.css( "cursor", o.cursor ); 15455 15456 this.storedStylesheet = 15457 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body ); 15458 } 15459 15460 if ( o.opacity ) { // opacity option 15461 if ( this.helper.css( "opacity" ) ) { 15462 this._storedOpacity = this.helper.css( "opacity" ); 15463 } 15464 this.helper.css( "opacity", o.opacity ); 15465 } 15466 15467 if ( o.zIndex ) { // zIndex option 15468 if ( this.helper.css( "zIndex" ) ) { 15469 this._storedZIndex = this.helper.css( "zIndex" ); 15470 } 15471 this.helper.css( "zIndex", o.zIndex ); 15472 } 15473 15474 //Prepare scrolling 15475 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15476 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15477 this.overflowOffset = this.scrollParent.offset(); 15478 } 15479 15480 //Call callbacks 15481 this._trigger( "start", event, this._uiHash() ); 15482 15483 //Recache the helper size 15484 if ( !this._preserveHelperProportions ) { 15485 this._cacheHelperProportions(); 15486 } 15487 15488 //Post "activate" events to possible containers 15489 if ( !noActivation ) { 15490 for ( i = this.containers.length - 1; i >= 0; i-- ) { 15491 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 15492 } 15493 } 15494 15495 //Prepare possible droppables 15496 if ( $.ui.ddmanager ) { 15497 $.ui.ddmanager.current = this; 15498 } 15499 15500 if ( $.ui.ddmanager && !o.dropBehaviour ) { 15501 $.ui.ddmanager.prepareOffsets( this, event ); 15502 } 15503 15504 this.dragging = true; 15505 15506 this._addClass( this.helper, "ui-sortable-helper" ); 15507 15508 // Execute the drag once - this causes the helper not to be visiblebefore getting its 15509 // correct position 15510 this._mouseDrag( event ); 15511 return true; 15512 15513 }, 15514 15515 _mouseDrag: function( event ) { 15516 var i, item, itemElement, intersection, 15517 o = this.options, 15518 scrolled = false; 15519 15520 //Compute the helpers position 15521 this.position = this._generatePosition( event ); 15522 this.positionAbs = this._convertPositionTo( "absolute" ); 15523 15524 if ( !this.lastPositionAbs ) { 15525 this.lastPositionAbs = this.positionAbs; 15526 } 15527 15528 //Do scrolling 15529 if ( this.options.scroll ) { 15530 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15531 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15532 15533 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) - 15534 event.pageY < o.scrollSensitivity ) { 15535 this.scrollParent[ 0 ].scrollTop = 15536 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed; 15537 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) { 15538 this.scrollParent[ 0 ].scrollTop = 15539 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed; 15540 } 15541 15542 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) - 15543 event.pageX < o.scrollSensitivity ) { 15544 this.scrollParent[ 0 ].scrollLeft = scrolled = 15545 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed; 15546 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) { 15547 this.scrollParent[ 0 ].scrollLeft = scrolled = 15548 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed; 15549 } 15550 15551 } else { 15552 15553 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) { 15554 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed ); 15555 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) < 15556 o.scrollSensitivity ) { 15557 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed ); 15558 } 15559 15560 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) { 15561 scrolled = this.document.scrollLeft( 15562 this.document.scrollLeft() - o.scrollSpeed 15563 ); 15564 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) < 15565 o.scrollSensitivity ) { 15566 scrolled = this.document.scrollLeft( 15567 this.document.scrollLeft() + o.scrollSpeed 15568 ); 15569 } 15570 15571 } 15572 15573 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 15574 $.ui.ddmanager.prepareOffsets( this, event ); 15575 } 15576 } 15577 15578 //Regenerate the absolute position used for position checks 15579 this.positionAbs = this._convertPositionTo( "absolute" ); 15580 15581 //Set the helper position 15582 if ( !this.options.axis || this.options.axis !== "y" ) { 15583 this.helper[ 0 ].style.left = this.position.left + "px"; 15584 } 15585 if ( !this.options.axis || this.options.axis !== "x" ) { 15586 this.helper[ 0 ].style.top = this.position.top + "px"; 15587 } 15588 15589 //Rearrange 15590 for ( i = this.items.length - 1; i >= 0; i-- ) { 15591 15592 //Cache variables and intersection, continue if no intersection 15593 item = this.items[ i ]; 15594 itemElement = item.item[ 0 ]; 15595 intersection = this._intersectsWithPointer( item ); 15596 if ( !intersection ) { 15597 continue; 15598 } 15599 15600 // Only put the placeholder inside the current Container, skip all 15601 // items from other containers. This works because when moving 15602 // an item from one container to another the 15603 // currentContainer is switched before the placeholder is moved. 15604 // 15605 // Without this, moving items in "sub-sortables" can cause 15606 // the placeholder to jitter between the outer and inner container. 15607 if ( item.instance !== this.currentContainer ) { 15608 continue; 15609 } 15610 15611 // Cannot intersect with itself 15612 // no useless actions that have been done before 15613 // no action if the item moved is the parent of the item checked 15614 if ( itemElement !== this.currentItem[ 0 ] && 15615 this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement && 15616 !$.contains( this.placeholder[ 0 ], itemElement ) && 15617 ( this.options.type === "semi-dynamic" ? 15618 !$.contains( this.element[ 0 ], itemElement ) : 15619 true 15620 ) 15621 ) { 15622 15623 this.direction = intersection === 1 ? "down" : "up"; 15624 15625 if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) { 15626 this._rearrange( event, item ); 15627 } else { 15628 break; 15629 } 15630 15631 this._trigger( "change", event, this._uiHash() ); 15632 break; 15633 } 15634 } 15635 15636 //Post events to containers 15637 this._contactContainers( event ); 15638 15639 //Interconnect with droppables 15640 if ( $.ui.ddmanager ) { 15641 $.ui.ddmanager.drag( this, event ); 15642 } 15643 15644 //Call callbacks 15645 this._trigger( "sort", event, this._uiHash() ); 15646 15647 this.lastPositionAbs = this.positionAbs; 15648 return false; 15649 15650 }, 15651 15652 _mouseStop: function( event, noPropagation ) { 15653 15654 if ( !event ) { 15655 return; 15656 } 15657 15658 //If we are using droppables, inform the manager about the drop 15659 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 15660 $.ui.ddmanager.drop( this, event ); 15661 } 15662 15663 if ( this.options.revert ) { 15664 var that = this, 15665 cur = this.placeholder.offset(), 15666 axis = this.options.axis, 15667 animation = {}; 15668 15669 if ( !axis || axis === "x" ) { 15670 animation.left = cur.left - this.offset.parent.left - this.margins.left + 15671 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15672 0 : 15673 this.offsetParent[ 0 ].scrollLeft 15674 ); 15675 } 15676 if ( !axis || axis === "y" ) { 15677 animation.top = cur.top - this.offset.parent.top - this.margins.top + 15678 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15679 0 : 15680 this.offsetParent[ 0 ].scrollTop 15681 ); 15682 } 15683 this.reverting = true; 15684 $( this.helper ).animate( 15685 animation, 15686 parseInt( this.options.revert, 10 ) || 500, 15687 function() { 15688 that._clear( event ); 15689 } 15690 ); 15691 } else { 15692 this._clear( event, noPropagation ); 15693 } 15694 15695 return false; 15696 15697 }, 15698 15699 cancel: function() { 15700 15701 if ( this.dragging ) { 15702 15703 this._mouseUp( new $.Event( "mouseup", { target: null } ) ); 15704 15705 if ( this.options.helper === "original" ) { 15706 this.currentItem.css( this._storedCSS ); 15707 this._removeClass( this.currentItem, "ui-sortable-helper" ); 15708 } else { 15709 this.currentItem.show(); 15710 } 15711 15712 //Post deactivating events to containers 15713 for ( var i = this.containers.length - 1; i >= 0; i-- ) { 15714 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) ); 15715 if ( this.containers[ i ].containerCache.over ) { 15716 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) ); 15717 this.containers[ i ].containerCache.over = 0; 15718 } 15719 } 15720 15721 } 15722 15723 if ( this.placeholder ) { 15724 15725 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 15726 // it unbinds ALL events from the original node! 15727 if ( this.placeholder[ 0 ].parentNode ) { 15728 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 15729 } 15730 if ( this.options.helper !== "original" && this.helper && 15731 this.helper[ 0 ].parentNode ) { 15732 this.helper.remove(); 15733 } 15734 15735 $.extend( this, { 15736 helper: null, 15737 dragging: false, 15738 reverting: false, 15739 _noFinalSort: null 15740 } ); 15741 15742 if ( this.domPosition.prev ) { 15743 $( this.domPosition.prev ).after( this.currentItem ); 15744 } else { 15745 $( this.domPosition.parent ).prepend( this.currentItem ); 15746 } 15747 } 15748 15749 return this; 15750 15751 }, 15752 15753 serialize: function( o ) { 15754 15755 var items = this._getItemsAsjQuery( o && o.connected ), 15756 str = []; 15757 o = o || {}; 15758 15759 $( items ).each( function() { 15760 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" ) 15761 .match( o.expression || ( /(.+)[\-=_](.+)/ ) ); 15762 if ( res ) { 15763 str.push( 15764 ( o.key || res[ 1 ] + "[]" ) + 15765 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) ); 15766 } 15767 } ); 15768 15769 if ( !str.length && o.key ) { 15770 str.push( o.key + "=" ); 15771 } 15772 15773 return str.join( "&" ); 15774 15775 }, 15776 15777 toArray: function( o ) { 15778 15779 var items = this._getItemsAsjQuery( o && o.connected ), 15780 ret = []; 15781 15782 o = o || {}; 15783 15784 items.each( function() { 15785 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" ); 15786 } ); 15787 return ret; 15788 15789 }, 15790 15791 /* Be careful with the following core functions */ 15792 _intersectsWith: function( item ) { 15793 15794 var x1 = this.positionAbs.left, 15795 x2 = x1 + this.helperProportions.width, 15796 y1 = this.positionAbs.top, 15797 y2 = y1 + this.helperProportions.height, 15798 l = item.left, 15799 r = l + item.width, 15800 t = item.top, 15801 b = t + item.height, 15802 dyClick = this.offset.click.top, 15803 dxClick = this.offset.click.left, 15804 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && 15805 ( y1 + dyClick ) < b ), 15806 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && 15807 ( x1 + dxClick ) < r ), 15808 isOverElement = isOverElementHeight && isOverElementWidth; 15809 15810 if ( this.options.tolerance === "pointer" || 15811 this.options.forcePointerForContainers || 15812 ( this.options.tolerance !== "pointer" && 15813 this.helperProportions[ this.floating ? "width" : "height" ] > 15814 item[ this.floating ? "width" : "height" ] ) 15815 ) { 15816 return isOverElement; 15817 } else { 15818 15819 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half 15820 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half 15821 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half 15822 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half 15823 15824 } 15825 }, 15826 15827 _intersectsWithPointer: function( item ) { 15828 var verticalDirection, horizontalDirection, 15829 isOverElementHeight = ( this.options.axis === "x" ) || 15830 this._isOverAxis( 15831 this.positionAbs.top + this.offset.click.top, item.top, item.height ), 15832 isOverElementWidth = ( this.options.axis === "y" ) || 15833 this._isOverAxis( 15834 this.positionAbs.left + this.offset.click.left, item.left, item.width ), 15835 isOverElement = isOverElementHeight && isOverElementWidth; 15836 15837 if ( !isOverElement ) { 15838 return false; 15839 } 15840 15841 verticalDirection = this._getDragVerticalDirection(); 15842 horizontalDirection = this._getDragHorizontalDirection(); 15843 15844 return this.floating ? 15845 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) 15846 : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) ); 15847 15848 }, 15849 15850 _intersectsWithSides: function( item ) { 15851 15852 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top + 15853 this.offset.click.top, item.top + ( item.height / 2 ), item.height ), 15854 isOverRightHalf = this._isOverAxis( this.positionAbs.left + 15855 this.offset.click.left, item.left + ( item.width / 2 ), item.width ), 15856 verticalDirection = this._getDragVerticalDirection(), 15857 horizontalDirection = this._getDragHorizontalDirection(); 15858 15859 if ( this.floating && horizontalDirection ) { 15860 return ( ( horizontalDirection === "right" && isOverRightHalf ) || 15861 ( horizontalDirection === "left" && !isOverRightHalf ) ); 15862 } else { 15863 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) || 15864 ( verticalDirection === "up" && !isOverBottomHalf ) ); 15865 } 15866 15867 }, 15868 15869 _getDragVerticalDirection: function() { 15870 var delta = this.positionAbs.top - this.lastPositionAbs.top; 15871 return delta !== 0 && ( delta > 0 ? "down" : "up" ); 15872 }, 15873 15874 _getDragHorizontalDirection: function() { 15875 var delta = this.positionAbs.left - this.lastPositionAbs.left; 15876 return delta !== 0 && ( delta > 0 ? "right" : "left" ); 15877 }, 15878 15879 refresh: function( event ) { 15880 this._refreshItems( event ); 15881 this._setHandleClassName(); 15882 this.refreshPositions(); 15883 return this; 15884 }, 15885 15886 _connectWith: function() { 15887 var options = this.options; 15888 return options.connectWith.constructor === String ? 15889 [ options.connectWith ] : 15890 options.connectWith; 15891 }, 15892 15893 _getItemsAsjQuery: function( connected ) { 15894 15895 var i, j, cur, inst, 15896 items = [], 15897 queries = [], 15898 connectWith = this._connectWith(); 15899 15900 if ( connectWith && connected ) { 15901 for ( i = connectWith.length - 1; i >= 0; i-- ) { 15902 cur = $( connectWith[ i ], this.document[ 0 ] ); 15903 for ( j = cur.length - 1; j >= 0; j-- ) { 15904 inst = $.data( cur[ j ], this.widgetFullName ); 15905 if ( inst && inst !== this && !inst.options.disabled ) { 15906 queries.push( [ $.isFunction( inst.options.items ) ? 15907 inst.options.items.call( inst.element ) : 15908 $( inst.options.items, inst.element ) 15909 .not( ".ui-sortable-helper" ) 15910 .not( ".ui-sortable-placeholder" ), inst ] ); 15911 } 15912 } 15913 } 15914 } 15915 15916 queries.push( [ $.isFunction( this.options.items ) ? 15917 this.options.items 15918 .call( this.element, null, { options: this.options, item: this.currentItem } ) : 15919 $( this.options.items, this.element ) 15920 .not( ".ui-sortable-helper" ) 15921 .not( ".ui-sortable-placeholder" ), this ] ); 15922 15923 function addItems() { 15924 items.push( this ); 15925 } 15926 for ( i = queries.length - 1; i >= 0; i-- ) { 15927 queries[ i ][ 0 ].each( addItems ); 15928 } 15929 15930 return $( items ); 15931 15932 }, 15933 15934 _removeCurrentsFromItems: function() { 15935 15936 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" ); 15937 15938 this.items = $.grep( this.items, function( item ) { 15939 for ( var j = 0; j < list.length; j++ ) { 15940 if ( list[ j ] === item.item[ 0 ] ) { 15941 return false; 15942 } 15943 } 15944 return true; 15945 } ); 15946 15947 }, 15948 15949 _refreshItems: function( event ) { 15950 15951 this.items = []; 15952 this.containers = [ this ]; 15953 15954 var i, j, cur, inst, targetData, _queries, item, queriesLength, 15955 items = this.items, 15956 queries = [ [ $.isFunction( this.options.items ) ? 15957 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) : 15958 $( this.options.items, this.element ), this ] ], 15959 connectWith = this._connectWith(); 15960 15961 //Shouldn't be run the first time through due to massive slow-down 15962 if ( connectWith && this.ready ) { 15963 for ( i = connectWith.length - 1; i >= 0; i-- ) { 15964 cur = $( connectWith[ i ], this.document[ 0 ] ); 15965 for ( j = cur.length - 1; j >= 0; j-- ) { 15966 inst = $.data( cur[ j ], this.widgetFullName ); 15967 if ( inst && inst !== this && !inst.options.disabled ) { 15968 queries.push( [ $.isFunction( inst.options.items ) ? 15969 inst.options.items 15970 .call( inst.element[ 0 ], event, { item: this.currentItem } ) : 15971 $( inst.options.items, inst.element ), inst ] ); 15972 this.containers.push( inst ); 15973 } 15974 } 15975 } 15976 } 15977 15978 for ( i = queries.length - 1; i >= 0; i-- ) { 15979 targetData = queries[ i ][ 1 ]; 15980 _queries = queries[ i ][ 0 ]; 15981 15982 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) { 15983 item = $( _queries[ j ] ); 15984 15985 // Data for target checking (mouse manager) 15986 item.data( this.widgetName + "-item", targetData ); 15987 15988 items.push( { 15989 item: item, 15990 instance: targetData, 15991 width: 0, height: 0, 15992 left: 0, top: 0 15993 } ); 15994 } 15995 } 15996 15997 }, 15998 15999 refreshPositions: function( fast ) { 16000 16001 // Determine whether items are being displayed horizontally 16002 this.floating = this.items.length ? 16003 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : 16004 false; 16005 16006 //This has to be redone because due to the item being moved out/into the offsetParent, 16007 // the offsetParent's position will change 16008 if ( this.offsetParent && this.helper ) { 16009 this.offset.parent = this._getParentOffset(); 16010 } 16011 16012 var i, item, t, p; 16013 16014 for ( i = this.items.length - 1; i >= 0; i-- ) { 16015 item = this.items[ i ]; 16016 16017 //We ignore calculating positions of all connected containers when we're not over them 16018 if ( item.instance !== this.currentContainer && this.currentContainer && 16019 item.item[ 0 ] !== this.currentItem[ 0 ] ) { 16020 continue; 16021 } 16022 16023 t = this.options.toleranceElement ? 16024 $( this.options.toleranceElement, item.item ) : 16025 item.item; 16026 16027 if ( !fast ) { 16028 item.width = t.outerWidth(); 16029 item.height = t.outerHeight(); 16030 } 16031 16032 p = t.offset(); 16033 item.left = p.left; 16034 item.top = p.top; 16035 } 16036 16037 if ( this.options.custom && this.options.custom.refreshContainers ) { 16038 this.options.custom.refreshContainers.call( this ); 16039 } else { 16040 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16041 p = this.containers[ i ].element.offset(); 16042 this.containers[ i ].containerCache.left = p.left; 16043 this.containers[ i ].containerCache.top = p.top; 16044 this.containers[ i ].containerCache.width = 16045 this.containers[ i ].element.outerWidth(); 16046 this.containers[ i ].containerCache.height = 16047 this.containers[ i ].element.outerHeight(); 16048 } 16049 } 16050 16051 return this; 16052 }, 16053 16054 _createPlaceholder: function( that ) { 16055 that = that || this; 16056 var className, 16057 o = that.options; 16058 16059 if ( !o.placeholder || o.placeholder.constructor === String ) { 16060 className = o.placeholder; 16061 o.placeholder = { 16062 element: function() { 16063 16064 var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(), 16065 element = $( "<" + nodeName + ">", that.document[ 0 ] ); 16066 16067 that._addClass( element, "ui-sortable-placeholder", 16068 className || that.currentItem[ 0 ].className ) 16069 ._removeClass( element, "ui-sortable-helper" ); 16070 16071 if ( nodeName === "tbody" ) { 16072 that._createTrPlaceholder( 16073 that.currentItem.find( "tr" ).eq( 0 ), 16074 $( "<tr>", that.document[ 0 ] ).appendTo( element ) 16075 ); 16076 } else if ( nodeName === "tr" ) { 16077 that._createTrPlaceholder( that.currentItem, element ); 16078 } else if ( nodeName === "img" ) { 16079 element.attr( "src", that.currentItem.attr( "src" ) ); 16080 } 16081 16082 if ( !className ) { 16083 element.css( "visibility", "hidden" ); 16084 } 16085 16086 return element; 16087 }, 16088 update: function( container, p ) { 16089 16090 // 1. If a className is set as 'placeholder option, we don't force sizes - 16091 // the class is responsible for that 16092 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a 16093 // class name is specified 16094 if ( className && !o.forcePlaceholderSize ) { 16095 return; 16096 } 16097 16098 //If the element doesn't have a actual height by itself (without styles coming 16099 // from a stylesheet), it receives the inline height from the dragged item 16100 if ( !p.height() ) { 16101 p.height( 16102 that.currentItem.innerHeight() - 16103 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) - 16104 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) ); 16105 } 16106 if ( !p.width() ) { 16107 p.width( 16108 that.currentItem.innerWidth() - 16109 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) - 16110 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) ); 16111 } 16112 } 16113 }; 16114 } 16115 16116 //Create the placeholder 16117 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) ); 16118 16119 //Append it after the actual current item 16120 that.currentItem.after( that.placeholder ); 16121 16122 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 16123 o.placeholder.update( that, that.placeholder ); 16124 16125 }, 16126 16127 _createTrPlaceholder: function( sourceTr, targetTr ) { 16128 var that = this; 16129 16130 sourceTr.children().each( function() { 16131 $( "<td> </td>", that.document[ 0 ] ) 16132 .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 16133 .appendTo( targetTr ); 16134 } ); 16135 }, 16136 16137 _contactContainers: function( event ) { 16138 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, 16139 floating, axis, 16140 innermostContainer = null, 16141 innermostIndex = null; 16142 16143 // Get innermost container that intersects with item 16144 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16145 16146 // Never consider a container that's located within the item itself 16147 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) { 16148 continue; 16149 } 16150 16151 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) { 16152 16153 // If we've already found a container and it's more "inner" than this, then continue 16154 if ( innermostContainer && 16155 $.contains( 16156 this.containers[ i ].element[ 0 ], 16157 innermostContainer.element[ 0 ] ) ) { 16158 continue; 16159 } 16160 16161 innermostContainer = this.containers[ i ]; 16162 innermostIndex = i; 16163 16164 } else { 16165 16166 // container doesn't intersect. trigger "out" event if necessary 16167 if ( this.containers[ i ].containerCache.over ) { 16168 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) ); 16169 this.containers[ i ].containerCache.over = 0; 16170 } 16171 } 16172 16173 } 16174 16175 // If no intersecting containers found, return 16176 if ( !innermostContainer ) { 16177 return; 16178 } 16179 16180 // Move the item into the container if it's not there already 16181 if ( this.containers.length === 1 ) { 16182 if ( !this.containers[ innermostIndex ].containerCache.over ) { 16183 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16184 this.containers[ innermostIndex ].containerCache.over = 1; 16185 } 16186 } else { 16187 16188 // When entering a new container, we will find the item with the least distance and 16189 // append our item near it 16190 dist = 10000; 16191 itemWithLeastDistance = null; 16192 floating = innermostContainer.floating || this._isFloating( this.currentItem ); 16193 posProperty = floating ? "left" : "top"; 16194 sizeProperty = floating ? "width" : "height"; 16195 axis = floating ? "pageX" : "pageY"; 16196 16197 for ( j = this.items.length - 1; j >= 0; j-- ) { 16198 if ( !$.contains( 16199 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] ) 16200 ) { 16201 continue; 16202 } 16203 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) { 16204 continue; 16205 } 16206 16207 cur = this.items[ j ].item.offset()[ posProperty ]; 16208 nearBottom = false; 16209 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 16210 nearBottom = true; 16211 } 16212 16213 if ( Math.abs( event[ axis ] - cur ) < dist ) { 16214 dist = Math.abs( event[ axis ] - cur ); 16215 itemWithLeastDistance = this.items[ j ]; 16216 this.direction = nearBottom ? "up" : "down"; 16217 } 16218 } 16219 16220 //Check if dropOnEmpty is enabled 16221 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) { 16222 return; 16223 } 16224 16225 if ( this.currentContainer === this.containers[ innermostIndex ] ) { 16226 if ( !this.currentContainer.containerCache.over ) { 16227 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); 16228 this.currentContainer.containerCache.over = 1; 16229 } 16230 return; 16231 } 16232 16233 itemWithLeastDistance ? 16234 this._rearrange( event, itemWithLeastDistance, null, true ) : 16235 this._rearrange( event, null, this.containers[ innermostIndex ].element, true ); 16236 this._trigger( "change", event, this._uiHash() ); 16237 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) ); 16238 this.currentContainer = this.containers[ innermostIndex ]; 16239 16240 //Update the placeholder 16241 this.options.placeholder.update( this.currentContainer, this.placeholder ); 16242 16243 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16244 this.containers[ innermostIndex ].containerCache.over = 1; 16245 } 16246 16247 }, 16248 16249 _createHelper: function( event ) { 16250 16251 var o = this.options, 16252 helper = $.isFunction( o.helper ) ? 16253 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) : 16254 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem ); 16255 16256 //Add the helper to the DOM if that didn't happen already 16257 if ( !helper.parents( "body" ).length ) { 16258 $( o.appendTo !== "parent" ? 16259 o.appendTo : 16260 this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] ); 16261 } 16262 16263 if ( helper[ 0 ] === this.currentItem[ 0 ] ) { 16264 this._storedCSS = { 16265 width: this.currentItem[ 0 ].style.width, 16266 height: this.currentItem[ 0 ].style.height, 16267 position: this.currentItem.css( "position" ), 16268 top: this.currentItem.css( "top" ), 16269 left: this.currentItem.css( "left" ) 16270 }; 16271 } 16272 16273 if ( !helper[ 0 ].style.width || o.forceHelperSize ) { 16274 helper.width( this.currentItem.width() ); 16275 } 16276 if ( !helper[ 0 ].style.height || o.forceHelperSize ) { 16277 helper.height( this.currentItem.height() ); 16278 } 16279 16280 return helper; 16281 16282 }, 16283 16284 _adjustOffsetFromHelper: function( obj ) { 16285 if ( typeof obj === "string" ) { 16286 obj = obj.split( " " ); 16287 } 16288 if ( $.isArray( obj ) ) { 16289 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 16290 } 16291 if ( "left" in obj ) { 16292 this.offset.click.left = obj.left + this.margins.left; 16293 } 16294 if ( "right" in obj ) { 16295 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 16296 } 16297 if ( "top" in obj ) { 16298 this.offset.click.top = obj.top + this.margins.top; 16299 } 16300 if ( "bottom" in obj ) { 16301 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 16302 } 16303 }, 16304 16305 _getParentOffset: function() { 16306 16307 //Get the offsetParent and cache its position 16308 this.offsetParent = this.helper.offsetParent(); 16309 var po = this.offsetParent.offset(); 16310 16311 // This is a special case where we need to modify a offset calculated on start, since the 16312 // following happened: 16313 // 1. The position of the helper is absolute, so it's position is calculated based on the 16314 // next positioned parent 16315 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 16316 // the document, which means that the scroll is included in the initial calculation of the 16317 // offset of the parent, and never recalculated upon drag 16318 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] && 16319 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 16320 po.left += this.scrollParent.scrollLeft(); 16321 po.top += this.scrollParent.scrollTop(); 16322 } 16323 16324 // This needs to be actually done for all browsers, since pageX/pageY includes this 16325 // information with an ugly IE fix 16326 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body || 16327 ( this.offsetParent[ 0 ].tagName && 16328 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) { 16329 po = { top: 0, left: 0 }; 16330 } 16331 16332 return { 16333 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 16334 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 16335 }; 16336 16337 }, 16338 16339 _getRelativeOffset: function() { 16340 16341 if ( this.cssPosition === "relative" ) { 16342 var p = this.currentItem.position(); 16343 return { 16344 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 16345 this.scrollParent.scrollTop(), 16346 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 16347 this.scrollParent.scrollLeft() 16348 }; 16349 } else { 16350 return { top: 0, left: 0 }; 16351 } 16352 16353 }, 16354 16355 _cacheMargins: function() { 16356 this.margins = { 16357 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ), 16358 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 ) 16359 }; 16360 }, 16361 16362 _cacheHelperProportions: function() { 16363 this.helperProportions = { 16364 width: this.helper.outerWidth(), 16365 height: this.helper.outerHeight() 16366 }; 16367 }, 16368 16369 _setContainment: function() { 16370 16371 var ce, co, over, 16372 o = this.options; 16373 if ( o.containment === "parent" ) { 16374 o.containment = this.helper[ 0 ].parentNode; 16375 } 16376 if ( o.containment === "document" || o.containment === "window" ) { 16377 this.containment = [ 16378 0 - this.offset.relative.left - this.offset.parent.left, 16379 0 - this.offset.relative.top - this.offset.parent.top, 16380 o.containment === "document" ? 16381 this.document.width() : 16382 this.window.width() - this.helperProportions.width - this.margins.left, 16383 ( o.containment === "document" ? 16384 ( this.document.height() || document.body.parentNode.scrollHeight ) : 16385 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight 16386 ) - this.helperProportions.height - this.margins.top 16387 ]; 16388 } 16389 16390 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) { 16391 ce = $( o.containment )[ 0 ]; 16392 co = $( o.containment ).offset(); 16393 over = ( $( ce ).css( "overflow" ) !== "hidden" ); 16394 16395 this.containment = [ 16396 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) + 16397 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left, 16398 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) + 16399 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top, 16400 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 16401 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) - 16402 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) - 16403 this.helperProportions.width - this.margins.left, 16404 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 16405 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) - 16406 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) - 16407 this.helperProportions.height - this.margins.top 16408 ]; 16409 } 16410 16411 }, 16412 16413 _convertPositionTo: function( d, pos ) { 16414 16415 if ( !pos ) { 16416 pos = this.position; 16417 } 16418 var mod = d === "absolute" ? 1 : -1, 16419 scroll = this.cssPosition === "absolute" && 16420 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16421 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16422 this.offsetParent : 16423 this.scrollParent, 16424 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16425 16426 return { 16427 top: ( 16428 16429 // The absolute mouse position 16430 pos.top + 16431 16432 // Only for relative positioned nodes: Relative offset from element to offset parent 16433 this.offset.relative.top * mod + 16434 16435 // The offsetParent's offset without borders (offset + border) 16436 this.offset.parent.top * mod - 16437 ( ( this.cssPosition === "fixed" ? 16438 -this.scrollParent.scrollTop() : 16439 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod ) 16440 ), 16441 left: ( 16442 16443 // The absolute mouse position 16444 pos.left + 16445 16446 // Only for relative positioned nodes: Relative offset from element to offset parent 16447 this.offset.relative.left * mod + 16448 16449 // The offsetParent's offset without borders (offset + border) 16450 this.offset.parent.left * mod - 16451 ( ( this.cssPosition === "fixed" ? 16452 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : 16453 scroll.scrollLeft() ) * mod ) 16454 ) 16455 }; 16456 16457 }, 16458 16459 _generatePosition: function( event ) { 16460 16461 var top, left, 16462 o = this.options, 16463 pageX = event.pageX, 16464 pageY = event.pageY, 16465 scroll = this.cssPosition === "absolute" && 16466 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16467 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16468 this.offsetParent : 16469 this.scrollParent, 16470 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16471 16472 // This is another very weird special case that only happens for relative elements: 16473 // 1. If the css position is relative 16474 // 2. and the scroll parent is the document or similar to the offset parent 16475 // we have to refresh the relative offset during the scroll so there are no jumps 16476 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16477 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) { 16478 this.offset.relative = this._getRelativeOffset(); 16479 } 16480 16481 /* 16482 * - Position constraining - 16483 * Constrain the position to a mix of grid, containment. 16484 */ 16485 16486 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options 16487 16488 if ( this.containment ) { 16489 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) { 16490 pageX = this.containment[ 0 ] + this.offset.click.left; 16491 } 16492 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) { 16493 pageY = this.containment[ 1 ] + this.offset.click.top; 16494 } 16495 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) { 16496 pageX = this.containment[ 2 ] + this.offset.click.left; 16497 } 16498 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) { 16499 pageY = this.containment[ 3 ] + this.offset.click.top; 16500 } 16501 } 16502 16503 if ( o.grid ) { 16504 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) / 16505 o.grid[ 1 ] ) * o.grid[ 1 ]; 16506 pageY = this.containment ? 16507 ( ( top - this.offset.click.top >= this.containment[ 1 ] && 16508 top - this.offset.click.top <= this.containment[ 3 ] ) ? 16509 top : 16510 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ? 16511 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : 16512 top; 16513 16514 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) / 16515 o.grid[ 0 ] ) * o.grid[ 0 ]; 16516 pageX = this.containment ? 16517 ( ( left - this.offset.click.left >= this.containment[ 0 ] && 16518 left - this.offset.click.left <= this.containment[ 2 ] ) ? 16519 left : 16520 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ? 16521 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : 16522 left; 16523 } 16524 16525 } 16526 16527 return { 16528 top: ( 16529 16530 // The absolute mouse position 16531 pageY - 16532 16533 // Click offset (relative to the element) 16534 this.offset.click.top - 16535 16536 // Only for relative positioned nodes: Relative offset from element to offset parent 16537 this.offset.relative.top - 16538 16539 // The offsetParent's offset without borders (offset + border) 16540 this.offset.parent.top + 16541 ( ( this.cssPosition === "fixed" ? 16542 -this.scrollParent.scrollTop() : 16543 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) ) 16544 ), 16545 left: ( 16546 16547 // The absolute mouse position 16548 pageX - 16549 16550 // Click offset (relative to the element) 16551 this.offset.click.left - 16552 16553 // Only for relative positioned nodes: Relative offset from element to offset parent 16554 this.offset.relative.left - 16555 16556 // The offsetParent's offset without borders (offset + border) 16557 this.offset.parent.left + 16558 ( ( this.cssPosition === "fixed" ? 16559 -this.scrollParent.scrollLeft() : 16560 scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) 16561 ) 16562 }; 16563 16564 }, 16565 16566 _rearrange: function( event, i, a, hardRefresh ) { 16567 16568 a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) : 16569 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ], 16570 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) ); 16571 16572 //Various things done here to improve the performance: 16573 // 1. we create a setTimeout, that calls refreshPositions 16574 // 2. on the instance, we have a counter variable, that get's higher after every append 16575 // 3. on the local scope, we copy the counter variable, and check in the timeout, 16576 // if it's still the same 16577 // 4. this lets only the last addition to the timeout stack through 16578 this.counter = this.counter ? ++this.counter : 1; 16579 var counter = this.counter; 16580 16581 this._delay( function() { 16582 if ( counter === this.counter ) { 16583 16584 //Precompute after each DOM insertion, NOT on mousemove 16585 this.refreshPositions( !hardRefresh ); 16586 } 16587 } ); 16588 16589 }, 16590 16591 _clear: function( event, noPropagation ) { 16592 16593 this.reverting = false; 16594 16595 // We delay all events that have to be triggered to after the point where the placeholder 16596 // has been removed and everything else normalized again 16597 var i, 16598 delayedTriggers = []; 16599 16600 // We first have to update the dom position of the actual currentItem 16601 // Note: don't do it if the current item is already removed (by a user), or it gets 16602 // reappended (see #4088) 16603 if ( !this._noFinalSort && this.currentItem.parent().length ) { 16604 this.placeholder.before( this.currentItem ); 16605 } 16606 this._noFinalSort = null; 16607 16608 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) { 16609 for ( i in this._storedCSS ) { 16610 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) { 16611 this._storedCSS[ i ] = ""; 16612 } 16613 } 16614 this.currentItem.css( this._storedCSS ); 16615 this._removeClass( this.currentItem, "ui-sortable-helper" ); 16616 } else { 16617 this.currentItem.show(); 16618 } 16619 16620 if ( this.fromOutside && !noPropagation ) { 16621 delayedTriggers.push( function( event ) { 16622 this._trigger( "receive", event, this._uiHash( this.fromOutside ) ); 16623 } ); 16624 } 16625 if ( ( this.fromOutside || 16626 this.domPosition.prev !== 16627 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] || 16628 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) { 16629 16630 // Trigger update callback if the DOM position has changed 16631 delayedTriggers.push( function( event ) { 16632 this._trigger( "update", event, this._uiHash() ); 16633 } ); 16634 } 16635 16636 // Check if the items Container has Changed and trigger appropriate 16637 // events. 16638 if ( this !== this.currentContainer ) { 16639 if ( !noPropagation ) { 16640 delayedTriggers.push( function( event ) { 16641 this._trigger( "remove", event, this._uiHash() ); 16642 } ); 16643 delayedTriggers.push( ( function( c ) { 16644 return function( event ) { 16645 c._trigger( "receive", event, this._uiHash( this ) ); 16646 }; 16647 } ).call( this, this.currentContainer ) ); 16648 delayedTriggers.push( ( function( c ) { 16649 return function( event ) { 16650 c._trigger( "update", event, this._uiHash( this ) ); 16651 }; 16652 } ).call( this, this.currentContainer ) ); 16653 } 16654 } 16655 16656 //Post events to containers 16657 function delayEvent( type, instance, container ) { 16658 return function( event ) { 16659 container._trigger( type, event, instance._uiHash( instance ) ); 16660 }; 16661 } 16662 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16663 if ( !noPropagation ) { 16664 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 16665 } 16666 if ( this.containers[ i ].containerCache.over ) { 16667 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 16668 this.containers[ i ].containerCache.over = 0; 16669 } 16670 } 16671 16672 //Do what was originally in plugins 16673 if ( this.storedCursor ) { 16674 this.document.find( "body" ).css( "cursor", this.storedCursor ); 16675 this.storedStylesheet.remove(); 16676 } 16677 if ( this._storedOpacity ) { 16678 this.helper.css( "opacity", this._storedOpacity ); 16679 } 16680 if ( this._storedZIndex ) { 16681 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex ); 16682 } 16683 16684 this.dragging = false; 16685 16686 if ( !noPropagation ) { 16687 this._trigger( "beforeStop", event, this._uiHash() ); 16688 } 16689 16690 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 16691 // it unbinds ALL events from the original node! 16692 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 16693 16694 if ( !this.cancelHelperRemoval ) { 16695 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 16696 this.helper.remove(); 16697 } 16698 this.helper = null; 16699 } 16700 16701 if ( !noPropagation ) { 16702 for ( i = 0; i < delayedTriggers.length; i++ ) { 16703 16704 // Trigger all delayed events 16705 delayedTriggers[ i ].call( this, event ); 16706 } 16707 this._trigger( "stop", event, this._uiHash() ); 16708 } 16709 16710 this.fromOutside = false; 16711 return !this.cancelHelperRemoval; 16712 16713 }, 16714 16715 _trigger: function() { 16716 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) { 16717 this.cancel(); 16718 } 16719 }, 16720 16721 _uiHash: function( _inst ) { 16722 var inst = _inst || this; 16723 return { 16724 helper: inst.helper, 16725 placeholder: inst.placeholder || $( [] ), 16726 position: inst.position, 16727 originalPosition: inst.originalPosition, 16728 offset: inst.positionAbs, 16729 item: inst.currentItem, 16730 sender: _inst ? _inst.element : null 16731 }; 16732 } 16733 16734 } ); 16735 16736 16737 /*! 16738 * jQuery UI Spinner 1.12.1 16739 * http://jqueryui.com 16740 * 16741 * Copyright jQuery Foundation and other contributors 16742 * Released under the MIT license. 16743 * http://jquery.org/license 16744 */ 16745 16746 //>>label: Spinner 16747 //>>group: Widgets 16748 //>>description: Displays buttons to easily input numbers via the keyboard or mouse. 16749 //>>docs: http://api.jqueryui.com/spinner/ 16750 //>>demos: http://jqueryui.com/spinner/ 16751 //>>css.structure: ../../themes/base/core.css 16752 //>>css.structure: ../../themes/base/spinner.css 16753 //>>css.theme: ../../themes/base/theme.css 16754 16755 16756 16757 function spinnerModifer( fn ) { 16758 return function() { 16759 var previous = this.element.val(); 16760 fn.apply( this, arguments ); 16761 this._refresh(); 16762 if ( previous !== this.element.val() ) { 16763 this._trigger( "change" ); 16764 } 16765 }; 16766 } 16767 16768 $.widget( "ui.spinner", { 16769 version: "1.12.1", 16770 defaultElement: "<input>", 16771 widgetEventPrefix: "spin", 16772 options: { 16773 classes: { 16774 "ui-spinner": "ui-corner-all", 16775 "ui-spinner-down": "ui-corner-br", 16776 "ui-spinner-up": "ui-corner-tr" 16777 }, 16778 culture: null, 16779 icons: { 16780 down: "ui-icon-triangle-1-s", 16781 up: "ui-icon-triangle-1-n" 16782 }, 16783 incremental: true, 16784 max: null, 16785 min: null, 16786 numberFormat: null, 16787 page: 10, 16788 step: 1, 16789 16790 change: null, 16791 spin: null, 16792 start: null, 16793 stop: null 16794 }, 16795 16796 _create: function() { 16797 16798 // handle string values that need to be parsed 16799 this._setOption( "max", this.options.max ); 16800 this._setOption( "min", this.options.min ); 16801 this._setOption( "step", this.options.step ); 16802 16803 // Only format if there is a value, prevents the field from being marked 16804 // as invalid in Firefox, see #9573. 16805 if ( this.value() !== "" ) { 16806 16807 // Format the value, but don't constrain. 16808 this._value( this.element.val(), true ); 16809 } 16810 16811 this._draw(); 16812 this._on( this._events ); 16813 this._refresh(); 16814 16815 // Turning off autocomplete prevents the browser from remembering the 16816 // value when navigating through history, so we re-enable autocomplete 16817 // if the page is unloaded before the widget is destroyed. #7790 16818 this._on( this.window, { 16819 beforeunload: function() { 16820 this.element.removeAttr( "autocomplete" ); 16821 } 16822 } ); 16823 }, 16824 16825 _getCreateOptions: function() { 16826 var options = this._super(); 16827 var element = this.element; 16828 16829 $.each( [ "min", "max", "step" ], function( i, option ) { 16830 var value = element.attr( option ); 16831 if ( value != null && value.length ) { 16832 options[ option ] = value; 16833 } 16834 } ); 16835 16836 return options; 16837 }, 16838 16839 _events: { 16840 keydown: function( event ) { 16841 if ( this._start( event ) && this._keydown( event ) ) { 16842 event.preventDefault(); 16843 } 16844 }, 16845 keyup: "_stop", 16846 focus: function() { 16847 this.previous = this.element.val(); 16848 }, 16849 blur: function( event ) { 16850 if ( this.cancelBlur ) { 16851 delete this.cancelBlur; 16852 return; 16853 } 16854 16855 this._stop(); 16856 this._refresh(); 16857 if ( this.previous !== this.element.val() ) { 16858 this._trigger( "change", event ); 16859 } 16860 }, 16861 mousewheel: function( event, delta ) { 16862 if ( !delta ) { 16863 return; 16864 } 16865 if ( !this.spinning && !this._start( event ) ) { 16866 return false; 16867 } 16868 16869 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); 16870 clearTimeout( this.mousewheelTimer ); 16871 this.mousewheelTimer = this._delay( function() { 16872 if ( this.spinning ) { 16873 this._stop( event ); 16874 } 16875 }, 100 ); 16876 event.preventDefault(); 16877 }, 16878 "mousedown .ui-spinner-button": function( event ) { 16879 var previous; 16880 16881 // We never want the buttons to have focus; whenever the user is 16882 // interacting with the spinner, the focus should be on the input. 16883 // If the input is focused then this.previous is properly set from 16884 // when the input first received focus. If the input is not focused 16885 // then we need to set this.previous based on the value before spinning. 16886 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ? 16887 this.previous : this.element.val(); 16888 function checkFocus() { 16889 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ); 16890 if ( !isActive ) { 16891 this.element.trigger( "focus" ); 16892 this.previous = previous; 16893 16894 // support: IE 16895 // IE sets focus asynchronously, so we need to check if focus 16896 // moved off of the input because the user clicked on the button. 16897 this._delay( function() { 16898 this.previous = previous; 16899 } ); 16900 } 16901 } 16902 16903 // Ensure focus is on (or stays on) the text field 16904 event.preventDefault(); 16905 checkFocus.call( this ); 16906 16907 // Support: IE 16908 // IE doesn't prevent moving focus even with event.preventDefault() 16909 // so we set a flag to know when we should ignore the blur event 16910 // and check (again) if focus moved off of the input. 16911 this.cancelBlur = true; 16912 this._delay( function() { 16913 delete this.cancelBlur; 16914 checkFocus.call( this ); 16915 } ); 16916 16917 if ( this._start( event ) === false ) { 16918 return; 16919 } 16920 16921 this._repeat( null, $( event.currentTarget ) 16922 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 16923 }, 16924 "mouseup .ui-spinner-button": "_stop", 16925 "mouseenter .ui-spinner-button": function( event ) { 16926 16927 // button will add ui-state-active if mouse was down while mouseleave and kept down 16928 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 16929 return; 16930 } 16931 16932 if ( this._start( event ) === false ) { 16933 return false; 16934 } 16935 this._repeat( null, $( event.currentTarget ) 16936 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 16937 }, 16938 16939 // TODO: do we really want to consider this a stop? 16940 // shouldn't we just stop the repeater and wait until mouseup before 16941 // we trigger the stop event? 16942 "mouseleave .ui-spinner-button": "_stop" 16943 }, 16944 16945 // Support mobile enhanced option and make backcompat more sane 16946 _enhance: function() { 16947 this.uiSpinner = this.element 16948 .attr( "autocomplete", "off" ) 16949 .wrap( "<span>" ) 16950 .parent() 16951 16952 // Add buttons 16953 .append( 16954 "<a></a><a></a>" 16955 ); 16956 }, 16957 16958 _draw: function() { 16959 this._enhance(); 16960 16961 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); 16962 this._addClass( "ui-spinner-input" ); 16963 16964 this.element.attr( "role", "spinbutton" ); 16965 16966 // Button bindings 16967 this.buttons = this.uiSpinner.children( "a" ) 16968 .attr( "tabIndex", -1 ) 16969 .attr( "aria-hidden", true ) 16970 .button( { 16971 classes: { 16972 "ui-button": "" 16973 } 16974 } ); 16975 16976 // TODO: Right now button does not support classes this is already updated in button PR 16977 this._removeClass( this.buttons, "ui-corner-all" ); 16978 16979 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); 16980 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); 16981 this.buttons.first().button( { 16982 "icon": this.options.icons.up, 16983 "showLabel": false 16984 } ); 16985 this.buttons.last().button( { 16986 "icon": this.options.icons.down, 16987 "showLabel": false 16988 } ); 16989 16990 // IE 6 doesn't understand height: 50% for the buttons 16991 // unless the wrapper has an explicit height 16992 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && 16993 this.uiSpinner.height() > 0 ) { 16994 this.uiSpinner.height( this.uiSpinner.height() ); 16995 } 16996 }, 16997 16998 _keydown: function( event ) { 16999 var options = this.options, 17000 keyCode = $.ui.keyCode; 17001 17002 switch ( event.keyCode ) { 17003 case keyCode.UP: 17004 this._repeat( null, 1, event ); 17005 return true; 17006 case keyCode.DOWN: 17007 this._repeat( null, -1, event ); 17008 return true; 17009 case keyCode.PAGE_UP: 17010 this._repeat( null, options.page, event ); 17011 return true; 17012 case keyCode.PAGE_DOWN: 17013 this._repeat( null, -options.page, event ); 17014 return true; 17015 } 17016 17017 return false; 17018 }, 17019 17020 _start: function( event ) { 17021 if ( !this.spinning && this._trigger( "start", event ) === false ) { 17022 return false; 17023 } 17024 17025 if ( !this.counter ) { 17026 this.counter = 1; 17027 } 17028 this.spinning = true; 17029 return true; 17030 }, 17031 17032 _repeat: function( i, steps, event ) { 17033 i = i || 500; 17034 17035 clearTimeout( this.timer ); 17036 this.timer = this._delay( function() { 17037 this._repeat( 40, steps, event ); 17038 }, i ); 17039 17040 this._spin( steps * this.options.step, event ); 17041 }, 17042 17043 _spin: function( step, event ) { 17044 var value = this.value() || 0; 17045 17046 if ( !this.counter ) { 17047 this.counter = 1; 17048 } 17049 17050 value = this._adjustValue( value + step * this._increment( this.counter ) ); 17051 17052 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { 17053 this._value( value ); 17054 this.counter++; 17055 } 17056 }, 17057 17058 _increment: function( i ) { 17059 var incremental = this.options.incremental; 17060 17061 if ( incremental ) { 17062 return $.isFunction( incremental ) ? 17063 incremental( i ) : 17064 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 17065 } 17066 17067 return 1; 17068 }, 17069 17070 _precision: function() { 17071 var precision = this._precisionOf( this.options.step ); 17072 if ( this.options.min !== null ) { 17073 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 17074 } 17075 return precision; 17076 }, 17077 17078 _precisionOf: function( num ) { 17079 var str = num.toString(), 17080 decimal = str.indexOf( "." ); 17081 return decimal === -1 ? 0 : str.length - decimal - 1; 17082 }, 17083 17084 _adjustValue: function( value ) { 17085 var base, aboveMin, 17086 options = this.options; 17087 17088 // Make sure we're at a valid step 17089 // - find out where we are relative to the base (min or 0) 17090 base = options.min !== null ? options.min : 0; 17091 aboveMin = value - base; 17092 17093 // - round to the nearest step 17094 aboveMin = Math.round( aboveMin / options.step ) * options.step; 17095 17096 // - rounding is based on 0, so adjust back to our base 17097 value = base + aboveMin; 17098 17099 // Fix precision from bad JS floating point math 17100 value = parseFloat( value.toFixed( this._precision() ) ); 17101 17102 // Clamp the value 17103 if ( options.max !== null && value > options.max ) { 17104 return options.max; 17105 } 17106 if ( options.min !== null && value < options.min ) { 17107 return options.min; 17108 } 17109 17110 return value; 17111 }, 17112 17113 _stop: function( event ) { 17114 if ( !this.spinning ) { 17115 return; 17116 } 17117 17118 clearTimeout( this.timer ); 17119 clearTimeout( this.mousewheelTimer ); 17120 this.counter = 0; 17121 this.spinning = false; 17122 this._trigger( "stop", event ); 17123 }, 17124 17125 _setOption: function( key, value ) { 17126 var prevValue, first, last; 17127 17128 if ( key === "culture" || key === "numberFormat" ) { 17129 prevValue = this._parse( this.element.val() ); 17130 this.options[ key ] = value; 17131 this.element.val( this._format( prevValue ) ); 17132 return; 17133 } 17134 17135 if ( key === "max" || key === "min" || key === "step" ) { 17136 if ( typeof value === "string" ) { 17137 value = this._parse( value ); 17138 } 17139 } 17140 if ( key === "icons" ) { 17141 first = this.buttons.first().find( ".ui-icon" ); 17142 this._removeClass( first, null, this.options.icons.up ); 17143 this._addClass( first, null, value.up ); 17144 last = this.buttons.last().find( ".ui-icon" ); 17145 this._removeClass( last, null, this.options.icons.down ); 17146 this._addClass( last, null, value.down ); 17147 } 17148 17149 this._super( key, value ); 17150 }, 17151 17152 _setOptionDisabled: function( value ) { 17153 this._super( value ); 17154 17155 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); 17156 this.element.prop( "disabled", !!value ); 17157 this.buttons.button( value ? "disable" : "enable" ); 17158 }, 17159 17160 _setOptions: spinnerModifer( function( options ) { 17161 this._super( options ); 17162 } ), 17163 17164 _parse: function( val ) { 17165 if ( typeof val === "string" && val !== "" ) { 17166 val = window.Globalize && this.options.numberFormat ? 17167 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 17168 } 17169 return val === "" || isNaN( val ) ? null : val; 17170 }, 17171 17172 _format: function( value ) { 17173 if ( value === "" ) { 17174 return ""; 17175 } 17176 return window.Globalize && this.options.numberFormat ? 17177 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 17178 value; 17179 }, 17180 17181 _refresh: function() { 17182 this.element.attr( { 17183 "aria-valuemin": this.options.min, 17184 "aria-valuemax": this.options.max, 17185 17186 // TODO: what should we do with values that can't be parsed? 17187 "aria-valuenow": this._parse( this.element.val() ) 17188 } ); 17189 }, 17190 17191 isValid: function() { 17192 var value = this.value(); 17193 17194 // Null is invalid 17195 if ( value === null ) { 17196 return false; 17197 } 17198 17199 // If value gets adjusted, it's invalid 17200 return value === this._adjustValue( value ); 17201 }, 17202 17203 // Update the value without triggering change 17204 _value: function( value, allowAny ) { 17205 var parsed; 17206 if ( value !== "" ) { 17207 parsed = this._parse( value ); 17208 if ( parsed !== null ) { 17209 if ( !allowAny ) { 17210 parsed = this._adjustValue( parsed ); 17211 } 17212 value = this._format( parsed ); 17213 } 17214 } 17215 this.element.val( value ); 17216 this._refresh(); 17217 }, 17218 17219 _destroy: function() { 17220 this.element 17221 .prop( "disabled", false ) 17222 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); 17223 17224 this.uiSpinner.replaceWith( this.element ); 17225 }, 17226 17227 stepUp: spinnerModifer( function( steps ) { 17228 this._stepUp( steps ); 17229 } ), 17230 _stepUp: function( steps ) { 17231 if ( this._start() ) { 17232 this._spin( ( steps || 1 ) * this.options.step ); 17233 this._stop(); 17234 } 17235 }, 17236 17237 stepDown: spinnerModifer( function( steps ) { 17238 this._stepDown( steps ); 17239 } ), 17240 _stepDown: function( steps ) { 17241 if ( this._start() ) { 17242 this._spin( ( steps || 1 ) * -this.options.step ); 17243 this._stop(); 17244 } 17245 }, 17246 17247 pageUp: spinnerModifer( function( pages ) { 17248 this._stepUp( ( pages || 1 ) * this.options.page ); 17249 } ), 17250 17251 pageDown: spinnerModifer( function( pages ) { 17252 this._stepDown( ( pages || 1 ) * this.options.page ); 17253 } ), 17254 17255 value: function( newVal ) { 17256 if ( !arguments.length ) { 17257 return this._parse( this.element.val() ); 17258 } 17259 spinnerModifer( this._value ).call( this, newVal ); 17260 }, 17261 17262 widget: function() { 17263 return this.uiSpinner; 17264 } 17265 } ); 17266 17267 // DEPRECATED 17268 // TODO: switch return back to widget declaration at top of file when this is removed 17269 if ( $.uiBackCompat !== false ) { 17270 17271 // Backcompat for spinner html extension points 17272 $.widget( "ui.spinner", $.ui.spinner, { 17273 _enhance: function() { 17274 this.uiSpinner = this.element 17275 .attr( "autocomplete", "off" ) 17276 .wrap( this._uiSpinnerHtml() ) 17277 .parent() 17278 17279 // Add buttons 17280 .append( this._buttonHtml() ); 17281 }, 17282 _uiSpinnerHtml: function() { 17283 return "<span>"; 17284 }, 17285 17286 _buttonHtml: function() { 17287 return "<a></a><a></a>"; 17288 } 17289 } ); 17290 } 17291 17292 var widgetsSpinner = $.ui.spinner; 17293 17294 17295 /*! 17296 * jQuery UI Tabs 1.12.1 17297 * http://jqueryui.com 17298 * 17299 * Copyright jQuery Foundation and other contributors 17300 * Released under the MIT license. 17301 * http://jquery.org/license 17302 */ 17303 17304 //>>label: Tabs 17305 //>>group: Widgets 17306 //>>description: Transforms a set of container elements into a tab structure. 17307 //>>docs: http://api.jqueryui.com/tabs/ 17308 //>>demos: http://jqueryui.com/tabs/ 17309 //>>css.structure: ../../themes/base/core.css 17310 //>>css.structure: ../../themes/base/tabs.css 17311 //>>css.theme: ../../themes/base/theme.css 17312 17313 17314 17315 $.widget( "ui.tabs", { 17316 version: "1.12.1", 17317 delay: 300, 17318 options: { 17319 active: null, 17320 classes: { 17321 "ui-tabs": "ui-corner-all", 17322 "ui-tabs-nav": "ui-corner-all", 17323 "ui-tabs-panel": "ui-corner-bottom", 17324 "ui-tabs-tab": "ui-corner-top" 17325 }, 17326 collapsible: false, 17327 event: "click", 17328 heightStyle: "content", 17329 hide: null, 17330 show: null, 17331 17332 // Callbacks 17333 activate: null, 17334 beforeActivate: null, 17335 beforeLoad: null, 17336 load: null 17337 }, 17338 17339 _isLocal: ( function() { 17340 var rhash = /#.*$/; 17341 17342 return function( anchor ) { 17343 var anchorUrl, locationUrl; 17344 17345 anchorUrl = anchor.href.replace( rhash, "" ); 17346 locationUrl = location.href.replace( rhash, "" ); 17347 17348 // Decoding may throw an error if the URL isn't UTF-8 (#9518) 17349 try { 17350 anchorUrl = decodeURIComponent( anchorUrl ); 17351 } catch ( error ) {} 17352 try { 17353 locationUrl = decodeURIComponent( locationUrl ); 17354 } catch ( error ) {} 17355 17356 return anchor.hash.length > 1 && anchorUrl === locationUrl; 17357 }; 17358 } )(), 17359 17360 _create: function() { 17361 var that = this, 17362 options = this.options; 17363 17364 this.running = false; 17365 17366 this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); 17367 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); 17368 17369 this._processTabs(); 17370 options.active = this._initialActive(); 17371 17372 // Take disabling tabs via class attribute from HTML 17373 // into account and update option properly. 17374 if ( $.isArray( options.disabled ) ) { 17375 options.disabled = $.unique( options.disabled.concat( 17376 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { 17377 return that.tabs.index( li ); 17378 } ) 17379 ) ).sort(); 17380 } 17381 17382 // Check for length avoids error when initializing empty list 17383 if ( this.options.active !== false && this.anchors.length ) { 17384 this.active = this._findActive( options.active ); 17385 } else { 17386 this.active = $(); 17387 } 17388 17389 this._refresh(); 17390 17391 if ( this.active.length ) { 17392 this.load( options.active ); 17393 } 17394 }, 17395 17396 _initialActive: function() { 17397 var active = this.options.active, 17398 collapsible = this.options.collapsible, 17399 locationHash = location.hash.substring( 1 ); 17400 17401 if ( active === null ) { 17402 17403 // check the fragment identifier in the URL 17404 if ( locationHash ) { 17405 this.tabs.each( function( i, tab ) { 17406 if ( $( tab ).attr( "aria-controls" ) === locationHash ) { 17407 active = i; 17408 return false; 17409 } 17410 } ); 17411 } 17412 17413 // Check for a tab marked active via a class 17414 if ( active === null ) { 17415 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); 17416 } 17417 17418 // No active tab, set to false 17419 if ( active === null || active === -1 ) { 17420 active = this.tabs.length ? 0 : false; 17421 } 17422 } 17423 17424 // Handle numbers: negative, out of range 17425 if ( active !== false ) { 17426 active = this.tabs.index( this.tabs.eq( active ) ); 17427 if ( active === -1 ) { 17428 active = collapsible ? false : 0; 17429 } 17430 } 17431 17432 // Don't allow collapsible: false and active: false 17433 if ( !collapsible && active === false && this.anchors.length ) { 17434 active = 0; 17435 } 17436 17437 return active; 17438 }, 17439 17440 _getCreateEventData: function() { 17441 return { 17442 tab: this.active, 17443 panel: !this.active.length ? $() : this._getPanelForTab( this.active ) 17444 }; 17445 }, 17446 17447 _tabKeydown: function( event ) { 17448 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ), 17449 selectedIndex = this.tabs.index( focusedTab ), 17450 goingForward = true; 17451 17452 if ( this._handlePageNav( event ) ) { 17453 return; 17454 } 17455 17456 switch ( event.keyCode ) { 17457 case $.ui.keyCode.RIGHT: 17458 case $.ui.keyCode.DOWN: 17459 selectedIndex++; 17460 break; 17461 case $.ui.keyCode.UP: 17462 case $.ui.keyCode.LEFT: 17463 goingForward = false; 17464 selectedIndex--; 17465 break; 17466 case $.ui.keyCode.END: 17467 selectedIndex = this.anchors.length - 1; 17468 break; 17469 case $.ui.keyCode.HOME: 17470 selectedIndex = 0; 17471 break; 17472 case $.ui.keyCode.SPACE: 17473 17474 // Activate only, no collapsing 17475 event.preventDefault(); 17476 clearTimeout( this.activating ); 17477 this._activate( selectedIndex ); 17478 return; 17479 case $.ui.keyCode.ENTER: 17480 17481 // Toggle (cancel delayed activation, allow collapsing) 17482 event.preventDefault(); 17483 clearTimeout( this.activating ); 17484 17485 // Determine if we should collapse or activate 17486 this._activate( selectedIndex === this.options.active ? false : selectedIndex ); 17487 return; 17488 default: 17489 return; 17490 } 17491 17492 // Focus the appropriate tab, based on which key was pressed 17493 event.preventDefault(); 17494 clearTimeout( this.activating ); 17495 selectedIndex = this._focusNextTab( selectedIndex, goingForward ); 17496 17497 // Navigating with control/command key will prevent automatic activation 17498 if ( !event.ctrlKey && !event.metaKey ) { 17499 17500 // Update aria-selected immediately so that AT think the tab is already selected. 17501 // Otherwise AT may confuse the user by stating that they need to activate the tab, 17502 // but the tab will already be activated by the time the announcement finishes. 17503 focusedTab.attr( "aria-selected", "false" ); 17504 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); 17505 17506 this.activating = this._delay( function() { 17507 this.option( "active", selectedIndex ); 17508 }, this.delay ); 17509 } 17510 }, 17511 17512 _panelKeydown: function( event ) { 17513 if ( this._handlePageNav( event ) ) { 17514 return; 17515 } 17516 17517 // Ctrl+up moves focus to the current tab 17518 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { 17519 event.preventDefault(); 17520 this.active.trigger( "focus" ); 17521 } 17522 }, 17523 17524 // Alt+page up/down moves focus to the previous/next tab (and activates) 17525 _handlePageNav: function( event ) { 17526 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { 17527 this._activate( this._focusNextTab( this.options.active - 1, false ) ); 17528 return true; 17529 } 17530 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { 17531 this._activate( this._focusNextTab( this.options.active + 1, true ) ); 17532 return true; 17533 } 17534 }, 17535 17536 _findNextTab: function( index, goingForward ) { 17537 var lastTabIndex = this.tabs.length - 1; 17538 17539 function constrain() { 17540 if ( index > lastTabIndex ) { 17541 index = 0; 17542 } 17543 if ( index < 0 ) { 17544 index = lastTabIndex; 17545 } 17546 return index; 17547 } 17548 17549 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { 17550 index = goingForward ? index + 1 : index - 1; 17551 } 17552 17553 return index; 17554 }, 17555 17556 _focusNextTab: function( index, goingForward ) { 17557 index = this._findNextTab( index, goingForward ); 17558 this.tabs.eq( index ).trigger( "focus" ); 17559 return index; 17560 }, 17561 17562 _setOption: function( key, value ) { 17563 if ( key === "active" ) { 17564 17565 // _activate() will handle invalid values and update this.options 17566 this._activate( value ); 17567 return; 17568 } 17569 17570 this._super( key, value ); 17571 17572 if ( key === "collapsible" ) { 17573 this._toggleClass( "ui-tabs-collapsible", null, value ); 17574 17575 // Setting collapsible: false while collapsed; open first panel 17576 if ( !value && this.options.active === false ) { 17577 this._activate( 0 ); 17578 } 17579 } 17580 17581 if ( key === "event" ) { 17582 this._setupEvents( value ); 17583 } 17584 17585 if ( key === "heightStyle" ) { 17586 this._setupHeightStyle( value ); 17587 } 17588 }, 17589 17590 _sanitizeSelector: function( hash ) { 17591 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; 17592 }, 17593 17594 refresh: function() { 17595 var options = this.options, 17596 lis = this.tablist.children( ":has(a[href])" ); 17597 17598 // Get disabled tabs from class attribute from HTML 17599 // this will get converted to a boolean if needed in _refresh() 17600 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { 17601 return lis.index( tab ); 17602 } ); 17603 17604 this._processTabs(); 17605 17606 // Was collapsed or no tabs 17607 if ( options.active === false || !this.anchors.length ) { 17608 options.active = false; 17609 this.active = $(); 17610 17611 // was active, but active tab is gone 17612 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { 17613 17614 // all remaining tabs are disabled 17615 if ( this.tabs.length === options.disabled.length ) { 17616 options.active = false; 17617 this.active = $(); 17618 17619 // activate previous tab 17620 } else { 17621 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); 17622 } 17623 17624 // was active, active tab still exists 17625 } else { 17626 17627 // make sure active index is correct 17628 options.active = this.tabs.index( this.active ); 17629 } 17630 17631 this._refresh(); 17632 }, 17633 17634 _refresh: function() { 17635 this._setOptionDisabled( this.options.disabled ); 17636 this._setupEvents( this.options.event ); 17637 this._setupHeightStyle( this.options.heightStyle ); 17638 17639 this.tabs.not( this.active ).attr( { 17640 "aria-selected": "false", 17641 "aria-expanded": "false", 17642 tabIndex: -1 17643 } ); 17644 this.panels.not( this._getPanelForTab( this.active ) ) 17645 .hide() 17646 .attr( { 17647 "aria-hidden": "true" 17648 } ); 17649 17650 // Make sure one tab is in the tab order 17651 if ( !this.active.length ) { 17652 this.tabs.eq( 0 ).attr( "tabIndex", 0 ); 17653 } else { 17654 this.active 17655 .attr( { 17656 "aria-selected": "true", 17657 "aria-expanded": "true", 17658 tabIndex: 0 17659 } ); 17660 this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); 17661 this._getPanelForTab( this.active ) 17662 .show() 17663 .attr( { 17664 "aria-hidden": "false" 17665 } ); 17666 } 17667 }, 17668 17669 _processTabs: function() { 17670 var that = this, 17671 prevTabs = this.tabs, 17672 prevAnchors = this.anchors, 17673 prevPanels = this.panels; 17674 17675 this.tablist = this._getList().attr( "role", "tablist" ); 17676 this._addClass( this.tablist, "ui-tabs-nav", 17677 "ui-helper-reset ui-helper-clearfix ui-widget-header" ); 17678 17679 // Prevent users from focusing disabled tabs via click 17680 this.tablist 17681 .on( "mousedown" + this.eventNamespace, "> li", function( event ) { 17682 if ( $( this ).is( ".ui-state-disabled" ) ) { 17683 event.preventDefault(); 17684 } 17685 } ) 17686 17687 // Support: IE <9 17688 // Preventing the default action in mousedown doesn't prevent IE 17689 // from focusing the element, so if the anchor gets focused, blur. 17690 // We don't have to worry about focusing the previously focused 17691 // element since clicking on a non-focusable element should focus 17692 // the body anyway. 17693 .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() { 17694 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { 17695 this.blur(); 17696 } 17697 } ); 17698 17699 this.tabs = this.tablist.find( "> li:has(a[href])" ) 17700 .attr( { 17701 role: "tab", 17702 tabIndex: -1 17703 } ); 17704 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); 17705 17706 this.anchors = this.tabs.map( function() { 17707 return $( "a", this )[ 0 ]; 17708 } ) 17709 .attr( { 17710 role: "presentation", 17711 tabIndex: -1 17712 } ); 17713 this._addClass( this.anchors, "ui-tabs-anchor" ); 17714 17715 this.panels = $(); 17716 17717 this.anchors.each( function( i, anchor ) { 17718 var selector, panel, panelId, 17719 anchorId = $( anchor ).uniqueId().attr( "id" ), 17720 tab = $( anchor ).closest( "li" ), 17721 originalAriaControls = tab.attr( "aria-controls" ); 17722 17723 // Inline tab 17724 if ( that._isLocal( anchor ) ) { 17725 selector = anchor.hash; 17726 panelId = selector.substring( 1 ); 17727 panel = that.element.find( that._sanitizeSelector( selector ) ); 17728 17729 // remote tab 17730 } else { 17731 17732 // If the tab doesn't already have aria-controls, 17733 // generate an id by using a throw-away element 17734 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; 17735 selector = "#" + panelId; 17736 panel = that.element.find( selector ); 17737 if ( !panel.length ) { 17738 panel = that._createPanel( panelId ); 17739 panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); 17740 } 17741 panel.attr( "aria-live", "polite" ); 17742 } 17743 17744 if ( panel.length ) { 17745 that.panels = that.panels.add( panel ); 17746 } 17747 if ( originalAriaControls ) { 17748 tab.data( "ui-tabs-aria-controls", originalAriaControls ); 17749 } 17750 tab.attr( { 17751 "aria-controls": panelId, 17752 "aria-labelledby": anchorId 17753 } ); 17754 panel.attr( "aria-labelledby", anchorId ); 17755 } ); 17756 17757 this.panels.attr( "role", "tabpanel" ); 17758 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); 17759 17760 // Avoid memory leaks (#10056) 17761 if ( prevTabs ) { 17762 this._off( prevTabs.not( this.tabs ) ); 17763 this._off( prevAnchors.not( this.anchors ) ); 17764 this._off( prevPanels.not( this.panels ) ); 17765 } 17766 }, 17767 17768 // Allow overriding how to find the list for rare usage scenarios (#7715) 17769 _getList: function() { 17770 return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); 17771 }, 17772 17773 _createPanel: function( id ) { 17774 return $( "<div>" ) 17775 .attr( "id", id ) 17776 .data( "ui-tabs-destroy", true ); 17777 }, 17778 17779 _setOptionDisabled: function( disabled ) { 17780 var currentItem, li, i; 17781 17782 if ( $.isArray( disabled ) ) { 17783 if ( !disabled.length ) { 17784 disabled = false; 17785 } else if ( disabled.length === this.anchors.length ) { 17786 disabled = true; 17787 } 17788 } 17789 17790 // Disable tabs 17791 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { 17792 currentItem = $( li ); 17793 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { 17794 currentItem.attr( "aria-disabled", "true" ); 17795 this._addClass( currentItem, null, "ui-state-disabled" ); 17796 } else { 17797 currentItem.removeAttr( "aria-disabled" ); 17798 this._removeClass( currentItem, null, "ui-state-disabled" ); 17799 } 17800 } 17801 17802 this.options.disabled = disabled; 17803 17804 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, 17805 disabled === true ); 17806 }, 17807 17808 _setupEvents: function( event ) { 17809 var events = {}; 17810 if ( event ) { 17811 $.each( event.split( " " ), function( index, eventName ) { 17812 events[ eventName ] = "_eventHandler"; 17813 } ); 17814 } 17815 17816 this._off( this.anchors.add( this.tabs ).add( this.panels ) ); 17817 17818 // Always prevent the default action, even when disabled 17819 this._on( true, this.anchors, { 17820 click: function( event ) { 17821 event.preventDefault(); 17822 } 17823 } ); 17824 this._on( this.anchors, events ); 17825 this._on( this.tabs, { keydown: "_tabKeydown" } ); 17826 this._on( this.panels, { keydown: "_panelKeydown" } ); 17827 17828 this._focusable( this.tabs ); 17829 this._hoverable( this.tabs ); 17830 }, 17831 17832 _setupHeightStyle: function( heightStyle ) { 17833 var maxHeight, 17834 parent = this.element.parent(); 17835 17836 if ( heightStyle === "fill" ) { 17837 maxHeight = parent.height(); 17838 maxHeight -= this.element.outerHeight() - this.element.height(); 17839 17840 this.element.siblings( ":visible" ).each( function() { 17841 var elem = $( this ), 17842 position = elem.css( "position" ); 17843 17844 if ( position === "absolute" || position === "fixed" ) { 17845 return; 17846 } 17847 maxHeight -= elem.outerHeight( true ); 17848 } ); 17849 17850 this.element.children().not( this.panels ).each( function() { 17851 maxHeight -= $( this ).outerHeight( true ); 17852 } ); 17853 17854 this.panels.each( function() { 17855 $( this ).height( Math.max( 0, maxHeight - 17856 $( this ).innerHeight() + $( this ).height() ) ); 17857 } ) 17858 .css( "overflow", "auto" ); 17859 } else if ( heightStyle === "auto" ) { 17860 maxHeight = 0; 17861 this.panels.each( function() { 17862 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 17863 } ).height( maxHeight ); 17864 } 17865 }, 17866 17867 _eventHandler: function( event ) { 17868 var options = this.options, 17869 active = this.active, 17870 anchor = $( event.currentTarget ), 17871 tab = anchor.closest( "li" ), 17872 clickedIsActive = tab[ 0 ] === active[ 0 ], 17873 collapsing = clickedIsActive && options.collapsible, 17874 toShow = collapsing ? $() : this._getPanelForTab( tab ), 17875 toHide = !active.length ? $() : this._getPanelForTab( active ), 17876 eventData = { 17877 oldTab: active, 17878 oldPanel: toHide, 17879 newTab: collapsing ? $() : tab, 17880 newPanel: toShow 17881 }; 17882 17883 event.preventDefault(); 17884 17885 if ( tab.hasClass( "ui-state-disabled" ) || 17886 17887 // tab is already loading 17888 tab.hasClass( "ui-tabs-loading" ) || 17889 17890 // can't switch durning an animation 17891 this.running || 17892 17893 // click on active header, but not collapsible 17894 ( clickedIsActive && !options.collapsible ) || 17895 17896 // allow canceling activation 17897 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 17898 return; 17899 } 17900 17901 options.active = collapsing ? false : this.tabs.index( tab ); 17902 17903 this.active = clickedIsActive ? $() : tab; 17904 if ( this.xhr ) { 17905 this.xhr.abort(); 17906 } 17907 17908 if ( !toHide.length && !toShow.length ) { 17909 $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); 17910 } 17911 17912 if ( toShow.length ) { 17913 this.load( this.tabs.index( tab ), event ); 17914 } 17915 this._toggle( event, eventData ); 17916 }, 17917 17918 // Handles show/hide for selecting tabs 17919 _toggle: function( event, eventData ) { 17920 var that = this, 17921 toShow = eventData.newPanel, 17922 toHide = eventData.oldPanel; 17923 17924 this.running = true; 17925 17926 function complete() { 17927 that.running = false; 17928 that._trigger( "activate", event, eventData ); 17929 } 17930 17931 function show() { 17932 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); 17933 17934 if ( toShow.length && that.options.show ) { 17935 that._show( toShow, that.options.show, complete ); 17936 } else { 17937 toShow.show(); 17938 complete(); 17939 } 17940 } 17941 17942 // Start out by hiding, then showing, then completing 17943 if ( toHide.length && this.options.hide ) { 17944 this._hide( toHide, this.options.hide, function() { 17945 that._removeClass( eventData.oldTab.closest( "li" ), 17946 "ui-tabs-active", "ui-state-active" ); 17947 show(); 17948 } ); 17949 } else { 17950 this._removeClass( eventData.oldTab.closest( "li" ), 17951 "ui-tabs-active", "ui-state-active" ); 17952 toHide.hide(); 17953 show(); 17954 } 17955 17956 toHide.attr( "aria-hidden", "true" ); 17957 eventData.oldTab.attr( { 17958 "aria-selected": "false", 17959 "aria-expanded": "false" 17960 } ); 17961 17962 // If we're switching tabs, remove the old tab from the tab order. 17963 // If we're opening from collapsed state, remove the previous tab from the tab order. 17964 // If we're collapsing, then keep the collapsing tab in the tab order. 17965 if ( toShow.length && toHide.length ) { 17966 eventData.oldTab.attr( "tabIndex", -1 ); 17967 } else if ( toShow.length ) { 17968 this.tabs.filter( function() { 17969 return $( this ).attr( "tabIndex" ) === 0; 17970 } ) 17971 .attr( "tabIndex", -1 ); 17972 } 17973 17974 toShow.attr( "aria-hidden", "false" ); 17975 eventData.newTab.attr( { 17976 "aria-selected": "true", 17977 "aria-expanded": "true", 17978 tabIndex: 0 17979 } ); 17980 }, 17981 17982 _activate: function( index ) { 17983 var anchor, 17984 active = this._findActive( index ); 17985 17986 // Trying to activate the already active panel 17987 if ( active[ 0 ] === this.active[ 0 ] ) { 17988 return; 17989 } 17990 17991 // Trying to collapse, simulate a click on the current active header 17992 if ( !active.length ) { 17993 active = this.active; 17994 } 17995 17996 anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; 17997 this._eventHandler( { 17998 target: anchor, 17999 currentTarget: anchor, 18000 preventDefault: $.noop 18001 } ); 18002 }, 18003 18004 _findActive: function( index ) { 18005 return index === false ? $() : this.tabs.eq( index ); 18006 }, 18007 18008 _getIndex: function( index ) { 18009 18010 // meta-function to give users option to provide a href string instead of a numerical index. 18011 if ( typeof index === "string" ) { 18012 index = this.anchors.index( this.anchors.filter( "[href$='" + 18013 $.ui.escapeSelector( index ) + "']" ) ); 18014 } 18015 18016 return index; 18017 }, 18018 18019 _destroy: function() { 18020 if ( this.xhr ) { 18021 this.xhr.abort(); 18022 } 18023 18024 this.tablist 18025 .removeAttr( "role" ) 18026 .off( this.eventNamespace ); 18027 18028 this.anchors 18029 .removeAttr( "role tabIndex" ) 18030 .removeUniqueId(); 18031 18032 this.tabs.add( this.panels ).each( function() { 18033 if ( $.data( this, "ui-tabs-destroy" ) ) { 18034 $( this ).remove(); 18035 } else { 18036 $( this ).removeAttr( "role tabIndex " + 18037 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); 18038 } 18039 } ); 18040 18041 this.tabs.each( function() { 18042 var li = $( this ), 18043 prev = li.data( "ui-tabs-aria-controls" ); 18044 if ( prev ) { 18045 li 18046 .attr( "aria-controls", prev ) 18047 .removeData( "ui-tabs-aria-controls" ); 18048 } else { 18049 li.removeAttr( "aria-controls" ); 18050 } 18051 } ); 18052 18053 this.panels.show(); 18054 18055 if ( this.options.heightStyle !== "content" ) { 18056 this.panels.css( "height", "" ); 18057 } 18058 }, 18059 18060 enable: function( index ) { 18061 var disabled = this.options.disabled; 18062 if ( disabled === false ) { 18063 return; 18064 } 18065 18066 if ( index === undefined ) { 18067 disabled = false; 18068 } else { 18069 index = this._getIndex( index ); 18070 if ( $.isArray( disabled ) ) { 18071 disabled = $.map( disabled, function( num ) { 18072 return num !== index ? num : null; 18073 } ); 18074 } else { 18075 disabled = $.map( this.tabs, function( li, num ) { 18076 return num !== index ? num : null; 18077 } ); 18078 } 18079 } 18080 this._setOptionDisabled( disabled ); 18081 }, 18082 18083 disable: function( index ) { 18084 var disabled = this.options.disabled; 18085 if ( disabled === true ) { 18086 return; 18087 } 18088 18089 if ( index === undefined ) { 18090 disabled = true; 18091 } else { 18092 index = this._getIndex( index ); 18093 if ( $.inArray( index, disabled ) !== -1 ) { 18094 return; 18095 } 18096 if ( $.isArray( disabled ) ) { 18097 disabled = $.merge( [ index ], disabled ).sort(); 18098 } else { 18099 disabled = [ index ]; 18100 } 18101 } 18102 this._setOptionDisabled( disabled ); 18103 }, 18104 18105 load: function( index, event ) { 18106 index = this._getIndex( index ); 18107 var that = this, 18108 tab = this.tabs.eq( index ), 18109 anchor = tab.find( ".ui-tabs-anchor" ), 18110 panel = this._getPanelForTab( tab ), 18111 eventData = { 18112 tab: tab, 18113 panel: panel 18114 }, 18115 complete = function( jqXHR, status ) { 18116 if ( status === "abort" ) { 18117 that.panels.stop( false, true ); 18118 } 18119 18120 that._removeClass( tab, "ui-tabs-loading" ); 18121 panel.removeAttr( "aria-busy" ); 18122 18123 if ( jqXHR === that.xhr ) { 18124 delete that.xhr; 18125 } 18126 }; 18127 18128 // Not remote 18129 if ( this._isLocal( anchor[ 0 ] ) ) { 18130 return; 18131 } 18132 18133 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); 18134 18135 // Support: jQuery <1.8 18136 // jQuery <1.8 returns false if the request is canceled in beforeSend, 18137 // but as of 1.8, $.ajax() always returns a jqXHR object. 18138 if ( this.xhr && this.xhr.statusText !== "canceled" ) { 18139 this._addClass( tab, "ui-tabs-loading" ); 18140 panel.attr( "aria-busy", "true" ); 18141 18142 this.xhr 18143 .done( function( response, status, jqXHR ) { 18144 18145 // support: jQuery <1.8 18146 // http://bugs.jquery.com/ticket/11778 18147 setTimeout( function() { 18148 panel.html( response ); 18149 that._trigger( "load", event, eventData ); 18150 18151 complete( jqXHR, status ); 18152 }, 1 ); 18153 } ) 18154 .fail( function( jqXHR, status ) { 18155 18156 // support: jQuery <1.8 18157 // http://bugs.jquery.com/ticket/11778 18158 setTimeout( function() { 18159 complete( jqXHR, status ); 18160 }, 1 ); 18161 } ); 18162 } 18163 }, 18164 18165 _ajaxSettings: function( anchor, event, eventData ) { 18166 var that = this; 18167 return { 18168 18169 // Support: IE <11 only 18170 // Strip any hash that exists to prevent errors with the Ajax request 18171 url: anchor.attr( "href" ).replace( /#.*$/, "" ), 18172 beforeSend: function( jqXHR, settings ) { 18173 return that._trigger( "beforeLoad", event, 18174 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); 18175 } 18176 }; 18177 }, 18178 18179 _getPanelForTab: function( tab ) { 18180 var id = $( tab ).attr( "aria-controls" ); 18181 return this.element.find( this._sanitizeSelector( "#" + id ) ); 18182 } 18183 } ); 18184 18185 // DEPRECATED 18186 // TODO: Switch return back to widget declaration at top of file when this is removed 18187 if ( $.uiBackCompat !== false ) { 18188 18189 // Backcompat for ui-tab class (now ui-tabs-tab) 18190 $.widget( "ui.tabs", $.ui.tabs, { 18191 _processTabs: function() { 18192 this._superApply( arguments ); 18193 this._addClass( this.tabs, "ui-tab" ); 18194 } 18195 } ); 18196 } 18197 18198 var widgetsTabs = $.ui.tabs; 18199 18200 18201 /*! 18202 * jQuery UI Tooltip 1.12.1 18203 * http://jqueryui.com 18204 * 18205 * Copyright jQuery Foundation and other contributors 18206 * Released under the MIT license. 18207 * http://jquery.org/license 18208 */ 18209 18210 //>>label: Tooltip 18211 //>>group: Widgets 18212 //>>description: Shows additional information for any element on hover or focus. 18213 //>>docs: http://api.jqueryui.com/tooltip/ 18214 //>>demos: http://jqueryui.com/tooltip/ 18215 //>>css.structure: ../../themes/base/core.css 18216 //>>css.structure: ../../themes/base/tooltip.css 18217 //>>css.theme: ../../themes/base/theme.css 18218 18219 18220 18221 $.widget( "ui.tooltip", { 18222 version: "1.12.1", 18223 options: { 18224 classes: { 18225 "ui-tooltip": "ui-corner-all ui-widget-shadow" 18226 }, 18227 content: function() { 18228 18229 // support: IE<9, Opera in jQuery <1.7 18230 // .text() can't accept undefined, so coerce to a string 18231 var title = $( this ).attr( "title" ) || ""; 18232 18233 // Escape title, since we're going from an attribute to raw HTML 18234 return $( "<a>" ).text( title ).html(); 18235 }, 18236 hide: true, 18237 18238 // Disabled elements have inconsistent behavior across browsers (#8661) 18239 items: "[title]:not([disabled])", 18240 position: { 18241 my: "left top+15", 18242 at: "left bottom", 18243 collision: "flipfit flip" 18244 }, 18245 show: true, 18246 track: false, 18247 18248 // Callbacks 18249 close: null, 18250 open: null 18251 }, 18252 18253 _addDescribedBy: function( elem, id ) { 18254 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); 18255 describedby.push( id ); 18256 elem 18257 .data( "ui-tooltip-id", id ) 18258 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); 18259 }, 18260 18261 _removeDescribedBy: function( elem ) { 18262 var id = elem.data( "ui-tooltip-id" ), 18263 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), 18264 index = $.inArray( id, describedby ); 18265 18266 if ( index !== -1 ) { 18267 describedby.splice( index, 1 ); 18268 } 18269 18270 elem.removeData( "ui-tooltip-id" ); 18271 describedby = $.trim( describedby.join( " " ) ); 18272 if ( describedby ) { 18273 elem.attr( "aria-describedby", describedby ); 18274 } else { 18275 elem.removeAttr( "aria-describedby" ); 18276 } 18277 }, 18278 18279 _create: function() { 18280 this._on( { 18281 mouseover: "open", 18282 focusin: "open" 18283 } ); 18284 18285 // IDs of generated tooltips, needed for destroy 18286 this.tooltips = {}; 18287 18288 // IDs of parent tooltips where we removed the title attribute 18289 this.parents = {}; 18290 18291 // Append the aria-live region so tooltips announce correctly 18292 this.liveRegion = $( "<div>" ) 18293 .attr( { 18294 role: "log", 18295 "aria-live": "assertive", 18296 "aria-relevant": "additions" 18297 } ) 18298 .appendTo( this.document[ 0 ].body ); 18299 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 18300 18301 this.disabledTitles = $( [] ); 18302 }, 18303 18304 _setOption: function( key, value ) { 18305 var that = this; 18306 18307 this._super( key, value ); 18308 18309 if ( key === "content" ) { 18310 $.each( this.tooltips, function( id, tooltipData ) { 18311 that._updateContent( tooltipData.element ); 18312 } ); 18313 } 18314 }, 18315 18316 _setOptionDisabled: function( value ) { 18317 this[ value ? "_disable" : "_enable" ](); 18318 }, 18319 18320 _disable: function() { 18321 var that = this; 18322 18323 // Close open tooltips 18324 $.each( this.tooltips, function( id, tooltipData ) { 18325 var event = $.Event( "blur" ); 18326 event.target = event.currentTarget = tooltipData.element[ 0 ]; 18327 that.close( event, true ); 18328 } ); 18329 18330 // Remove title attributes to prevent native tooltips 18331 this.disabledTitles = this.disabledTitles.add( 18332 this.element.find( this.options.items ).addBack() 18333 .filter( function() { 18334 var element = $( this ); 18335 if ( element.is( "[title]" ) ) { 18336 return element 18337 .data( "ui-tooltip-title", element.attr( "title" ) ) 18338 .removeAttr( "title" ); 18339 } 18340 } ) 18341 ); 18342 }, 18343 18344 _enable: function() { 18345 18346 // restore title attributes 18347 this.disabledTitles.each( function() { 18348 var element = $( this ); 18349 if ( element.data( "ui-tooltip-title" ) ) { 18350 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18351 } 18352 } ); 18353 this.disabledTitles = $( [] ); 18354 }, 18355 18356 open: function( event ) { 18357 var that = this, 18358 target = $( event ? event.target : this.element ) 18359 18360 // we need closest here due to mouseover bubbling, 18361 // but always pointing at the same event target 18362 .closest( this.options.items ); 18363 18364 // No element to show a tooltip for or the tooltip is already open 18365 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 18366 return; 18367 } 18368 18369 if ( target.attr( "title" ) ) { 18370 target.data( "ui-tooltip-title", target.attr( "title" ) ); 18371 } 18372 18373 target.data( "ui-tooltip-open", true ); 18374 18375 // Kill parent tooltips, custom or native, for hover 18376 if ( event && event.type === "mouseover" ) { 18377 target.parents().each( function() { 18378 var parent = $( this ), 18379 blurEvent; 18380 if ( parent.data( "ui-tooltip-open" ) ) { 18381 blurEvent = $.Event( "blur" ); 18382 blurEvent.target = blurEvent.currentTarget = this; 18383 that.close( blurEvent, true ); 18384 } 18385 if ( parent.attr( "title" ) ) { 18386 parent.uniqueId(); 18387 that.parents[ this.id ] = { 18388 element: this, 18389 title: parent.attr( "title" ) 18390 }; 18391 parent.attr( "title", "" ); 18392 } 18393 } ); 18394 } 18395 18396 this._registerCloseHandlers( event, target ); 18397 this._updateContent( target, event ); 18398 }, 18399 18400 _updateContent: function( target, event ) { 18401 var content, 18402 contentOption = this.options.content, 18403 that = this, 18404 eventType = event ? event.type : null; 18405 18406 if ( typeof contentOption === "string" || contentOption.nodeType || 18407 contentOption.jquery ) { 18408 return this._open( event, target, contentOption ); 18409 } 18410 18411 content = contentOption.call( target[ 0 ], function( response ) { 18412 18413 // IE may instantly serve a cached response for ajax requests 18414 // delay this call to _open so the other call to _open runs first 18415 that._delay( function() { 18416 18417 // Ignore async response if tooltip was closed already 18418 if ( !target.data( "ui-tooltip-open" ) ) { 18419 return; 18420 } 18421 18422 // JQuery creates a special event for focusin when it doesn't 18423 // exist natively. To improve performance, the native event 18424 // object is reused and the type is changed. Therefore, we can't 18425 // rely on the type being correct after the event finished 18426 // bubbling, so we set it back to the previous value. (#8740) 18427 if ( event ) { 18428 event.type = eventType; 18429 } 18430 this._open( event, target, response ); 18431 } ); 18432 } ); 18433 if ( content ) { 18434 this._open( event, target, content ); 18435 } 18436 }, 18437 18438 _open: function( event, target, content ) { 18439 var tooltipData, tooltip, delayedShow, a11yContent, 18440 positionOption = $.extend( {}, this.options.position ); 18441 18442 if ( !content ) { 18443 return; 18444 } 18445 18446 // Content can be updated multiple times. If the tooltip already 18447 // exists, then just update the content and bail. 18448 tooltipData = this._find( target ); 18449 if ( tooltipData ) { 18450 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); 18451 return; 18452 } 18453 18454 // If we have a title, clear it to prevent the native tooltip 18455 // we have to check first to avoid defining a title if none exists 18456 // (we don't want to cause an element to start matching [title]) 18457 // 18458 // We use removeAttr only for key events, to allow IE to export the correct 18459 // accessible attributes. For mouse events, set to empty string to avoid 18460 // native tooltip showing up (happens only when removing inside mouseover). 18461 if ( target.is( "[title]" ) ) { 18462 if ( event && event.type === "mouseover" ) { 18463 target.attr( "title", "" ); 18464 } else { 18465 target.removeAttr( "title" ); 18466 } 18467 } 18468 18469 tooltipData = this._tooltip( target ); 18470 tooltip = tooltipData.tooltip; 18471 this._addDescribedBy( target, tooltip.attr( "id" ) ); 18472 tooltip.find( ".ui-tooltip-content" ).html( content ); 18473 18474 // Support: Voiceover on OS X, JAWS on IE <= 9 18475 // JAWS announces deletions even when aria-relevant="additions" 18476 // Voiceover will sometimes re-read the entire log region's contents from the beginning 18477 this.liveRegion.children().hide(); 18478 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() ); 18479 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); 18480 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 18481 a11yContent.appendTo( this.liveRegion ); 18482 18483 function position( event ) { 18484 positionOption.of = event; 18485 if ( tooltip.is( ":hidden" ) ) { 18486 return; 18487 } 18488 tooltip.position( positionOption ); 18489 } 18490 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 18491 this._on( this.document, { 18492 mousemove: position 18493 } ); 18494 18495 // trigger once to override element-relative positioning 18496 position( event ); 18497 } else { 18498 tooltip.position( $.extend( { 18499 of: target 18500 }, this.options.position ) ); 18501 } 18502 18503 tooltip.hide(); 18504 18505 this._show( tooltip, this.options.show ); 18506 18507 // Handle tracking tooltips that are shown with a delay (#8644). As soon 18508 // as the tooltip is visible, position the tooltip using the most recent 18509 // event. 18510 // Adds the check to add the timers only when both delay and track options are set (#14682) 18511 if ( this.options.track && this.options.show && this.options.show.delay ) { 18512 delayedShow = this.delayedShow = setInterval( function() { 18513 if ( tooltip.is( ":visible" ) ) { 18514 position( positionOption.of ); 18515 clearInterval( delayedShow ); 18516 } 18517 }, $.fx.interval ); 18518 } 18519 18520 this._trigger( "open", event, { tooltip: tooltip } ); 18521 }, 18522 18523 _registerCloseHandlers: function( event, target ) { 18524 var events = { 18525 keyup: function( event ) { 18526 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 18527 var fakeEvent = $.Event( event ); 18528 fakeEvent.currentTarget = target[ 0 ]; 18529 this.close( fakeEvent, true ); 18530 } 18531 } 18532 }; 18533 18534 // Only bind remove handler for delegated targets. Non-delegated 18535 // tooltips will handle this in destroy. 18536 if ( target[ 0 ] !== this.element[ 0 ] ) { 18537 events.remove = function() { 18538 this._removeTooltip( this._find( target ).tooltip ); 18539 }; 18540 } 18541 18542 if ( !event || event.type === "mouseover" ) { 18543 events.mouseleave = "close"; 18544 } 18545 if ( !event || event.type === "focusin" ) { 18546 events.focusout = "close"; 18547 } 18548 this._on( true, target, events ); 18549 }, 18550 18551 close: function( event ) { 18552 var tooltip, 18553 that = this, 18554 target = $( event ? event.currentTarget : this.element ), 18555 tooltipData = this._find( target ); 18556 18557 // The tooltip may already be closed 18558 if ( !tooltipData ) { 18559 18560 // We set ui-tooltip-open immediately upon open (in open()), but only set the 18561 // additional data once there's actually content to show (in _open()). So even if the 18562 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in 18563 // the period between open() and _open(). 18564 target.removeData( "ui-tooltip-open" ); 18565 return; 18566 } 18567 18568 tooltip = tooltipData.tooltip; 18569 18570 // Disabling closes the tooltip, so we need to track when we're closing 18571 // to avoid an infinite loop in case the tooltip becomes disabled on close 18572 if ( tooltipData.closing ) { 18573 return; 18574 } 18575 18576 // Clear the interval for delayed tracking tooltips 18577 clearInterval( this.delayedShow ); 18578 18579 // Only set title if we had one before (see comment in _open()) 18580 // If the title attribute has changed since open(), don't restore 18581 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 18582 target.attr( "title", target.data( "ui-tooltip-title" ) ); 18583 } 18584 18585 this._removeDescribedBy( target ); 18586 18587 tooltipData.hiding = true; 18588 tooltip.stop( true ); 18589 this._hide( tooltip, this.options.hide, function() { 18590 that._removeTooltip( $( this ) ); 18591 } ); 18592 18593 target.removeData( "ui-tooltip-open" ); 18594 this._off( target, "mouseleave focusout keyup" ); 18595 18596 // Remove 'remove' binding only on delegated targets 18597 if ( target[ 0 ] !== this.element[ 0 ] ) { 18598 this._off( target, "remove" ); 18599 } 18600 this._off( this.document, "mousemove" ); 18601 18602 if ( event && event.type === "mouseleave" ) { 18603 $.each( this.parents, function( id, parent ) { 18604 $( parent.element ).attr( "title", parent.title ); 18605 delete that.parents[ id ]; 18606 } ); 18607 } 18608 18609 tooltipData.closing = true; 18610 this._trigger( "close", event, { tooltip: tooltip } ); 18611 if ( !tooltipData.hiding ) { 18612 tooltipData.closing = false; 18613 } 18614 }, 18615 18616 _tooltip: function( element ) { 18617 var tooltip = $( "<div>" ).attr( "role", "tooltip" ), 18618 content = $( "<div>" ).appendTo( tooltip ), 18619 id = tooltip.uniqueId().attr( "id" ); 18620 18621 this._addClass( content, "ui-tooltip-content" ); 18622 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); 18623 18624 tooltip.appendTo( this._appendTo( element ) ); 18625 18626 return this.tooltips[ id ] = { 18627 element: element, 18628 tooltip: tooltip 18629 }; 18630 }, 18631 18632 _find: function( target ) { 18633 var id = target.data( "ui-tooltip-id" ); 18634 return id ? this.tooltips[ id ] : null; 18635 }, 18636 18637 _removeTooltip: function( tooltip ) { 18638 tooltip.remove(); 18639 delete this.tooltips[ tooltip.attr( "id" ) ]; 18640 }, 18641 18642 _appendTo: function( target ) { 18643 var element = target.closest( ".ui-front, dialog" ); 18644 18645 if ( !element.length ) { 18646 element = this.document[ 0 ].body; 18647 } 18648 18649 return element; 18650 }, 18651 18652 _destroy: function() { 18653 var that = this; 18654 18655 // Close open tooltips 18656 $.each( this.tooltips, function( id, tooltipData ) { 18657 18658 // Delegate to close method to handle common cleanup 18659 var event = $.Event( "blur" ), 18660 element = tooltipData.element; 18661 event.target = event.currentTarget = element[ 0 ]; 18662 that.close( event, true ); 18663 18664 // Remove immediately; destroying an open tooltip doesn't use the 18665 // hide animation 18666 $( "#" + id ).remove(); 18667 18668 // Restore the title 18669 if ( element.data( "ui-tooltip-title" ) ) { 18670 18671 // If the title attribute has changed since open(), don't restore 18672 if ( !element.attr( "title" ) ) { 18673 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18674 } 18675 element.removeData( "ui-tooltip-title" ); 18676 } 18677 } ); 18678 this.liveRegion.remove(); 18679 } 18680 } ); 18681 18682 // DEPRECATED 18683 // TODO: Switch return back to widget declaration at top of file when this is removed 18684 if ( $.uiBackCompat !== false ) { 18685 18686 // Backcompat for tooltipClass option 18687 $.widget( "ui.tooltip", $.ui.tooltip, { 18688 options: { 18689 tooltipClass: null 18690 }, 18691 _tooltip: function() { 18692 var tooltipData = this._superApply( arguments ); 18693 if ( this.options.tooltipClass ) { 18694 tooltipData.tooltip.addClass( this.options.tooltipClass ); 18695 } 18696 return tooltipData; 18697 } 18698 } ); 18699 } 18700 18701 var widgetsTooltip = $.ui.tooltip; 18702 18703 18704 18705 18706 }));