jquery-ui.js (539425B)
1 /*! jQuery UI - v1.12.1 - 2016-09-14 2 * http://jqueryui.com 3 * 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 4 * Copyright jQuery Foundation and other contributors; Licensed MIT */ 5 6 (function( factory ) { 7 if ( typeof define === "function" && define.amd ) { 8 9 // AMD. Register as an anonymous module. 10 define([ "jquery" ], factory ); 11 } else { 12 13 // Browser globals 14 factory( jQuery ); 15 } 16 }(function( $ ) { 17 18 $.ui = $.ui || {}; 19 20 var version = $.ui.version = "1.12.1"; 21 22 23 /*! 24 * jQuery UI Widget 1.12.1 25 * http://jqueryui.com 26 * 27 * Copyright jQuery Foundation and other contributors 28 * Released under the MIT license. 29 * http://jquery.org/license 30 */ 31 32 //>>label: Widget 33 //>>group: Core 34 //>>description: Provides a factory for creating stateful widgets with a common API. 35 //>>docs: http://api.jqueryui.com/jQuery.widget/ 36 //>>demos: http://jqueryui.com/widget/ 37 38 39 40 var widgetUuid = 0; 41 var widgetSlice = Array.prototype.slice; 42 43 $.cleanData = ( function( orig ) { 44 return function( elems ) { 45 var events, elem, i; 46 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { 47 try { 48 49 // Only trigger remove when necessary to save time 50 events = $._data( elem, "events" ); 51 if ( events && events.remove ) { 52 $( elem ).triggerHandler( "remove" ); 53 } 54 55 // Http://bugs.jquery.com/ticket/8235 56 } catch ( e ) {} 57 } 58 orig( elems ); 59 }; 60 } )( $.cleanData ); 61 62 $.widget = function( name, base, prototype ) { 63 var existingConstructor, constructor, basePrototype; 64 65 // ProxiedPrototype allows the provided prototype to remain unmodified 66 // so that it can be used as a mixin for multiple widgets (#8876) 67 var proxiedPrototype = {}; 68 69 var namespace = name.split( "." )[ 0 ]; 70 name = name.split( "." )[ 1 ]; 71 var fullName = namespace + "-" + name; 72 73 if ( !prototype ) { 74 prototype = base; 75 base = $.Widget; 76 } 77 78 if ( $.isArray( prototype ) ) { 79 prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); 80 } 81 82 // Create selector for plugin 83 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 84 return !!$.data( elem, fullName ); 85 }; 86 87 $[ namespace ] = $[ namespace ] || {}; 88 existingConstructor = $[ namespace ][ name ]; 89 constructor = $[ namespace ][ name ] = function( options, element ) { 90 91 // Allow instantiation without "new" keyword 92 if ( !this._createWidget ) { 93 return new constructor( options, element ); 94 } 95 96 // Allow instantiation without initializing for simple inheritance 97 // must use "new" keyword (the code above always passes args) 98 if ( arguments.length ) { 99 this._createWidget( options, element ); 100 } 101 }; 102 103 // Extend with the existing constructor to carry over any static properties 104 $.extend( constructor, existingConstructor, { 105 version: prototype.version, 106 107 // Copy the object used to create the prototype in case we need to 108 // redefine the widget later 109 _proto: $.extend( {}, prototype ), 110 111 // Track widgets that inherit from this widget in case this widget is 112 // redefined after a widget inherits from it 113 _childConstructors: [] 114 } ); 115 116 basePrototype = new base(); 117 118 // We need to make the options hash a property directly on the new instance 119 // otherwise we'll modify the options hash on the prototype that we're 120 // inheriting from 121 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 122 $.each( prototype, function( prop, value ) { 123 if ( !$.isFunction( value ) ) { 124 proxiedPrototype[ prop ] = value; 125 return; 126 } 127 proxiedPrototype[ prop ] = ( function() { 128 function _super() { 129 return base.prototype[ prop ].apply( this, arguments ); 130 } 131 132 function _superApply( args ) { 133 return base.prototype[ prop ].apply( this, args ); 134 } 135 136 return function() { 137 var __super = this._super; 138 var __superApply = this._superApply; 139 var returnValue; 140 141 this._super = _super; 142 this._superApply = _superApply; 143 144 returnValue = value.apply( this, arguments ); 145 146 this._super = __super; 147 this._superApply = __superApply; 148 149 return returnValue; 150 }; 151 } )(); 152 } ); 153 constructor.prototype = $.widget.extend( basePrototype, { 154 155 // TODO: remove support for widgetEventPrefix 156 // always use the name + a colon as the prefix, e.g., draggable:start 157 // don't prefix for widgets that aren't DOM-based 158 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name 159 }, proxiedPrototype, { 160 constructor: constructor, 161 namespace: namespace, 162 widgetName: name, 163 widgetFullName: fullName 164 } ); 165 166 // If this widget is being redefined then we need to find all widgets that 167 // are inheriting from it and redefine all of them so that they inherit from 168 // the new version of this widget. We're essentially trying to replace one 169 // level in the prototype chain. 170 if ( existingConstructor ) { 171 $.each( existingConstructor._childConstructors, function( i, child ) { 172 var childPrototype = child.prototype; 173 174 // Redefine the child widget using the same prototype that was 175 // originally used, but inherit from the new version of the base 176 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, 177 child._proto ); 178 } ); 179 180 // Remove the list of existing child constructors from the old constructor 181 // so the old child constructors can be garbage collected 182 delete existingConstructor._childConstructors; 183 } else { 184 base._childConstructors.push( constructor ); 185 } 186 187 $.widget.bridge( name, constructor ); 188 189 return constructor; 190 }; 191 192 $.widget.extend = function( target ) { 193 var input = widgetSlice.call( arguments, 1 ); 194 var inputIndex = 0; 195 var inputLength = input.length; 196 var key; 197 var value; 198 199 for ( ; inputIndex < inputLength; inputIndex++ ) { 200 for ( key in input[ inputIndex ] ) { 201 value = input[ inputIndex ][ key ]; 202 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 203 204 // Clone objects 205 if ( $.isPlainObject( value ) ) { 206 target[ key ] = $.isPlainObject( target[ key ] ) ? 207 $.widget.extend( {}, target[ key ], value ) : 208 209 // Don't extend strings, arrays, etc. with objects 210 $.widget.extend( {}, value ); 211 212 // Copy everything else by reference 213 } else { 214 target[ key ] = value; 215 } 216 } 217 } 218 } 219 return target; 220 }; 221 222 $.widget.bridge = function( name, object ) { 223 var fullName = object.prototype.widgetFullName || name; 224 $.fn[ name ] = function( options ) { 225 var isMethodCall = typeof options === "string"; 226 var args = widgetSlice.call( arguments, 1 ); 227 var returnValue = this; 228 229 if ( isMethodCall ) { 230 231 // If this is an empty collection, we need to have the instance method 232 // return undefined instead of the jQuery instance 233 if ( !this.length && options === "instance" ) { 234 returnValue = undefined; 235 } else { 236 this.each( function() { 237 var methodValue; 238 var instance = $.data( this, fullName ); 239 240 if ( options === "instance" ) { 241 returnValue = instance; 242 return false; 243 } 244 245 if ( !instance ) { 246 return $.error( "cannot call methods on " + name + 247 " prior to initialization; " + 248 "attempted to call method '" + options + "'" ); 249 } 250 251 if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) { 252 return $.error( "no such method '" + options + "' for " + name + 253 " widget instance" ); 254 } 255 256 methodValue = instance[ options ].apply( instance, args ); 257 258 if ( methodValue !== instance && methodValue !== undefined ) { 259 returnValue = methodValue && methodValue.jquery ? 260 returnValue.pushStack( methodValue.get() ) : 261 methodValue; 262 return false; 263 } 264 } ); 265 } 266 } else { 267 268 // Allow multiple hashes to be passed on init 269 if ( args.length ) { 270 options = $.widget.extend.apply( null, [ options ].concat( args ) ); 271 } 272 273 this.each( function() { 274 var instance = $.data( this, fullName ); 275 if ( instance ) { 276 instance.option( options || {} ); 277 if ( instance._init ) { 278 instance._init(); 279 } 280 } else { 281 $.data( this, fullName, new object( options, this ) ); 282 } 283 } ); 284 } 285 286 return returnValue; 287 }; 288 }; 289 290 $.Widget = function( /* options, element */ ) {}; 291 $.Widget._childConstructors = []; 292 293 $.Widget.prototype = { 294 widgetName: "widget", 295 widgetEventPrefix: "", 296 defaultElement: "<div>", 297 298 options: { 299 classes: {}, 300 disabled: false, 301 302 // Callbacks 303 create: null 304 }, 305 306 _createWidget: function( options, element ) { 307 element = $( element || this.defaultElement || this )[ 0 ]; 308 this.element = $( element ); 309 this.uuid = widgetUuid++; 310 this.eventNamespace = "." + this.widgetName + this.uuid; 311 312 this.bindings = $(); 313 this.hoverable = $(); 314 this.focusable = $(); 315 this.classesElementLookup = {}; 316 317 if ( element !== this ) { 318 $.data( element, this.widgetFullName, this ); 319 this._on( true, this.element, { 320 remove: function( event ) { 321 if ( event.target === element ) { 322 this.destroy(); 323 } 324 } 325 } ); 326 this.document = $( element.style ? 327 328 // Element within the document 329 element.ownerDocument : 330 331 // Element is window or document 332 element.document || element ); 333 this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); 334 } 335 336 this.options = $.widget.extend( {}, 337 this.options, 338 this._getCreateOptions(), 339 options ); 340 341 this._create(); 342 343 if ( this.options.disabled ) { 344 this._setOptionDisabled( this.options.disabled ); 345 } 346 347 this._trigger( "create", null, this._getCreateEventData() ); 348 this._init(); 349 }, 350 351 _getCreateOptions: function() { 352 return {}; 353 }, 354 355 _getCreateEventData: $.noop, 356 357 _create: $.noop, 358 359 _init: $.noop, 360 361 destroy: function() { 362 var that = this; 363 364 this._destroy(); 365 $.each( this.classesElementLookup, function( key, value ) { 366 that._removeClass( value, key ); 367 } ); 368 369 // We can probably remove the unbind calls in 2.0 370 // all event bindings should go through this._on() 371 this.element 372 .off( this.eventNamespace ) 373 .removeData( this.widgetFullName ); 374 this.widget() 375 .off( this.eventNamespace ) 376 .removeAttr( "aria-disabled" ); 377 378 // Clean up events and states 379 this.bindings.off( this.eventNamespace ); 380 }, 381 382 _destroy: $.noop, 383 384 widget: function() { 385 return this.element; 386 }, 387 388 option: function( key, value ) { 389 var options = key; 390 var parts; 391 var curOption; 392 var i; 393 394 if ( arguments.length === 0 ) { 395 396 // Don't return a reference to the internal hash 397 return $.widget.extend( {}, this.options ); 398 } 399 400 if ( typeof key === "string" ) { 401 402 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 403 options = {}; 404 parts = key.split( "." ); 405 key = parts.shift(); 406 if ( parts.length ) { 407 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 408 for ( i = 0; i < parts.length - 1; i++ ) { 409 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 410 curOption = curOption[ parts[ i ] ]; 411 } 412 key = parts.pop(); 413 if ( arguments.length === 1 ) { 414 return curOption[ key ] === undefined ? null : curOption[ key ]; 415 } 416 curOption[ key ] = value; 417 } else { 418 if ( arguments.length === 1 ) { 419 return this.options[ key ] === undefined ? null : this.options[ key ]; 420 } 421 options[ key ] = value; 422 } 423 } 424 425 this._setOptions( options ); 426 427 return this; 428 }, 429 430 _setOptions: function( options ) { 431 var key; 432 433 for ( key in options ) { 434 this._setOption( key, options[ key ] ); 435 } 436 437 return this; 438 }, 439 440 _setOption: function( key, value ) { 441 if ( key === "classes" ) { 442 this._setOptionClasses( value ); 443 } 444 445 this.options[ key ] = value; 446 447 if ( key === "disabled" ) { 448 this._setOptionDisabled( value ); 449 } 450 451 return this; 452 }, 453 454 _setOptionClasses: function( value ) { 455 var classKey, elements, currentElements; 456 457 for ( classKey in value ) { 458 currentElements = this.classesElementLookup[ classKey ]; 459 if ( value[ classKey ] === this.options.classes[ classKey ] || 460 !currentElements || 461 !currentElements.length ) { 462 continue; 463 } 464 465 // We are doing this to create a new jQuery object because the _removeClass() call 466 // on the next line is going to destroy the reference to the current elements being 467 // tracked. We need to save a copy of this collection so that we can add the new classes 468 // below. 469 elements = $( currentElements.get() ); 470 this._removeClass( currentElements, classKey ); 471 472 // We don't use _addClass() here, because that uses this.options.classes 473 // for generating the string of classes. We want to use the value passed in from 474 // _setOption(), this is the new value of the classes option which was passed to 475 // _setOption(). We pass this value directly to _classes(). 476 elements.addClass( this._classes( { 477 element: elements, 478 keys: classKey, 479 classes: value, 480 add: true 481 } ) ); 482 } 483 }, 484 485 _setOptionDisabled: function( value ) { 486 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); 487 488 // If the widget is becoming disabled, then nothing is interactive 489 if ( value ) { 490 this._removeClass( this.hoverable, null, "ui-state-hover" ); 491 this._removeClass( this.focusable, null, "ui-state-focus" ); 492 } 493 }, 494 495 enable: function() { 496 return this._setOptions( { disabled: false } ); 497 }, 498 499 disable: function() { 500 return this._setOptions( { disabled: true } ); 501 }, 502 503 _classes: function( options ) { 504 var full = []; 505 var that = this; 506 507 options = $.extend( { 508 element: this.element, 509 classes: this.options.classes || {} 510 }, options ); 511 512 function processClassString( classes, checkOption ) { 513 var current, i; 514 for ( i = 0; i < classes.length; i++ ) { 515 current = that.classesElementLookup[ classes[ i ] ] || $(); 516 if ( options.add ) { 517 current = $( $.unique( current.get().concat( options.element.get() ) ) ); 518 } else { 519 current = $( current.not( options.element ).get() ); 520 } 521 that.classesElementLookup[ classes[ i ] ] = current; 522 full.push( classes[ i ] ); 523 if ( checkOption && options.classes[ classes[ i ] ] ) { 524 full.push( options.classes[ classes[ i ] ] ); 525 } 526 } 527 } 528 529 this._on( options.element, { 530 "remove": "_untrackClassesElement" 531 } ); 532 533 if ( options.keys ) { 534 processClassString( options.keys.match( /\S+/g ) || [], true ); 535 } 536 if ( options.extra ) { 537 processClassString( options.extra.match( /\S+/g ) || [] ); 538 } 539 540 return full.join( " " ); 541 }, 542 543 _untrackClassesElement: function( event ) { 544 var that = this; 545 $.each( that.classesElementLookup, function( key, value ) { 546 if ( $.inArray( event.target, value ) !== -1 ) { 547 that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); 548 } 549 } ); 550 }, 551 552 _removeClass: function( element, keys, extra ) { 553 return this._toggleClass( element, keys, extra, false ); 554 }, 555 556 _addClass: function( element, keys, extra ) { 557 return this._toggleClass( element, keys, extra, true ); 558 }, 559 560 _toggleClass: function( element, keys, extra, add ) { 561 add = ( typeof add === "boolean" ) ? add : extra; 562 var shift = ( typeof element === "string" || element === null ), 563 options = { 564 extra: shift ? keys : extra, 565 keys: shift ? element : keys, 566 element: shift ? this.element : element, 567 add: add 568 }; 569 options.element.toggleClass( this._classes( options ), add ); 570 return this; 571 }, 572 573 _on: function( suppressDisabledCheck, element, handlers ) { 574 var delegateElement; 575 var instance = this; 576 577 // No suppressDisabledCheck flag, shuffle arguments 578 if ( typeof suppressDisabledCheck !== "boolean" ) { 579 handlers = element; 580 element = suppressDisabledCheck; 581 suppressDisabledCheck = false; 582 } 583 584 // No element argument, shuffle and use this.element 585 if ( !handlers ) { 586 handlers = element; 587 element = this.element; 588 delegateElement = this.widget(); 589 } else { 590 element = delegateElement = $( element ); 591 this.bindings = this.bindings.add( element ); 592 } 593 594 $.each( handlers, function( event, handler ) { 595 function handlerProxy() { 596 597 // Allow widgets to customize the disabled handling 598 // - disabled as an array instead of boolean 599 // - disabled class as method for disabling individual parts 600 if ( !suppressDisabledCheck && 601 ( instance.options.disabled === true || 602 $( this ).hasClass( "ui-state-disabled" ) ) ) { 603 return; 604 } 605 return ( typeof handler === "string" ? instance[ handler ] : handler ) 606 .apply( instance, arguments ); 607 } 608 609 // Copy the guid so direct unbinding works 610 if ( typeof handler !== "string" ) { 611 handlerProxy.guid = handler.guid = 612 handler.guid || handlerProxy.guid || $.guid++; 613 } 614 615 var match = event.match( /^([\w:-]*)\s*(.*)$/ ); 616 var eventName = match[ 1 ] + instance.eventNamespace; 617 var selector = match[ 2 ]; 618 619 if ( selector ) { 620 delegateElement.on( eventName, selector, handlerProxy ); 621 } else { 622 element.on( eventName, handlerProxy ); 623 } 624 } ); 625 }, 626 627 _off: function( element, eventName ) { 628 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + 629 this.eventNamespace; 630 element.off( eventName ).off( eventName ); 631 632 // Clear the stack to avoid memory leaks (#10056) 633 this.bindings = $( this.bindings.not( element ).get() ); 634 this.focusable = $( this.focusable.not( element ).get() ); 635 this.hoverable = $( this.hoverable.not( element ).get() ); 636 }, 637 638 _delay: function( handler, delay ) { 639 function handlerProxy() { 640 return ( typeof handler === "string" ? instance[ handler ] : handler ) 641 .apply( instance, arguments ); 642 } 643 var instance = this; 644 return setTimeout( handlerProxy, delay || 0 ); 645 }, 646 647 _hoverable: function( element ) { 648 this.hoverable = this.hoverable.add( element ); 649 this._on( element, { 650 mouseenter: function( event ) { 651 this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); 652 }, 653 mouseleave: function( event ) { 654 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); 655 } 656 } ); 657 }, 658 659 _focusable: function( element ) { 660 this.focusable = this.focusable.add( element ); 661 this._on( element, { 662 focusin: function( event ) { 663 this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); 664 }, 665 focusout: function( event ) { 666 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); 667 } 668 } ); 669 }, 670 671 _trigger: function( type, event, data ) { 672 var prop, orig; 673 var callback = this.options[ type ]; 674 675 data = data || {}; 676 event = $.Event( event ); 677 event.type = ( type === this.widgetEventPrefix ? 678 type : 679 this.widgetEventPrefix + type ).toLowerCase(); 680 681 // The original event may come from any element 682 // so we need to reset the target on the new event 683 event.target = this.element[ 0 ]; 684 685 // Copy original event properties over to the new event 686 orig = event.originalEvent; 687 if ( orig ) { 688 for ( prop in orig ) { 689 if ( !( prop in event ) ) { 690 event[ prop ] = orig[ prop ]; 691 } 692 } 693 } 694 695 this.element.trigger( event, data ); 696 return !( $.isFunction( callback ) && 697 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || 698 event.isDefaultPrevented() ); 699 } 700 }; 701 702 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 703 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 704 if ( typeof options === "string" ) { 705 options = { effect: options }; 706 } 707 708 var hasOptions; 709 var effectName = !options ? 710 method : 711 options === true || typeof options === "number" ? 712 defaultEffect : 713 options.effect || defaultEffect; 714 715 options = options || {}; 716 if ( typeof options === "number" ) { 717 options = { duration: options }; 718 } 719 720 hasOptions = !$.isEmptyObject( options ); 721 options.complete = callback; 722 723 if ( options.delay ) { 724 element.delay( options.delay ); 725 } 726 727 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 728 element[ method ]( options ); 729 } else if ( effectName !== method && element[ effectName ] ) { 730 element[ effectName ]( options.duration, options.easing, callback ); 731 } else { 732 element.queue( function( next ) { 733 $( this )[ method ](); 734 if ( callback ) { 735 callback.call( element[ 0 ] ); 736 } 737 next(); 738 } ); 739 } 740 }; 741 } ); 742 743 var widget = $.widget; 744 745 746 /*! 747 * jQuery UI Position 1.12.1 748 * http://jqueryui.com 749 * 750 * Copyright jQuery Foundation and other contributors 751 * Released under the MIT license. 752 * http://jquery.org/license 753 * 754 * http://api.jqueryui.com/position/ 755 */ 756 757 //>>label: Position 758 //>>group: Core 759 //>>description: Positions elements relative to other elements. 760 //>>docs: http://api.jqueryui.com/position/ 761 //>>demos: http://jqueryui.com/position/ 762 763 764 ( function() { 765 var cachedScrollbarWidth, 766 max = Math.max, 767 abs = Math.abs, 768 rhorizontal = /left|center|right/, 769 rvertical = /top|center|bottom/, 770 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 771 rposition = /^\w+/, 772 rpercent = /%$/, 773 _position = $.fn.position; 774 775 function getOffsets( offsets, width, height ) { 776 return [ 777 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 778 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 779 ]; 780 } 781 782 function parseCss( element, property ) { 783 return parseInt( $.css( element, property ), 10 ) || 0; 784 } 785 786 function getDimensions( elem ) { 787 var raw = elem[ 0 ]; 788 if ( raw.nodeType === 9 ) { 789 return { 790 width: elem.width(), 791 height: elem.height(), 792 offset: { top: 0, left: 0 } 793 }; 794 } 795 if ( $.isWindow( raw ) ) { 796 return { 797 width: elem.width(), 798 height: elem.height(), 799 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 800 }; 801 } 802 if ( raw.preventDefault ) { 803 return { 804 width: 0, 805 height: 0, 806 offset: { top: raw.pageY, left: raw.pageX } 807 }; 808 } 809 return { 810 width: elem.outerWidth(), 811 height: elem.outerHeight(), 812 offset: elem.offset() 813 }; 814 } 815 816 $.position = { 817 scrollbarWidth: function() { 818 if ( cachedScrollbarWidth !== undefined ) { 819 return cachedScrollbarWidth; 820 } 821 var w1, w2, 822 div = $( "<div " + 823 "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" + 824 "<div style='height:100px;width:auto;'></div></div>" ), 825 innerDiv = div.children()[ 0 ]; 826 827 $( "body" ).append( div ); 828 w1 = innerDiv.offsetWidth; 829 div.css( "overflow", "scroll" ); 830 831 w2 = innerDiv.offsetWidth; 832 833 if ( w1 === w2 ) { 834 w2 = div[ 0 ].clientWidth; 835 } 836 837 div.remove(); 838 839 return ( cachedScrollbarWidth = w1 - w2 ); 840 }, 841 getScrollInfo: function( within ) { 842 var overflowX = within.isWindow || within.isDocument ? "" : 843 within.element.css( "overflow-x" ), 844 overflowY = within.isWindow || within.isDocument ? "" : 845 within.element.css( "overflow-y" ), 846 hasOverflowX = overflowX === "scroll" || 847 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), 848 hasOverflowY = overflowY === "scroll" || 849 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); 850 return { 851 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 852 height: hasOverflowX ? $.position.scrollbarWidth() : 0 853 }; 854 }, 855 getWithinInfo: function( element ) { 856 var withinElement = $( element || window ), 857 isWindow = $.isWindow( withinElement[ 0 ] ), 858 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, 859 hasOffset = !isWindow && !isDocument; 860 return { 861 element: withinElement, 862 isWindow: isWindow, 863 isDocument: isDocument, 864 offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, 865 scrollLeft: withinElement.scrollLeft(), 866 scrollTop: withinElement.scrollTop(), 867 width: withinElement.outerWidth(), 868 height: withinElement.outerHeight() 869 }; 870 } 871 }; 872 873 $.fn.position = function( options ) { 874 if ( !options || !options.of ) { 875 return _position.apply( this, arguments ); 876 } 877 878 // Make a copy, we don't want to modify arguments 879 options = $.extend( {}, options ); 880 881 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 882 target = $( options.of ), 883 within = $.position.getWithinInfo( options.within ), 884 scrollInfo = $.position.getScrollInfo( within ), 885 collision = ( options.collision || "flip" ).split( " " ), 886 offsets = {}; 887 888 dimensions = getDimensions( target ); 889 if ( target[ 0 ].preventDefault ) { 890 891 // Force left top to allow flipping 892 options.at = "left top"; 893 } 894 targetWidth = dimensions.width; 895 targetHeight = dimensions.height; 896 targetOffset = dimensions.offset; 897 898 // Clone to reuse original targetOffset later 899 basePosition = $.extend( {}, targetOffset ); 900 901 // Force my and at to have valid horizontal and vertical positions 902 // if a value is missing or invalid, it will be converted to center 903 $.each( [ "my", "at" ], function() { 904 var pos = ( options[ this ] || "" ).split( " " ), 905 horizontalOffset, 906 verticalOffset; 907 908 if ( pos.length === 1 ) { 909 pos = rhorizontal.test( pos[ 0 ] ) ? 910 pos.concat( [ "center" ] ) : 911 rvertical.test( pos[ 0 ] ) ? 912 [ "center" ].concat( pos ) : 913 [ "center", "center" ]; 914 } 915 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 916 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 917 918 // Calculate offsets 919 horizontalOffset = roffset.exec( pos[ 0 ] ); 920 verticalOffset = roffset.exec( pos[ 1 ] ); 921 offsets[ this ] = [ 922 horizontalOffset ? horizontalOffset[ 0 ] : 0, 923 verticalOffset ? verticalOffset[ 0 ] : 0 924 ]; 925 926 // Reduce to just the positions without the offsets 927 options[ this ] = [ 928 rposition.exec( pos[ 0 ] )[ 0 ], 929 rposition.exec( pos[ 1 ] )[ 0 ] 930 ]; 931 } ); 932 933 // Normalize collision option 934 if ( collision.length === 1 ) { 935 collision[ 1 ] = collision[ 0 ]; 936 } 937 938 if ( options.at[ 0 ] === "right" ) { 939 basePosition.left += targetWidth; 940 } else if ( options.at[ 0 ] === "center" ) { 941 basePosition.left += targetWidth / 2; 942 } 943 944 if ( options.at[ 1 ] === "bottom" ) { 945 basePosition.top += targetHeight; 946 } else if ( options.at[ 1 ] === "center" ) { 947 basePosition.top += targetHeight / 2; 948 } 949 950 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 951 basePosition.left += atOffset[ 0 ]; 952 basePosition.top += atOffset[ 1 ]; 953 954 return this.each( function() { 955 var collisionPosition, using, 956 elem = $( this ), 957 elemWidth = elem.outerWidth(), 958 elemHeight = elem.outerHeight(), 959 marginLeft = parseCss( this, "marginLeft" ), 960 marginTop = parseCss( this, "marginTop" ), 961 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + 962 scrollInfo.width, 963 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + 964 scrollInfo.height, 965 position = $.extend( {}, basePosition ), 966 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 967 968 if ( options.my[ 0 ] === "right" ) { 969 position.left -= elemWidth; 970 } else if ( options.my[ 0 ] === "center" ) { 971 position.left -= elemWidth / 2; 972 } 973 974 if ( options.my[ 1 ] === "bottom" ) { 975 position.top -= elemHeight; 976 } else if ( options.my[ 1 ] === "center" ) { 977 position.top -= elemHeight / 2; 978 } 979 980 position.left += myOffset[ 0 ]; 981 position.top += myOffset[ 1 ]; 982 983 collisionPosition = { 984 marginLeft: marginLeft, 985 marginTop: marginTop 986 }; 987 988 $.each( [ "left", "top" ], function( i, dir ) { 989 if ( $.ui.position[ collision[ i ] ] ) { 990 $.ui.position[ collision[ i ] ][ dir ]( position, { 991 targetWidth: targetWidth, 992 targetHeight: targetHeight, 993 elemWidth: elemWidth, 994 elemHeight: elemHeight, 995 collisionPosition: collisionPosition, 996 collisionWidth: collisionWidth, 997 collisionHeight: collisionHeight, 998 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 999 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 2836 function parseClip( str, element ) { 2837 var outerWidth = element.outerWidth(), 2838 outerHeight = element.outerHeight(), 2839 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)\)$/, 2840 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ]; 2841 2842 return { 2843 top: parseFloat( values[ 1 ] ) || 0, 2844 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ), 2845 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ), 2846 left: parseFloat( values[ 4 ] ) || 0 2847 }; 2848 } 2849 2850 $.fx.step.clip = function( fx ) { 2851 if ( !fx.clipInit ) { 2852 fx.start = $( fx.elem ).cssClip(); 2853 if ( typeof fx.end === "string" ) { 2854 fx.end = parseClip( fx.end, fx.elem ); 2855 } 2856 fx.clipInit = true; 2857 } 2858 2859 $( fx.elem ).cssClip( { 2860 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top, 2861 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right, 2862 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom, 2863 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left 2864 } ); 2865 }; 2866 2867 } )(); 2868 2869 /******************************************************************************/ 2870 /*********************************** EASING ***********************************/ 2871 /******************************************************************************/ 2872 2873 ( function() { 2874 2875 // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing) 2876 2877 var baseEasings = {}; 2878 2879 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { 2880 baseEasings[ name ] = function( p ) { 2881 return Math.pow( p, i + 2 ); 2882 }; 2883 } ); 2884 2885 $.extend( baseEasings, { 2886 Sine: function( p ) { 2887 return 1 - Math.cos( p * Math.PI / 2 ); 2888 }, 2889 Circ: function( p ) { 2890 return 1 - Math.sqrt( 1 - p * p ); 2891 }, 2892 Elastic: function( p ) { 2893 return p === 0 || p === 1 ? p : 2894 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 ); 2895 }, 2896 Back: function( p ) { 2897 return p * p * ( 3 * p - 2 ); 2898 }, 2899 Bounce: function( p ) { 2900 var pow2, 2901 bounce = 4; 2902 2903 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} 2904 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); 2905 } 2906 } ); 2907 2908 $.each( baseEasings, function( name, easeIn ) { 2909 $.easing[ "easeIn" + name ] = easeIn; 2910 $.easing[ "easeOut" + name ] = function( p ) { 2911 return 1 - easeIn( 1 - p ); 2912 }; 2913 $.easing[ "easeInOut" + name ] = function( p ) { 2914 return p < 0.5 ? 2915 easeIn( p * 2 ) / 2 : 2916 1 - easeIn( p * -2 + 2 ) / 2; 2917 }; 2918 } ); 2919 2920 } )(); 2921 2922 var effect = $.effects; 2923 2924 2925 /*! 2926 * jQuery UI Effects Blind 1.12.1 2927 * http://jqueryui.com 2928 * 2929 * Copyright jQuery Foundation and other contributors 2930 * Released under the MIT license. 2931 * http://jquery.org/license 2932 */ 2933 2934 //>>label: Blind Effect 2935 //>>group: Effects 2936 //>>description: Blinds the element. 2937 //>>docs: http://api.jqueryui.com/blind-effect/ 2938 //>>demos: http://jqueryui.com/effect/ 2939 2940 2941 2942 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) { 2943 var map = { 2944 up: [ "bottom", "top" ], 2945 vertical: [ "bottom", "top" ], 2946 down: [ "top", "bottom" ], 2947 left: [ "right", "left" ], 2948 horizontal: [ "right", "left" ], 2949 right: [ "left", "right" ] 2950 }, 2951 element = $( this ), 2952 direction = options.direction || "up", 2953 start = element.cssClip(), 2954 animate = { clip: $.extend( {}, start ) }, 2955 placeholder = $.effects.createPlaceholder( element ); 2956 2957 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ]; 2958 2959 if ( options.mode === "show" ) { 2960 element.cssClip( animate.clip ); 2961 if ( placeholder ) { 2962 placeholder.css( $.effects.clipToBox( animate ) ); 2963 } 2964 2965 animate.clip = start; 2966 } 2967 2968 if ( placeholder ) { 2969 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing ); 2970 } 2971 2972 element.animate( animate, { 2973 queue: false, 2974 duration: options.duration, 2975 easing: options.easing, 2976 complete: done 2977 } ); 2978 } ); 2979 2980 2981 /*! 2982 * jQuery UI Effects Bounce 1.12.1 2983 * http://jqueryui.com 2984 * 2985 * Copyright jQuery Foundation and other contributors 2986 * Released under the MIT license. 2987 * http://jquery.org/license 2988 */ 2989 2990 //>>label: Bounce Effect 2991 //>>group: Effects 2992 //>>description: Bounces an element horizontally or vertically n times. 2993 //>>docs: http://api.jqueryui.com/bounce-effect/ 2994 //>>demos: http://jqueryui.com/effect/ 2995 2996 2997 2998 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) { 2999 var upAnim, downAnim, refValue, 3000 element = $( this ), 3001 3002 // Defaults: 3003 mode = options.mode, 3004 hide = mode === "hide", 3005 show = mode === "show", 3006 direction = options.direction || "up", 3007 distance = options.distance, 3008 times = options.times || 5, 3009 3010 // Number of internal animations 3011 anims = times * 2 + ( show || hide ? 1 : 0 ), 3012 speed = options.duration / anims, 3013 easing = options.easing, 3014 3015 // Utility: 3016 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3017 motion = ( direction === "up" || direction === "left" ), 3018 i = 0, 3019 3020 queuelen = element.queue().length; 3021 3022 $.effects.createPlaceholder( element ); 3023 3024 refValue = element.css( ref ); 3025 3026 // Default distance for the BIGGEST bounce is the outer Distance / 3 3027 if ( !distance ) { 3028 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; 3029 } 3030 3031 if ( show ) { 3032 downAnim = { opacity: 1 }; 3033 downAnim[ ref ] = refValue; 3034 3035 // If we are showing, force opacity 0 and set the initial position 3036 // then do the "first" animation 3037 element 3038 .css( "opacity", 0 ) 3039 .css( ref, motion ? -distance * 2 : distance * 2 ) 3040 .animate( downAnim, speed, easing ); 3041 } 3042 3043 // Start at the smallest distance if we are hiding 3044 if ( hide ) { 3045 distance = distance / Math.pow( 2, times - 1 ); 3046 } 3047 3048 downAnim = {}; 3049 downAnim[ ref ] = refValue; 3050 3051 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here 3052 for ( ; i < times; i++ ) { 3053 upAnim = {}; 3054 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 3055 3056 element 3057 .animate( upAnim, speed, easing ) 3058 .animate( downAnim, speed, easing ); 3059 3060 distance = hide ? distance * 2 : distance / 2; 3061 } 3062 3063 // Last Bounce when Hiding 3064 if ( hide ) { 3065 upAnim = { opacity: 0 }; 3066 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 3067 3068 element.animate( upAnim, speed, easing ); 3069 } 3070 3071 element.queue( done ); 3072 3073 $.effects.unshift( element, queuelen, anims + 1 ); 3074 } ); 3075 3076 3077 /*! 3078 * jQuery UI Effects Clip 1.12.1 3079 * http://jqueryui.com 3080 * 3081 * Copyright jQuery Foundation and other contributors 3082 * Released under the MIT license. 3083 * http://jquery.org/license 3084 */ 3085 3086 //>>label: Clip Effect 3087 //>>group: Effects 3088 //>>description: Clips the element on and off like an old TV. 3089 //>>docs: http://api.jqueryui.com/clip-effect/ 3090 //>>demos: http://jqueryui.com/effect/ 3091 3092 3093 3094 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) { 3095 var start, 3096 animate = {}, 3097 element = $( this ), 3098 direction = options.direction || "vertical", 3099 both = direction === "both", 3100 horizontal = both || direction === "horizontal", 3101 vertical = both || direction === "vertical"; 3102 3103 start = element.cssClip(); 3104 animate.clip = { 3105 top: vertical ? ( start.bottom - start.top ) / 2 : start.top, 3106 right: horizontal ? ( start.right - start.left ) / 2 : start.right, 3107 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom, 3108 left: horizontal ? ( start.right - start.left ) / 2 : start.left 3109 }; 3110 3111 $.effects.createPlaceholder( element ); 3112 3113 if ( options.mode === "show" ) { 3114 element.cssClip( animate.clip ); 3115 animate.clip = start; 3116 } 3117 3118 element.animate( animate, { 3119 queue: false, 3120 duration: options.duration, 3121 easing: options.easing, 3122 complete: done 3123 } ); 3124 3125 } ); 3126 3127 3128 /*! 3129 * jQuery UI Effects Drop 1.12.1 3130 * http://jqueryui.com 3131 * 3132 * Copyright jQuery Foundation and other contributors 3133 * Released under the MIT license. 3134 * http://jquery.org/license 3135 */ 3136 3137 //>>label: Drop Effect 3138 //>>group: Effects 3139 //>>description: Moves an element in one direction and hides it at the same time. 3140 //>>docs: http://api.jqueryui.com/drop-effect/ 3141 //>>demos: http://jqueryui.com/effect/ 3142 3143 3144 3145 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) { 3146 3147 var distance, 3148 element = $( this ), 3149 mode = options.mode, 3150 show = mode === "show", 3151 direction = options.direction || "left", 3152 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3153 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=", 3154 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=", 3155 animation = { 3156 opacity: 0 3157 }; 3158 3159 $.effects.createPlaceholder( element ); 3160 3161 distance = options.distance || 3162 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; 3163 3164 animation[ ref ] = motion + distance; 3165 3166 if ( show ) { 3167 element.css( animation ); 3168 3169 animation[ ref ] = oppositeMotion + distance; 3170 animation.opacity = 1; 3171 } 3172 3173 // Animate 3174 element.animate( animation, { 3175 queue: false, 3176 duration: options.duration, 3177 easing: options.easing, 3178 complete: done 3179 } ); 3180 } ); 3181 3182 3183 /*! 3184 * jQuery UI Effects Explode 1.12.1 3185 * http://jqueryui.com 3186 * 3187 * Copyright jQuery Foundation and other contributors 3188 * Released under the MIT license. 3189 * http://jquery.org/license 3190 */ 3191 3192 //>>label: Explode Effect 3193 //>>group: Effects 3194 // jscs:disable maximumLineLength 3195 //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness. 3196 // jscs:enable maximumLineLength 3197 //>>docs: http://api.jqueryui.com/explode-effect/ 3198 //>>demos: http://jqueryui.com/effect/ 3199 3200 3201 3202 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) { 3203 3204 var i, j, left, top, mx, my, 3205 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3, 3206 cells = rows, 3207 element = $( this ), 3208 mode = options.mode, 3209 show = mode === "show", 3210 3211 // Show and then visibility:hidden the element before calculating offset 3212 offset = element.show().css( "visibility", "hidden" ).offset(), 3213 3214 // Width and height of a piece 3215 width = Math.ceil( element.outerWidth() / cells ), 3216 height = Math.ceil( element.outerHeight() / rows ), 3217 pieces = []; 3218 3219 // Children animate complete: 3220 function childComplete() { 3221 pieces.push( this ); 3222 if ( pieces.length === rows * cells ) { 3223 animComplete(); 3224 } 3225 } 3226 3227 // Clone the element for each row and cell. 3228 for ( i = 0; i < rows; i++ ) { // ===> 3229 top = offset.top + i * height; 3230 my = i - ( rows - 1 ) / 2; 3231 3232 for ( j = 0; j < cells; j++ ) { // ||| 3233 left = offset.left + j * width; 3234 mx = j - ( cells - 1 ) / 2; 3235 3236 // Create a clone of the now hidden main element that will be absolute positioned 3237 // within a wrapper div off the -left and -top equal to size of our pieces 3238 element 3239 .clone() 3240 .appendTo( "body" ) 3241 .wrap( "<div></div>" ) 3242 .css( { 3243 position: "absolute", 3244 visibility: "visible", 3245 left: -j * width, 3246 top: -i * height 3247 } ) 3248 3249 // Select the wrapper - make it overflow: hidden and absolute positioned based on 3250 // where the original was located +left and +top equal to the size of pieces 3251 .parent() 3252 .addClass( "ui-effects-explode" ) 3253 .css( { 3254 position: "absolute", 3255 overflow: "hidden", 3256 width: width, 3257 height: height, 3258 left: left + ( show ? mx * width : 0 ), 3259 top: top + ( show ? my * height : 0 ), 3260 opacity: show ? 0 : 1 3261 } ) 3262 .animate( { 3263 left: left + ( show ? 0 : mx * width ), 3264 top: top + ( show ? 0 : my * height ), 3265 opacity: show ? 1 : 0 3266 }, options.duration || 500, options.easing, childComplete ); 3267 } 3268 } 3269 3270 function animComplete() { 3271 element.css( { 3272 visibility: "visible" 3273 } ); 3274 $( pieces ).remove(); 3275 done(); 3276 } 3277 } ); 3278 3279 3280 /*! 3281 * jQuery UI Effects Fade 1.12.1 3282 * http://jqueryui.com 3283 * 3284 * Copyright jQuery Foundation and other contributors 3285 * Released under the MIT license. 3286 * http://jquery.org/license 3287 */ 3288 3289 //>>label: Fade Effect 3290 //>>group: Effects 3291 //>>description: Fades the element. 3292 //>>docs: http://api.jqueryui.com/fade-effect/ 3293 //>>demos: http://jqueryui.com/effect/ 3294 3295 3296 3297 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) { 3298 var show = options.mode === "show"; 3299 3300 $( this ) 3301 .css( "opacity", show ? 0 : 1 ) 3302 .animate( { 3303 opacity: show ? 1 : 0 3304 }, { 3305 queue: false, 3306 duration: options.duration, 3307 easing: options.easing, 3308 complete: done 3309 } ); 3310 } ); 3311 3312 3313 /*! 3314 * jQuery UI Effects Fold 1.12.1 3315 * http://jqueryui.com 3316 * 3317 * Copyright jQuery Foundation and other contributors 3318 * Released under the MIT license. 3319 * http://jquery.org/license 3320 */ 3321 3322 //>>label: Fold Effect 3323 //>>group: Effects 3324 //>>description: Folds an element first horizontally and then vertically. 3325 //>>docs: http://api.jqueryui.com/fold-effect/ 3326 //>>demos: http://jqueryui.com/effect/ 3327 3328 3329 3330 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) { 3331 3332 // Create element 3333 var element = $( this ), 3334 mode = options.mode, 3335 show = mode === "show", 3336 hide = mode === "hide", 3337 size = options.size || 15, 3338 percent = /([0-9]+)%/.exec( size ), 3339 horizFirst = !!options.horizFirst, 3340 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ], 3341 duration = options.duration / 2, 3342 3343 placeholder = $.effects.createPlaceholder( element ), 3344 3345 start = element.cssClip(), 3346 animation1 = { clip: $.extend( {}, start ) }, 3347 animation2 = { clip: $.extend( {}, start ) }, 3348 3349 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ], 3350 3351 queuelen = element.queue().length; 3352 3353 if ( percent ) { 3354 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; 3355 } 3356 animation1.clip[ ref[ 0 ] ] = size; 3357 animation2.clip[ ref[ 0 ] ] = size; 3358 animation2.clip[ ref[ 1 ] ] = 0; 3359 3360 if ( show ) { 3361 element.cssClip( animation2.clip ); 3362 if ( placeholder ) { 3363 placeholder.css( $.effects.clipToBox( animation2 ) ); 3364 } 3365 3366 animation2.clip = start; 3367 } 3368 3369 // Animate 3370 element 3371 .queue( function( next ) { 3372 if ( placeholder ) { 3373 placeholder 3374 .animate( $.effects.clipToBox( animation1 ), duration, options.easing ) 3375 .animate( $.effects.clipToBox( animation2 ), duration, options.easing ); 3376 } 3377 3378 next(); 3379 } ) 3380 .animate( animation1, duration, options.easing ) 3381 .animate( animation2, duration, options.easing ) 3382 .queue( done ); 3383 3384 $.effects.unshift( element, queuelen, 4 ); 3385 } ); 3386 3387 3388 /*! 3389 * jQuery UI Effects Highlight 1.12.1 3390 * http://jqueryui.com 3391 * 3392 * Copyright jQuery Foundation and other contributors 3393 * Released under the MIT license. 3394 * http://jquery.org/license 3395 */ 3396 3397 //>>label: Highlight Effect 3398 //>>group: Effects 3399 //>>description: Highlights the background of an element in a defined color for a custom duration. 3400 //>>docs: http://api.jqueryui.com/highlight-effect/ 3401 //>>demos: http://jqueryui.com/effect/ 3402 3403 3404 3405 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) { 3406 var element = $( this ), 3407 animation = { 3408 backgroundColor: element.css( "backgroundColor" ) 3409 }; 3410 3411 if ( options.mode === "hide" ) { 3412 animation.opacity = 0; 3413 } 3414 3415 $.effects.saveStyle( element ); 3416 3417 element 3418 .css( { 3419 backgroundImage: "none", 3420 backgroundColor: options.color || "#ffff99" 3421 } ) 3422 .animate( animation, { 3423 queue: false, 3424 duration: options.duration, 3425 easing: options.easing, 3426 complete: done 3427 } ); 3428 } ); 3429 3430 3431 /*! 3432 * jQuery UI Effects Size 1.12.1 3433 * http://jqueryui.com 3434 * 3435 * Copyright jQuery Foundation and other contributors 3436 * Released under the MIT license. 3437 * http://jquery.org/license 3438 */ 3439 3440 //>>label: Size Effect 3441 //>>group: Effects 3442 //>>description: Resize an element to a specified width and height. 3443 //>>docs: http://api.jqueryui.com/size-effect/ 3444 //>>demos: http://jqueryui.com/effect/ 3445 3446 3447 3448 var effectsEffectSize = $.effects.define( "size", function( options, done ) { 3449 3450 // Create element 3451 var baseline, factor, temp, 3452 element = $( this ), 3453 3454 // Copy for children 3455 cProps = [ "fontSize" ], 3456 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], 3457 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], 3458 3459 // Set options 3460 mode = options.mode, 3461 restore = mode !== "effect", 3462 scale = options.scale || "both", 3463 origin = options.origin || [ "middle", "center" ], 3464 position = element.css( "position" ), 3465 pos = element.position(), 3466 original = $.effects.scaledDimensions( element ), 3467 from = options.from || original, 3468 to = options.to || $.effects.scaledDimensions( element, 0 ); 3469 3470 $.effects.createPlaceholder( element ); 3471 3472 if ( mode === "show" ) { 3473 temp = from; 3474 from = to; 3475 to = temp; 3476 } 3477 3478 // Set scaling factor 3479 factor = { 3480 from: { 3481 y: from.height / original.height, 3482 x: from.width / original.width 3483 }, 3484 to: { 3485 y: to.height / original.height, 3486 x: to.width / original.width 3487 } 3488 }; 3489 3490 // Scale the css box 3491 if ( scale === "box" || scale === "both" ) { 3492 3493 // Vertical props scaling 3494 if ( factor.from.y !== factor.to.y ) { 3495 from = $.effects.setTransition( element, vProps, factor.from.y, from ); 3496 to = $.effects.setTransition( element, vProps, factor.to.y, to ); 3497 } 3498 3499 // Horizontal props scaling 3500 if ( factor.from.x !== factor.to.x ) { 3501 from = $.effects.setTransition( element, hProps, factor.from.x, from ); 3502 to = $.effects.setTransition( element, hProps, factor.to.x, to ); 3503 } 3504 } 3505 3506 // Scale the content 3507 if ( scale === "content" || scale === "both" ) { 3508 3509 // Vertical props scaling 3510 if ( factor.from.y !== factor.to.y ) { 3511 from = $.effects.setTransition( element, cProps, factor.from.y, from ); 3512 to = $.effects.setTransition( element, cProps, factor.to.y, to ); 3513 } 3514 } 3515 3516 // Adjust the position properties based on the provided origin points 3517 if ( origin ) { 3518 baseline = $.effects.getBaseline( origin, original ); 3519 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top; 3520 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left; 3521 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top; 3522 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left; 3523 } 3524 element.css( from ); 3525 3526 // Animate the children if desired 3527 if ( scale === "content" || scale === "both" ) { 3528 3529 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps ); 3530 hProps = hProps.concat( [ "marginLeft", "marginRight" ] ); 3531 3532 // Only animate children with width attributes specified 3533 // TODO: is this right? should we include anything with css width specified as well 3534 element.find( "*[width]" ).each( function() { 3535 var child = $( this ), 3536 childOriginal = $.effects.scaledDimensions( child ), 3537 childFrom = { 3538 height: childOriginal.height * factor.from.y, 3539 width: childOriginal.width * factor.from.x, 3540 outerHeight: childOriginal.outerHeight * factor.from.y, 3541 outerWidth: childOriginal.outerWidth * factor.from.x 3542 }, 3543 childTo = { 3544 height: childOriginal.height * factor.to.y, 3545 width: childOriginal.width * factor.to.x, 3546 outerHeight: childOriginal.height * factor.to.y, 3547 outerWidth: childOriginal.width * factor.to.x 3548 }; 3549 3550 // Vertical props scaling 3551 if ( factor.from.y !== factor.to.y ) { 3552 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom ); 3553 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo ); 3554 } 3555 3556 // Horizontal props scaling 3557 if ( factor.from.x !== factor.to.x ) { 3558 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom ); 3559 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo ); 3560 } 3561 3562 if ( restore ) { 3563 $.effects.saveStyle( child ); 3564 } 3565 3566 // Animate children 3567 child.css( childFrom ); 3568 child.animate( childTo, options.duration, options.easing, function() { 3569 3570 // Restore children 3571 if ( restore ) { 3572 $.effects.restoreStyle( child ); 3573 } 3574 } ); 3575 } ); 3576 } 3577 3578 // Animate 3579 element.animate( to, { 3580 queue: false, 3581 duration: options.duration, 3582 easing: options.easing, 3583 complete: function() { 3584 3585 var offset = element.offset(); 3586 3587 if ( to.opacity === 0 ) { 3588 element.css( "opacity", from.opacity ); 3589 } 3590 3591 if ( !restore ) { 3592 element 3593 .css( "position", position === "static" ? "relative" : position ) 3594 .offset( offset ); 3595 3596 // Need to save style here so that automatic style restoration 3597 // doesn't restore to the original styles from before the animation. 3598 $.effects.saveStyle( element ); 3599 } 3600 3601 done(); 3602 } 3603 } ); 3604 3605 } ); 3606 3607 3608 /*! 3609 * jQuery UI Effects Scale 1.12.1 3610 * http://jqueryui.com 3611 * 3612 * Copyright jQuery Foundation and other contributors 3613 * Released under the MIT license. 3614 * http://jquery.org/license 3615 */ 3616 3617 //>>label: Scale Effect 3618 //>>group: Effects 3619 //>>description: Grows or shrinks an element and its content. 3620 //>>docs: http://api.jqueryui.com/scale-effect/ 3621 //>>demos: http://jqueryui.com/effect/ 3622 3623 3624 3625 var effectsEffectScale = $.effects.define( "scale", function( options, done ) { 3626 3627 // Create element 3628 var el = $( this ), 3629 mode = options.mode, 3630 percent = parseInt( options.percent, 10 ) || 3631 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ), 3632 3633 newOptions = $.extend( true, { 3634 from: $.effects.scaledDimensions( el ), 3635 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ), 3636 origin: options.origin || [ "middle", "center" ] 3637 }, options ); 3638 3639 // Fade option to support puff 3640 if ( options.fade ) { 3641 newOptions.from.opacity = 1; 3642 newOptions.to.opacity = 0; 3643 } 3644 3645 $.effects.effect.size.call( this, newOptions, done ); 3646 } ); 3647 3648 3649 /*! 3650 * jQuery UI Effects Puff 1.12.1 3651 * http://jqueryui.com 3652 * 3653 * Copyright jQuery Foundation and other contributors 3654 * Released under the MIT license. 3655 * http://jquery.org/license 3656 */ 3657 3658 //>>label: Puff Effect 3659 //>>group: Effects 3660 //>>description: Creates a puff effect by scaling the element up and hiding it at the same time. 3661 //>>docs: http://api.jqueryui.com/puff-effect/ 3662 //>>demos: http://jqueryui.com/effect/ 3663 3664 3665 3666 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) { 3667 var newOptions = $.extend( true, {}, options, { 3668 fade: true, 3669 percent: parseInt( options.percent, 10 ) || 150 3670 } ); 3671 3672 $.effects.effect.scale.call( this, newOptions, done ); 3673 } ); 3674 3675 3676 /*! 3677 * jQuery UI Effects Pulsate 1.12.1 3678 * http://jqueryui.com 3679 * 3680 * Copyright jQuery Foundation and other contributors 3681 * Released under the MIT license. 3682 * http://jquery.org/license 3683 */ 3684 3685 //>>label: Pulsate Effect 3686 //>>group: Effects 3687 //>>description: Pulsates an element n times by changing the opacity to zero and back. 3688 //>>docs: http://api.jqueryui.com/pulsate-effect/ 3689 //>>demos: http://jqueryui.com/effect/ 3690 3691 3692 3693 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) { 3694 var element = $( this ), 3695 mode = options.mode, 3696 show = mode === "show", 3697 hide = mode === "hide", 3698 showhide = show || hide, 3699 3700 // Showing or hiding leaves off the "last" animation 3701 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), 3702 duration = options.duration / anims, 3703 animateTo = 0, 3704 i = 1, 3705 queuelen = element.queue().length; 3706 3707 if ( show || !element.is( ":visible" ) ) { 3708 element.css( "opacity", 0 ).show(); 3709 animateTo = 1; 3710 } 3711 3712 // Anims - 1 opacity "toggles" 3713 for ( ; i < anims; i++ ) { 3714 element.animate( { opacity: animateTo }, duration, options.easing ); 3715 animateTo = 1 - animateTo; 3716 } 3717 3718 element.animate( { opacity: animateTo }, duration, options.easing ); 3719 3720 element.queue( done ); 3721 3722 $.effects.unshift( element, queuelen, anims + 1 ); 3723 } ); 3724 3725 3726 /*! 3727 * jQuery UI Effects Shake 1.12.1 3728 * http://jqueryui.com 3729 * 3730 * Copyright jQuery Foundation and other contributors 3731 * Released under the MIT license. 3732 * http://jquery.org/license 3733 */ 3734 3735 //>>label: Shake Effect 3736 //>>group: Effects 3737 //>>description: Shakes an element horizontally or vertically n times. 3738 //>>docs: http://api.jqueryui.com/shake-effect/ 3739 //>>demos: http://jqueryui.com/effect/ 3740 3741 3742 3743 var effectsEffectShake = $.effects.define( "shake", function( options, done ) { 3744 3745 var i = 1, 3746 element = $( this ), 3747 direction = options.direction || "left", 3748 distance = options.distance || 20, 3749 times = options.times || 3, 3750 anims = times * 2 + 1, 3751 speed = Math.round( options.duration / anims ), 3752 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3753 positiveMotion = ( direction === "up" || direction === "left" ), 3754 animation = {}, 3755 animation1 = {}, 3756 animation2 = {}, 3757 3758 queuelen = element.queue().length; 3759 3760 $.effects.createPlaceholder( element ); 3761 3762 // Animation 3763 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; 3764 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; 3765 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; 3766 3767 // Animate 3768 element.animate( animation, speed, options.easing ); 3769 3770 // Shakes 3771 for ( ; i < times; i++ ) { 3772 element 3773 .animate( animation1, speed, options.easing ) 3774 .animate( animation2, speed, options.easing ); 3775 } 3776 3777 element 3778 .animate( animation1, speed, options.easing ) 3779 .animate( animation, speed / 2, options.easing ) 3780 .queue( done ); 3781 3782 $.effects.unshift( element, queuelen, anims + 1 ); 3783 } ); 3784 3785 3786 /*! 3787 * jQuery UI Effects Slide 1.12.1 3788 * http://jqueryui.com 3789 * 3790 * Copyright jQuery Foundation and other contributors 3791 * Released under the MIT license. 3792 * http://jquery.org/license 3793 */ 3794 3795 //>>label: Slide Effect 3796 //>>group: Effects 3797 //>>description: Slides an element in and out of the viewport. 3798 //>>docs: http://api.jqueryui.com/slide-effect/ 3799 //>>demos: http://jqueryui.com/effect/ 3800 3801 3802 3803 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) { 3804 var startClip, startRef, 3805 element = $( this ), 3806 map = { 3807 up: [ "bottom", "top" ], 3808 down: [ "top", "bottom" ], 3809 left: [ "right", "left" ], 3810 right: [ "left", "right" ] 3811 }, 3812 mode = options.mode, 3813 direction = options.direction || "left", 3814 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3815 positiveMotion = ( direction === "up" || direction === "left" ), 3816 distance = options.distance || 3817 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ), 3818 animation = {}; 3819 3820 $.effects.createPlaceholder( element ); 3821 3822 startClip = element.cssClip(); 3823 startRef = element.position()[ ref ]; 3824 3825 // Define hide animation 3826 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef; 3827 animation.clip = element.cssClip(); 3828 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ]; 3829 3830 // Reverse the animation if we're showing 3831 if ( mode === "show" ) { 3832 element.cssClip( animation.clip ); 3833 element.css( ref, animation[ ref ] ); 3834 animation.clip = startClip; 3835 animation[ ref ] = startRef; 3836 } 3837 3838 // Actually animate 3839 element.animate( animation, { 3840 queue: false, 3841 duration: options.duration, 3842 easing: options.easing, 3843 complete: done 3844 } ); 3845 } ); 3846 3847 3848 /*! 3849 * jQuery UI Effects Transfer 1.12.1 3850 * http://jqueryui.com 3851 * 3852 * Copyright jQuery Foundation and other contributors 3853 * Released under the MIT license. 3854 * http://jquery.org/license 3855 */ 3856 3857 //>>label: Transfer Effect 3858 //>>group: Effects 3859 //>>description: Displays a transfer effect from one element to another. 3860 //>>docs: http://api.jqueryui.com/transfer-effect/ 3861 //>>demos: http://jqueryui.com/effect/ 3862 3863 3864 3865 var effect; 3866 if ( $.uiBackCompat !== false ) { 3867 effect = $.effects.define( "transfer", function( options, done ) { 3868 $( this ).transfer( options, done ); 3869 } ); 3870 } 3871 var effectsEffectTransfer = effect; 3872 3873 3874 /*! 3875 * jQuery UI Focusable 1.12.1 3876 * http://jqueryui.com 3877 * 3878 * Copyright jQuery Foundation and other contributors 3879 * Released under the MIT license. 3880 * http://jquery.org/license 3881 */ 3882 3883 //>>label: :focusable Selector 3884 //>>group: Core 3885 //>>description: Selects elements which can be focused. 3886 //>>docs: http://api.jqueryui.com/focusable-selector/ 3887 3888 3889 3890 // Selectors 3891 $.ui.focusable = function( element, hasTabindex ) { 3892 var map, mapName, img, focusableIfVisible, fieldset, 3893 nodeName = element.nodeName.toLowerCase(); 3894 3895 if ( "area" === nodeName ) { 3896 map = element.parentNode; 3897 mapName = map.name; 3898 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { 3899 return false; 3900 } 3901 img = $( "img[usemap='#" + mapName + "']" ); 3902 return img.length > 0 && img.is( ":visible" ); 3903 } 3904 3905 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { 3906 focusableIfVisible = !element.disabled; 3907 3908 if ( focusableIfVisible ) { 3909 3910 // Form controls within a disabled fieldset are disabled. 3911 // However, controls within the fieldset's legend do not get disabled. 3912 // Since controls generally aren't placed inside legends, we skip 3913 // this portion of the check. 3914 fieldset = $( element ).closest( "fieldset" )[ 0 ]; 3915 if ( fieldset ) { 3916 focusableIfVisible = !fieldset.disabled; 3917 } 3918 } 3919 } else if ( "a" === nodeName ) { 3920 focusableIfVisible = element.href || hasTabindex; 3921 } else { 3922 focusableIfVisible = hasTabindex; 3923 } 3924 3925 return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) ); 3926 }; 3927 3928 // Support: IE 8 only 3929 // IE 8 doesn't resolve inherit to visible/hidden for computed values 3930 function visible( element ) { 3931 var visibility = element.css( "visibility" ); 3932 while ( visibility === "inherit" ) { 3933 element = element.parent(); 3934 visibility = element.css( "visibility" ); 3935 } 3936 return visibility !== "hidden"; 3937 } 3938 3939 $.extend( $.expr[ ":" ], { 3940 focusable: function( element ) { 3941 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); 3942 } 3943 } ); 3944 3945 var focusable = $.ui.focusable; 3946 3947 3948 3949 3950 // Support: IE8 Only 3951 // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop 3952 // with a string, so we need to find the proper form. 3953 var form = $.fn.form = function() { 3954 return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form ); 3955 }; 3956 3957 3958 /*! 3959 * jQuery UI Form Reset Mixin 1.12.1 3960 * http://jqueryui.com 3961 * 3962 * Copyright jQuery Foundation and other contributors 3963 * Released under the MIT license. 3964 * http://jquery.org/license 3965 */ 3966 3967 //>>label: Form Reset Mixin 3968 //>>group: Core 3969 //>>description: Refresh input widgets when their form is reset 3970 //>>docs: http://api.jqueryui.com/form-reset-mixin/ 3971 3972 3973 3974 var formResetMixin = $.ui.formResetMixin = { 3975 _formResetHandler: function() { 3976 var form = $( this ); 3977 3978 // Wait for the form reset to actually happen before refreshing 3979 setTimeout( function() { 3980 var instances = form.data( "ui-form-reset-instances" ); 3981 $.each( instances, function() { 3982 this.refresh(); 3983 } ); 3984 } ); 3985 }, 3986 3987 _bindFormResetHandler: function() { 3988 this.form = this.element.form(); 3989 if ( !this.form.length ) { 3990 return; 3991 } 3992 3993 var instances = this.form.data( "ui-form-reset-instances" ) || []; 3994 if ( !instances.length ) { 3995 3996 // We don't use _on() here because we use a single event handler per form 3997 this.form.on( "reset.ui-form-reset", this._formResetHandler ); 3998 } 3999 instances.push( this ); 4000 this.form.data( "ui-form-reset-instances", instances ); 4001 }, 4002 4003 _unbindFormResetHandler: function() { 4004 if ( !this.form.length ) { 4005 return; 4006 } 4007 4008 var instances = this.form.data( "ui-form-reset-instances" ); 4009 instances.splice( $.inArray( this, instances ), 1 ); 4010 if ( instances.length ) { 4011 this.form.data( "ui-form-reset-instances", instances ); 4012 } else { 4013 this.form 4014 .removeData( "ui-form-reset-instances" ) 4015 .off( "reset.ui-form-reset" ); 4016 } 4017 } 4018 }; 4019 4020 4021 /*! 4022 * jQuery UI Support for jQuery core 1.7.x 1.12.1 4023 * http://jqueryui.com 4024 * 4025 * Copyright jQuery Foundation and other contributors 4026 * Released under the MIT license. 4027 * http://jquery.org/license 4028 * 4029 */ 4030 4031 //>>label: jQuery 1.7 Support 4032 //>>group: Core 4033 //>>description: Support version 1.7.x of jQuery core 4034 4035 4036 4037 // Support: jQuery 1.7 only 4038 // Not a great way to check versions, but since we only support 1.7+ and only 4039 // need to detect <1.8, this is a simple check that should suffice. Checking 4040 // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0 4041 // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting 4042 // 1.7 anymore). See #11197 for why we're not using feature detection. 4043 if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) { 4044 4045 // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight() 4046 // Unlike jQuery Core 1.8+, these only support numeric values to set the 4047 // dimensions in pixels 4048 $.each( [ "Width", "Height" ], function( i, name ) { 4049 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], 4050 type = name.toLowerCase(), 4051 orig = { 4052 innerWidth: $.fn.innerWidth, 4053 innerHeight: $.fn.innerHeight, 4054 outerWidth: $.fn.outerWidth, 4055 outerHeight: $.fn.outerHeight 4056 }; 4057 4058 function reduce( elem, size, border, margin ) { 4059 $.each( side, function() { 4060 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; 4061 if ( border ) { 4062 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; 4063 } 4064 if ( margin ) { 4065 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; 4066 } 4067 } ); 4068 return size; 4069 } 4070 4071 $.fn[ "inner" + name ] = function( size ) { 4072 if ( size === undefined ) { 4073 return orig[ "inner" + name ].call( this ); 4074 } 4075 4076 return this.each( function() { 4077 $( this ).css( type, reduce( this, size ) + "px" ); 4078 } ); 4079 }; 4080 4081 $.fn[ "outer" + name ] = function( size, margin ) { 4082 if ( typeof size !== "number" ) { 4083 return orig[ "outer" + name ].call( this, size ); 4084 } 4085 4086 return this.each( function() { 4087 $( this ).css( type, reduce( this, size, true, margin ) + "px" ); 4088 } ); 4089 }; 4090 } ); 4091 4092 $.fn.addBack = function( selector ) { 4093 return this.add( selector == null ? 4094 this.prevObject : this.prevObject.filter( selector ) 4095 ); 4096 }; 4097 } 4098 4099 ; 4100 /*! 4101 * jQuery UI Keycode 1.12.1 4102 * http://jqueryui.com 4103 * 4104 * Copyright jQuery Foundation and other contributors 4105 * Released under the MIT license. 4106 * http://jquery.org/license 4107 */ 4108 4109 //>>label: Keycode 4110 //>>group: Core 4111 //>>description: Provide keycodes as keynames 4112 //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/ 4113 4114 4115 var keycode = $.ui.keyCode = { 4116 BACKSPACE: 8, 4117 COMMA: 188, 4118 DELETE: 46, 4119 DOWN: 40, 4120 END: 35, 4121 ENTER: 13, 4122 ESCAPE: 27, 4123 HOME: 36, 4124 LEFT: 37, 4125 PAGE_DOWN: 34, 4126 PAGE_UP: 33, 4127 PERIOD: 190, 4128 RIGHT: 39, 4129 SPACE: 32, 4130 TAB: 9, 4131 UP: 38 4132 }; 4133 4134 4135 4136 4137 // Internal use only 4138 var escapeSelector = $.ui.escapeSelector = ( function() { 4139 var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g; 4140 return function( selector ) { 4141 return selector.replace( selectorEscape, "\\$1" ); 4142 }; 4143 } )(); 4144 4145 4146 /*! 4147 * jQuery UI Labels 1.12.1 4148 * http://jqueryui.com 4149 * 4150 * Copyright jQuery Foundation and other contributors 4151 * Released under the MIT license. 4152 * http://jquery.org/license 4153 */ 4154 4155 //>>label: labels 4156 //>>group: Core 4157 //>>description: Find all the labels associated with a given input 4158 //>>docs: http://api.jqueryui.com/labels/ 4159 4160 4161 4162 var labels = $.fn.labels = function() { 4163 var ancestor, selector, id, labels, ancestors; 4164 4165 // Check control.labels first 4166 if ( this[ 0 ].labels && this[ 0 ].labels.length ) { 4167 return this.pushStack( this[ 0 ].labels ); 4168 } 4169 4170 // Support: IE <= 11, FF <= 37, Android <= 2.3 only 4171 // Above browsers do not support control.labels. Everything below is to support them 4172 // as well as document fragments. control.labels does not work on document fragments 4173 labels = this.eq( 0 ).parents( "label" ); 4174 4175 // Look for the label based on the id 4176 id = this.attr( "id" ); 4177 if ( id ) { 4178 4179 // We don't search against the document in case the element 4180 // is disconnected from the DOM 4181 ancestor = this.eq( 0 ).parents().last(); 4182 4183 // Get a full set of top level ancestors 4184 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); 4185 4186 // Create a selector for the label based on the id 4187 selector = "label[for='" + $.ui.escapeSelector( id ) + "']"; 4188 4189 labels = labels.add( ancestors.find( selector ).addBack( selector ) ); 4190 4191 } 4192 4193 // Return whatever we have found for labels 4194 return this.pushStack( labels ); 4195 }; 4196 4197 4198 /*! 4199 * jQuery UI Scroll Parent 1.12.1 4200 * http://jqueryui.com 4201 * 4202 * Copyright jQuery Foundation and other contributors 4203 * Released under the MIT license. 4204 * http://jquery.org/license 4205 */ 4206 4207 //>>label: scrollParent 4208 //>>group: Core 4209 //>>description: Get the closest ancestor element that is scrollable. 4210 //>>docs: http://api.jqueryui.com/scrollParent/ 4211 4212 4213 4214 var scrollParent = $.fn.scrollParent = function( includeHidden ) { 4215 var position = this.css( "position" ), 4216 excludeStaticParent = position === "absolute", 4217 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, 4218 scrollParent = this.parents().filter( function() { 4219 var parent = $( this ); 4220 if ( excludeStaticParent && parent.css( "position" ) === "static" ) { 4221 return false; 4222 } 4223 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + 4224 parent.css( "overflow-x" ) ); 4225 } ).eq( 0 ); 4226 4227 return position === "fixed" || !scrollParent.length ? 4228 $( this[ 0 ].ownerDocument || document ) : 4229 scrollParent; 4230 }; 4231 4232 4233 /*! 4234 * jQuery UI Tabbable 1.12.1 4235 * http://jqueryui.com 4236 * 4237 * Copyright jQuery Foundation and other contributors 4238 * Released under the MIT license. 4239 * http://jquery.org/license 4240 */ 4241 4242 //>>label: :tabbable Selector 4243 //>>group: Core 4244 //>>description: Selects elements which can be tabbed to. 4245 //>>docs: http://api.jqueryui.com/tabbable-selector/ 4246 4247 4248 4249 var tabbable = $.extend( $.expr[ ":" ], { 4250 tabbable: function( element ) { 4251 var tabIndex = $.attr( element, "tabindex" ), 4252 hasTabindex = tabIndex != null; 4253 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); 4254 } 4255 } ); 4256 4257 4258 /*! 4259 * jQuery UI Unique ID 1.12.1 4260 * http://jqueryui.com 4261 * 4262 * Copyright jQuery Foundation and other contributors 4263 * Released under the MIT license. 4264 * http://jquery.org/license 4265 */ 4266 4267 //>>label: uniqueId 4268 //>>group: Core 4269 //>>description: Functions to generate and remove uniqueId's 4270 //>>docs: http://api.jqueryui.com/uniqueId/ 4271 4272 4273 4274 var uniqueId = $.fn.extend( { 4275 uniqueId: ( function() { 4276 var uuid = 0; 4277 4278 return function() { 4279 return this.each( function() { 4280 if ( !this.id ) { 4281 this.id = "ui-id-" + ( ++uuid ); 4282 } 4283 } ); 4284 }; 4285 } )(), 4286 4287 removeUniqueId: function() { 4288 return this.each( function() { 4289 if ( /^ui-id-\d+$/.test( this.id ) ) { 4290 $( this ).removeAttr( "id" ); 4291 } 4292 } ); 4293 } 4294 } ); 4295 4296 4297 /*! 4298 * jQuery UI Accordion 1.12.1 4299 * http://jqueryui.com 4300 * 4301 * Copyright jQuery Foundation and other contributors 4302 * Released under the MIT license. 4303 * http://jquery.org/license 4304 */ 4305 4306 //>>label: Accordion 4307 //>>group: Widgets 4308 // jscs:disable maximumLineLength 4309 //>>description: Displays collapsible content panels for presenting information in a limited amount of space. 4310 // jscs:enable maximumLineLength 4311 //>>docs: http://api.jqueryui.com/accordion/ 4312 //>>demos: http://jqueryui.com/accordion/ 4313 //>>css.structure: ../../themes/base/core.css 4314 //>>css.structure: ../../themes/base/accordion.css 4315 //>>css.theme: ../../themes/base/theme.css 4316 4317 4318 4319 var widgetsAccordion = $.widget( "ui.accordion", { 4320 version: "1.12.1", 4321 options: { 4322 active: 0, 4323 animate: {}, 4324 classes: { 4325 "ui-accordion-header": "ui-corner-top", 4326 "ui-accordion-header-collapsed": "ui-corner-all", 4327 "ui-accordion-content": "ui-corner-bottom" 4328 }, 4329 collapsible: false, 4330 event: "click", 4331 header: "> li > :first-child, > :not(li):even", 4332 heightStyle: "auto", 4333 icons: { 4334 activeHeader: "ui-icon-triangle-1-s", 4335 header: "ui-icon-triangle-1-e" 4336 }, 4337 4338 // Callbacks 4339 activate: null, 4340 beforeActivate: null 4341 }, 4342 4343 hideProps: { 4344 borderTopWidth: "hide", 4345 borderBottomWidth: "hide", 4346 paddingTop: "hide", 4347 paddingBottom: "hide", 4348 height: "hide" 4349 }, 4350 4351 showProps: { 4352 borderTopWidth: "show", 4353 borderBottomWidth: "show", 4354 paddingTop: "show", 4355 paddingBottom: "show", 4356 height: "show" 4357 }, 4358 4359 _create: function() { 4360 var options = this.options; 4361 4362 this.prevShow = this.prevHide = $(); 4363 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); 4364 this.element.attr( "role", "tablist" ); 4365 4366 // Don't allow collapsible: false and active: false / null 4367 if ( !options.collapsible && ( options.active === false || options.active == null ) ) { 4368 options.active = 0; 4369 } 4370 4371 this._processPanels(); 4372 4373 // handle negative values 4374 if ( options.active < 0 ) { 4375 options.active += this.headers.length; 4376 } 4377 this._refresh(); 4378 }, 4379 4380 _getCreateEventData: function() { 4381 return { 4382 header: this.active, 4383 panel: !this.active.length ? $() : this.active.next() 4384 }; 4385 }, 4386 4387 _createIcons: function() { 4388 var icon, children, 4389 icons = this.options.icons; 4390 4391 if ( icons ) { 4392 icon = $( "<span>" ); 4393 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); 4394 icon.prependTo( this.headers ); 4395 children = this.active.children( ".ui-accordion-header-icon" ); 4396 this._removeClass( children, icons.header ) 4397 ._addClass( children, null, icons.activeHeader ) 4398 ._addClass( this.headers, "ui-accordion-icons" ); 4399 } 4400 }, 4401 4402 _destroyIcons: function() { 4403 this._removeClass( this.headers, "ui-accordion-icons" ); 4404 this.headers.children( ".ui-accordion-header-icon" ).remove(); 4405 }, 4406 4407 _destroy: function() { 4408 var contents; 4409 4410 // Clean up main element 4411 this.element.removeAttr( "role" ); 4412 4413 // Clean up headers 4414 this.headers 4415 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) 4416 .removeUniqueId(); 4417 4418 this._destroyIcons(); 4419 4420 // Clean up content panels 4421 contents = this.headers.next() 4422 .css( "display", "" ) 4423 .removeAttr( "role aria-hidden aria-labelledby" ) 4424 .removeUniqueId(); 4425 4426 if ( this.options.heightStyle !== "content" ) { 4427 contents.css( "height", "" ); 4428 } 4429 }, 4430 4431 _setOption: function( key, value ) { 4432 if ( key === "active" ) { 4433 4434 // _activate() will handle invalid values and update this.options 4435 this._activate( value ); 4436 return; 4437 } 4438 4439 if ( key === "event" ) { 4440 if ( this.options.event ) { 4441 this._off( this.headers, this.options.event ); 4442 } 4443 this._setupEvents( value ); 4444 } 4445 4446 this._super( key, value ); 4447 4448 // Setting collapsible: false while collapsed; open first panel 4449 if ( key === "collapsible" && !value && this.options.active === false ) { 4450 this._activate( 0 ); 4451 } 4452 4453 if ( key === "icons" ) { 4454 this._destroyIcons(); 4455 if ( value ) { 4456 this._createIcons(); 4457 } 4458 } 4459 }, 4460 4461 _setOptionDisabled: function( value ) { 4462 this._super( value ); 4463 4464 this.element.attr( "aria-disabled", value ); 4465 4466 // Support: IE8 Only 4467 // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE 4468 // so we need to add the disabled class to the headers and panels 4469 this._toggleClass( null, "ui-state-disabled", !!value ); 4470 this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled", 4471 !!value ); 4472 }, 4473 4474 _keydown: function( event ) { 4475 if ( event.altKey || event.ctrlKey ) { 4476 return; 4477 } 4478 4479 var keyCode = $.ui.keyCode, 4480 length = this.headers.length, 4481 currentIndex = this.headers.index( event.target ), 4482 toFocus = false; 4483 4484 switch ( event.keyCode ) { 4485 case keyCode.RIGHT: 4486 case keyCode.DOWN: 4487 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 4488 break; 4489 case keyCode.LEFT: 4490 case keyCode.UP: 4491 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 4492 break; 4493 case keyCode.SPACE: 4494 case keyCode.ENTER: 4495 this._eventHandler( event ); 4496 break; 4497 case keyCode.HOME: 4498 toFocus = this.headers[ 0 ]; 4499 break; 4500 case keyCode.END: 4501 toFocus = this.headers[ length - 1 ]; 4502 break; 4503 } 4504 4505 if ( toFocus ) { 4506 $( event.target ).attr( "tabIndex", -1 ); 4507 $( toFocus ).attr( "tabIndex", 0 ); 4508 $( toFocus ).trigger( "focus" ); 4509 event.preventDefault(); 4510 } 4511 }, 4512 4513 _panelKeyDown: function( event ) { 4514 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { 4515 $( event.currentTarget ).prev().trigger( "focus" ); 4516 } 4517 }, 4518 4519 refresh: function() { 4520 var options = this.options; 4521 this._processPanels(); 4522 4523 // Was collapsed or no panel 4524 if ( ( options.active === false && options.collapsible === true ) || 4525 !this.headers.length ) { 4526 options.active = false; 4527 this.active = $(); 4528 4529 // active false only when collapsible is true 4530 } else if ( options.active === false ) { 4531 this._activate( 0 ); 4532 4533 // was active, but active panel is gone 4534 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 4535 4536 // all remaining panel are disabled 4537 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { 4538 options.active = false; 4539 this.active = $(); 4540 4541 // activate previous panel 4542 } else { 4543 this._activate( Math.max( 0, options.active - 1 ) ); 4544 } 4545 4546 // was active, active panel still exists 4547 } else { 4548 4549 // make sure active index is correct 4550 options.active = this.headers.index( this.active ); 4551 } 4552 4553 this._destroyIcons(); 4554 4555 this._refresh(); 4556 }, 4557 4558 _processPanels: function() { 4559 var prevHeaders = this.headers, 4560 prevPanels = this.panels; 4561 4562 this.headers = this.element.find( this.options.header ); 4563 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", 4564 "ui-state-default" ); 4565 4566 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); 4567 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); 4568 4569 // Avoid memory leaks (#10056) 4570 if ( prevPanels ) { 4571 this._off( prevHeaders.not( this.headers ) ); 4572 this._off( prevPanels.not( this.panels ) ); 4573 } 4574 }, 4575 4576 _refresh: function() { 4577 var maxHeight, 4578 options = this.options, 4579 heightStyle = options.heightStyle, 4580 parent = this.element.parent(); 4581 4582 this.active = this._findActive( options.active ); 4583 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) 4584 ._removeClass( this.active, "ui-accordion-header-collapsed" ); 4585 this._addClass( this.active.next(), "ui-accordion-content-active" ); 4586 this.active.next().show(); 4587 4588 this.headers 4589 .attr( "role", "tab" ) 4590 .each( function() { 4591 var header = $( this ), 4592 headerId = header.uniqueId().attr( "id" ), 4593 panel = header.next(), 4594 panelId = panel.uniqueId().attr( "id" ); 4595 header.attr( "aria-controls", panelId ); 4596 panel.attr( "aria-labelledby", headerId ); 4597 } ) 4598 .next() 4599 .attr( "role", "tabpanel" ); 4600 4601 this.headers 4602 .not( this.active ) 4603 .attr( { 4604 "aria-selected": "false", 4605 "aria-expanded": "false", 4606 tabIndex: -1 4607 } ) 4608 .next() 4609 .attr( { 4610 "aria-hidden": "true" 4611 } ) 4612 .hide(); 4613 4614 // Make sure at least one header is in the tab order 4615 if ( !this.active.length ) { 4616 this.headers.eq( 0 ).attr( "tabIndex", 0 ); 4617 } else { 4618 this.active.attr( { 4619 "aria-selected": "true", 4620 "aria-expanded": "true", 4621 tabIndex: 0 4622 } ) 4623 .next() 4624 .attr( { 4625 "aria-hidden": "false" 4626 } ); 4627 } 4628 4629 this._createIcons(); 4630 4631 this._setupEvents( options.event ); 4632 4633 if ( heightStyle === "fill" ) { 4634 maxHeight = parent.height(); 4635 this.element.siblings( ":visible" ).each( function() { 4636 var elem = $( this ), 4637 position = elem.css( "position" ); 4638 4639 if ( position === "absolute" || position === "fixed" ) { 4640 return; 4641 } 4642 maxHeight -= elem.outerHeight( true ); 4643 } ); 4644 4645 this.headers.each( function() { 4646 maxHeight -= $( this ).outerHeight( true ); 4647 } ); 4648 4649 this.headers.next() 4650 .each( function() { 4651 $( this ).height( Math.max( 0, maxHeight - 4652 $( this ).innerHeight() + $( this ).height() ) ); 4653 } ) 4654 .css( "overflow", "auto" ); 4655 } else if ( heightStyle === "auto" ) { 4656 maxHeight = 0; 4657 this.headers.next() 4658 .each( function() { 4659 var isVisible = $( this ).is( ":visible" ); 4660 if ( !isVisible ) { 4661 $( this ).show(); 4662 } 4663 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); 4664 if ( !isVisible ) { 4665 $( this ).hide(); 4666 } 4667 } ) 4668 .height( maxHeight ); 4669 } 4670 }, 4671 4672 _activate: function( index ) { 4673 var active = this._findActive( index )[ 0 ]; 4674 4675 // Trying to activate the already active panel 4676 if ( active === this.active[ 0 ] ) { 4677 return; 4678 } 4679 4680 // Trying to collapse, simulate a click on the currently active header 4681 active = active || this.active[ 0 ]; 4682 4683 this._eventHandler( { 4684 target: active, 4685 currentTarget: active, 4686 preventDefault: $.noop 4687 } ); 4688 }, 4689 4690 _findActive: function( selector ) { 4691 return typeof selector === "number" ? this.headers.eq( selector ) : $(); 4692 }, 4693 4694 _setupEvents: function( event ) { 4695 var events = { 4696 keydown: "_keydown" 4697 }; 4698 if ( event ) { 4699 $.each( event.split( " " ), function( index, eventName ) { 4700 events[ eventName ] = "_eventHandler"; 4701 } ); 4702 } 4703 4704 this._off( this.headers.add( this.headers.next() ) ); 4705 this._on( this.headers, events ); 4706 this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); 4707 this._hoverable( this.headers ); 4708 this._focusable( this.headers ); 4709 }, 4710 4711 _eventHandler: function( event ) { 4712 var activeChildren, clickedChildren, 4713 options = this.options, 4714 active = this.active, 4715 clicked = $( event.currentTarget ), 4716 clickedIsActive = clicked[ 0 ] === active[ 0 ], 4717 collapsing = clickedIsActive && options.collapsible, 4718 toShow = collapsing ? $() : clicked.next(), 4719 toHide = active.next(), 4720 eventData = { 4721 oldHeader: active, 4722 oldPanel: toHide, 4723 newHeader: collapsing ? $() : clicked, 4724 newPanel: toShow 4725 }; 4726 4727 event.preventDefault(); 4728 4729 if ( 4730 4731 // click on active header, but not collapsible 4732 ( clickedIsActive && !options.collapsible ) || 4733 4734 // allow canceling activation 4735 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 4736 return; 4737 } 4738 4739 options.active = collapsing ? false : this.headers.index( clicked ); 4740 4741 // When the call to ._toggle() comes after the class changes 4742 // it causes a very odd bug in IE 8 (see #6720) 4743 this.active = clickedIsActive ? $() : clicked; 4744 this._toggle( eventData ); 4745 4746 // Switch classes 4747 // corner classes on the previously active header stay after the animation 4748 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); 4749 if ( options.icons ) { 4750 activeChildren = active.children( ".ui-accordion-header-icon" ); 4751 this._removeClass( activeChildren, null, options.icons.activeHeader ) 4752 ._addClass( activeChildren, null, options.icons.header ); 4753 } 4754 4755 if ( !clickedIsActive ) { 4756 this._removeClass( clicked, "ui-accordion-header-collapsed" ) 4757 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); 4758 if ( options.icons ) { 4759 clickedChildren = clicked.children( ".ui-accordion-header-icon" ); 4760 this._removeClass( clickedChildren, null, options.icons.header ) 4761 ._addClass( clickedChildren, null, options.icons.activeHeader ); 4762 } 4763 4764 this._addClass( clicked.next(), "ui-accordion-content-active" ); 4765 } 4766 }, 4767 4768 _toggle: function( data ) { 4769 var toShow = data.newPanel, 4770 toHide = this.prevShow.length ? this.prevShow : data.oldPanel; 4771 4772 // Handle activating a panel during the animation for another activation 4773 this.prevShow.add( this.prevHide ).stop( true, true ); 4774 this.prevShow = toShow; 4775 this.prevHide = toHide; 4776 4777 if ( this.options.animate ) { 4778 this._animate( toShow, toHide, data ); 4779 } else { 4780 toHide.hide(); 4781 toShow.show(); 4782 this._toggleComplete( data ); 4783 } 4784 4785 toHide.attr( { 4786 "aria-hidden": "true" 4787 } ); 4788 toHide.prev().attr( { 4789 "aria-selected": "false", 4790 "aria-expanded": "false" 4791 } ); 4792 4793 // if we're switching panels, remove the old header from the tab order 4794 // if we're opening from collapsed state, remove the previous header from the tab order 4795 // if we're collapsing, then keep the collapsing header in the tab order 4796 if ( toShow.length && toHide.length ) { 4797 toHide.prev().attr( { 4798 "tabIndex": -1, 4799 "aria-expanded": "false" 4800 } ); 4801 } else if ( toShow.length ) { 4802 this.headers.filter( function() { 4803 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; 4804 } ) 4805 .attr( "tabIndex", -1 ); 4806 } 4807 4808 toShow 4809 .attr( "aria-hidden", "false" ) 4810 .prev() 4811 .attr( { 4812 "aria-selected": "true", 4813 "aria-expanded": "true", 4814 tabIndex: 0 4815 } ); 4816 }, 4817 4818 _animate: function( toShow, toHide, data ) { 4819 var total, easing, duration, 4820 that = this, 4821 adjust = 0, 4822 boxSizing = toShow.css( "box-sizing" ), 4823 down = toShow.length && 4824 ( !toHide.length || ( toShow.index() < toHide.index() ) ), 4825 animate = this.options.animate || {}, 4826 options = down && animate.down || animate, 4827 complete = function() { 4828 that._toggleComplete( data ); 4829 }; 4830 4831 if ( typeof options === "number" ) { 4832 duration = options; 4833 } 4834 if ( typeof options === "string" ) { 4835 easing = options; 4836 } 4837 4838 // fall back from options to animation in case of partial down settings 4839 easing = easing || options.easing || animate.easing; 4840 duration = duration || options.duration || animate.duration; 4841 4842 if ( !toHide.length ) { 4843 return toShow.animate( this.showProps, duration, easing, complete ); 4844 } 4845 if ( !toShow.length ) { 4846 return toHide.animate( this.hideProps, duration, easing, complete ); 4847 } 4848 4849 total = toShow.show().outerHeight(); 4850 toHide.animate( this.hideProps, { 4851 duration: duration, 4852 easing: easing, 4853 step: function( now, fx ) { 4854 fx.now = Math.round( now ); 4855 } 4856 } ); 4857 toShow 4858 .hide() 4859 .animate( this.showProps, { 4860 duration: duration, 4861 easing: easing, 4862 complete: complete, 4863 step: function( now, fx ) { 4864 fx.now = Math.round( now ); 4865 if ( fx.prop !== "height" ) { 4866 if ( boxSizing === "content-box" ) { 4867 adjust += fx.now; 4868 } 4869 } else if ( that.options.heightStyle !== "content" ) { 4870 fx.now = Math.round( total - toHide.outerHeight() - adjust ); 4871 adjust = 0; 4872 } 4873 } 4874 } ); 4875 }, 4876 4877 _toggleComplete: function( data ) { 4878 var toHide = data.oldPanel, 4879 prev = toHide.prev(); 4880 4881 this._removeClass( toHide, "ui-accordion-content-active" ); 4882 this._removeClass( prev, "ui-accordion-header-active" ) 4883 ._addClass( prev, "ui-accordion-header-collapsed" ); 4884 4885 // Work around for rendering bug in IE (#5421) 4886 if ( toHide.length ) { 4887 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; 4888 } 4889 this._trigger( "activate", null, data ); 4890 } 4891 } ); 4892 4893 4894 4895 var safeActiveElement = $.ui.safeActiveElement = function( document ) { 4896 var activeElement; 4897 4898 // Support: IE 9 only 4899 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 4900 try { 4901 activeElement = document.activeElement; 4902 } catch ( error ) { 4903 activeElement = document.body; 4904 } 4905 4906 // Support: IE 9 - 11 only 4907 // IE may return null instead of an element 4908 // Interestingly, this only seems to occur when NOT in an iframe 4909 if ( !activeElement ) { 4910 activeElement = document.body; 4911 } 4912 4913 // Support: IE 11 only 4914 // IE11 returns a seemingly empty object in some cases when accessing 4915 // document.activeElement from an <iframe> 4916 if ( !activeElement.nodeName ) { 4917 activeElement = document.body; 4918 } 4919 4920 return activeElement; 4921 }; 4922 4923 4924 /*! 4925 * jQuery UI Menu 1.12.1 4926 * http://jqueryui.com 4927 * 4928 * Copyright jQuery Foundation and other contributors 4929 * Released under the MIT license. 4930 * http://jquery.org/license 4931 */ 4932 4933 //>>label: Menu 4934 //>>group: Widgets 4935 //>>description: Creates nestable menus. 4936 //>>docs: http://api.jqueryui.com/menu/ 4937 //>>demos: http://jqueryui.com/menu/ 4938 //>>css.structure: ../../themes/base/core.css 4939 //>>css.structure: ../../themes/base/menu.css 4940 //>>css.theme: ../../themes/base/theme.css 4941 4942 4943 4944 var widgetsMenu = $.widget( "ui.menu", { 4945 version: "1.12.1", 4946 defaultElement: "<ul>", 4947 delay: 300, 4948 options: { 4949 icons: { 4950 submenu: "ui-icon-caret-1-e" 4951 }, 4952 items: "> *", 4953 menus: "ul", 4954 position: { 4955 my: "left top", 4956 at: "right top" 4957 }, 4958 role: "menu", 4959 4960 // Callbacks 4961 blur: null, 4962 focus: null, 4963 select: null 4964 }, 4965 4966 _create: function() { 4967 this.activeMenu = this.element; 4968 4969 // Flag used to prevent firing of the click handler 4970 // as the event bubbles up through nested menus 4971 this.mouseHandled = false; 4972 this.element 4973 .uniqueId() 4974 .attr( { 4975 role: this.options.role, 4976 tabIndex: 0 4977 } ); 4978 4979 this._addClass( "ui-menu", "ui-widget ui-widget-content" ); 4980 this._on( { 4981 4982 // Prevent focus from sticking to links inside menu after clicking 4983 // them (focus should always stay on UL during navigation). 4984 "mousedown .ui-menu-item": function( event ) { 4985 event.preventDefault(); 4986 }, 4987 "click .ui-menu-item": function( event ) { 4988 var target = $( event.target ); 4989 var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); 4990 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { 4991 this.select( event ); 4992 4993 // Only set the mouseHandled flag if the event will bubble, see #9469. 4994 if ( !event.isPropagationStopped() ) { 4995 this.mouseHandled = true; 4996 } 4997 4998 // Open submenu on click 4999 if ( target.has( ".ui-menu" ).length ) { 5000 this.expand( event ); 5001 } else if ( !this.element.is( ":focus" ) && 5002 active.closest( ".ui-menu" ).length ) { 5003 5004 // Redirect focus to the menu 5005 this.element.trigger( "focus", [ true ] ); 5006 5007 // If the active item is on the top level, let it stay active. 5008 // Otherwise, blur the active item since it is no longer visible. 5009 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { 5010 clearTimeout( this.timer ); 5011 } 5012 } 5013 } 5014 }, 5015 "mouseenter .ui-menu-item": function( event ) { 5016 5017 // Ignore mouse events while typeahead is active, see #10458. 5018 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse 5019 // is over an item in the menu 5020 if ( this.previousFilter ) { 5021 return; 5022 } 5023 5024 var actualTarget = $( event.target ).closest( ".ui-menu-item" ), 5025 target = $( event.currentTarget ); 5026 5027 // Ignore bubbled events on parent items, see #11641 5028 if ( actualTarget[ 0 ] !== target[ 0 ] ) { 5029 return; 5030 } 5031 5032 // Remove ui-state-active class from siblings of the newly focused menu item 5033 // to avoid a jump caused by adjacent elements both having a class with a border 5034 this._removeClass( target.siblings().children( ".ui-state-active" ), 5035 null, "ui-state-active" ); 5036 this.focus( event, target ); 5037 }, 5038 mouseleave: "collapseAll", 5039 "mouseleave .ui-menu": "collapseAll", 5040 focus: function( event, keepActiveItem ) { 5041 5042 // If there's already an active item, keep it active 5043 // If not, activate the first item 5044 var item = this.active || this.element.find( this.options.items ).eq( 0 ); 5045 5046 if ( !keepActiveItem ) { 5047 this.focus( event, item ); 5048 } 5049 }, 5050 blur: function( event ) { 5051 this._delay( function() { 5052 var notContained = !$.contains( 5053 this.element[ 0 ], 5054 $.ui.safeActiveElement( this.document[ 0 ] ) 5055 ); 5056 if ( notContained ) { 5057 this.collapseAll( event ); 5058 } 5059 } ); 5060 }, 5061 keydown: "_keydown" 5062 } ); 5063 5064 this.refresh(); 5065 5066 // Clicks outside of a menu collapse any open menus 5067 this._on( this.document, { 5068 click: function( event ) { 5069 if ( this._closeOnDocumentClick( event ) ) { 5070 this.collapseAll( event ); 5071 } 5072 5073 // Reset the mouseHandled flag 5074 this.mouseHandled = false; 5075 } 5076 } ); 5077 }, 5078 5079 _destroy: function() { 5080 var items = this.element.find( ".ui-menu-item" ) 5081 .removeAttr( "role aria-disabled" ), 5082 submenus = items.children( ".ui-menu-item-wrapper" ) 5083 .removeUniqueId() 5084 .removeAttr( "tabIndex role aria-haspopup" ); 5085 5086 // Destroy (sub)menus 5087 this.element 5088 .removeAttr( "aria-activedescendant" ) 5089 .find( ".ui-menu" ).addBack() 5090 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " + 5091 "tabIndex" ) 5092 .removeUniqueId() 5093 .show(); 5094 5095 submenus.children().each( function() { 5096 var elem = $( this ); 5097 if ( elem.data( "ui-menu-submenu-caret" ) ) { 5098 elem.remove(); 5099 } 5100 } ); 5101 }, 5102 5103 _keydown: function( event ) { 5104 var match, prev, character, skip, 5105 preventDefault = true; 5106 5107 switch ( event.keyCode ) { 5108 case $.ui.keyCode.PAGE_UP: 5109 this.previousPage( event ); 5110 break; 5111 case $.ui.keyCode.PAGE_DOWN: 5112 this.nextPage( event ); 5113 break; 5114 case $.ui.keyCode.HOME: 5115 this._move( "first", "first", event ); 5116 break; 5117 case $.ui.keyCode.END: 5118 this._move( "last", "last", event ); 5119 break; 5120 case $.ui.keyCode.UP: 5121 this.previous( event ); 5122 break; 5123 case $.ui.keyCode.DOWN: 5124 this.next( event ); 5125 break; 5126 case $.ui.keyCode.LEFT: 5127 this.collapse( event ); 5128 break; 5129 case $.ui.keyCode.RIGHT: 5130 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 5131 this.expand( event ); 5132 } 5133 break; 5134 case $.ui.keyCode.ENTER: 5135 case $.ui.keyCode.SPACE: 5136 this._activate( event ); 5137 break; 5138 case $.ui.keyCode.ESCAPE: 5139 this.collapse( event ); 5140 break; 5141 default: 5142 preventDefault = false; 5143 prev = this.previousFilter || ""; 5144 skip = false; 5145 5146 // Support number pad values 5147 character = event.keyCode >= 96 && event.keyCode <= 105 ? 5148 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode ); 5149 5150 clearTimeout( this.filterTimer ); 5151 5152 if ( character === prev ) { 5153 skip = true; 5154 } else { 5155 character = prev + character; 5156 } 5157 5158 match = this._filterMenuItems( character ); 5159 match = skip && match.index( this.active.next() ) !== -1 ? 5160 this.active.nextAll( ".ui-menu-item" ) : 5161 match; 5162 5163 // If no matches on the current filter, reset to the last character pressed 5164 // to move down the menu to the first item that starts with that character 5165 if ( !match.length ) { 5166 character = String.fromCharCode( event.keyCode ); 5167 match = this._filterMenuItems( character ); 5168 } 5169 5170 if ( match.length ) { 5171 this.focus( event, match ); 5172 this.previousFilter = character; 5173 this.filterTimer = this._delay( function() { 5174 delete this.previousFilter; 5175 }, 1000 ); 5176 } else { 5177 delete this.previousFilter; 5178 } 5179 } 5180 5181 if ( preventDefault ) { 5182 event.preventDefault(); 5183 } 5184 }, 5185 5186 _activate: function( event ) { 5187 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 5188 if ( this.active.children( "[aria-haspopup='true']" ).length ) { 5189 this.expand( event ); 5190 } else { 5191 this.select( event ); 5192 } 5193 } 5194 }, 5195 5196 refresh: function() { 5197 var menus, items, newSubmenus, newItems, newWrappers, 5198 that = this, 5199 icon = this.options.icons.submenu, 5200 submenus = this.element.find( this.options.menus ); 5201 5202 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length ); 5203 5204 // Initialize nested menus 5205 newSubmenus = submenus.filter( ":not(.ui-menu)" ) 5206 .hide() 5207 .attr( { 5208 role: this.options.role, 5209 "aria-hidden": "true", 5210 "aria-expanded": "false" 5211 } ) 5212 .each( function() { 5213 var menu = $( this ), 5214 item = menu.prev(), 5215 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true ); 5216 5217 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon ); 5218 item 5219 .attr( "aria-haspopup", "true" ) 5220 .prepend( submenuCaret ); 5221 menu.attr( "aria-labelledby", item.attr( "id" ) ); 5222 } ); 5223 5224 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" ); 5225 5226 menus = submenus.add( this.element ); 5227 items = menus.find( this.options.items ); 5228 5229 // Initialize menu-items containing spaces and/or dashes only as dividers 5230 items.not( ".ui-menu-item" ).each( function() { 5231 var item = $( this ); 5232 if ( that._isDivider( item ) ) { 5233 that._addClass( item, "ui-menu-divider", "ui-widget-content" ); 5234 } 5235 } ); 5236 5237 // Don't refresh list items that are already adapted 5238 newItems = items.not( ".ui-menu-item, .ui-menu-divider" ); 5239 newWrappers = newItems.children() 5240 .not( ".ui-menu" ) 5241 .uniqueId() 5242 .attr( { 5243 tabIndex: -1, 5244 role: this._itemRole() 5245 } ); 5246 this._addClass( newItems, "ui-menu-item" ) 5247 ._addClass( newWrappers, "ui-menu-item-wrapper" ); 5248 5249 // Add aria-disabled attribute to any disabled menu item 5250 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); 5251 5252 // If the active item has been removed, blur the menu 5253 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 5254 this.blur(); 5255 } 5256 }, 5257 5258 _itemRole: function() { 5259 return { 5260 menu: "menuitem", 5261 listbox: "option" 5262 }[ this.options.role ]; 5263 }, 5264 5265 _setOption: function( key, value ) { 5266 if ( key === "icons" ) { 5267 var icons = this.element.find( ".ui-menu-icon" ); 5268 this._removeClass( icons, null, this.options.icons.submenu ) 5269 ._addClass( icons, null, value.submenu ); 5270 } 5271 this._super( key, value ); 5272 }, 5273 5274 _setOptionDisabled: function( value ) { 5275 this._super( value ); 5276 5277 this.element.attr( "aria-disabled", String( value ) ); 5278 this._toggleClass( null, "ui-state-disabled", !!value ); 5279 }, 5280 5281 focus: function( event, item ) { 5282 var nested, focused, activeParent; 5283 this.blur( event, event && event.type === "focus" ); 5284 5285 this._scrollIntoView( item ); 5286 5287 this.active = item.first(); 5288 5289 focused = this.active.children( ".ui-menu-item-wrapper" ); 5290 this._addClass( focused, null, "ui-state-active" ); 5291 5292 // Only update aria-activedescendant if there's a role 5293 // otherwise we assume focus is managed elsewhere 5294 if ( this.options.role ) { 5295 this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); 5296 } 5297 5298 // Highlight active parent menu item, if any 5299 activeParent = this.active 5300 .parent() 5301 .closest( ".ui-menu-item" ) 5302 .children( ".ui-menu-item-wrapper" ); 5303 this._addClass( activeParent, null, "ui-state-active" ); 5304 5305 if ( event && event.type === "keydown" ) { 5306 this._close(); 5307 } else { 5308 this.timer = this._delay( function() { 5309 this._close(); 5310 }, this.delay ); 5311 } 5312 5313 nested = item.children( ".ui-menu" ); 5314 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { 5315 this._startOpening( nested ); 5316 } 5317 this.activeMenu = item.parent(); 5318 5319 this._trigger( "focus", event, { item: item } ); 5320 }, 5321 5322 _scrollIntoView: function( item ) { 5323 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; 5324 if ( this._hasScroll() ) { 5325 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0; 5326 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0; 5327 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; 5328 scroll = this.activeMenu.scrollTop(); 5329 elementHeight = this.activeMenu.height(); 5330 itemHeight = item.outerHeight(); 5331 5332 if ( offset < 0 ) { 5333 this.activeMenu.scrollTop( scroll + offset ); 5334 } else if ( offset + itemHeight > elementHeight ) { 5335 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); 5336 } 5337 } 5338 }, 5339 5340 blur: function( event, fromFocus ) { 5341 if ( !fromFocus ) { 5342 clearTimeout( this.timer ); 5343 } 5344 5345 if ( !this.active ) { 5346 return; 5347 } 5348 5349 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ), 5350 null, "ui-state-active" ); 5351 5352 this._trigger( "blur", event, { item: this.active } ); 5353 this.active = null; 5354 }, 5355 5356 _startOpening: function( submenu ) { 5357 clearTimeout( this.timer ); 5358 5359 // Don't open if already open fixes a Firefox bug that caused a .5 pixel 5360 // shift in the submenu position when mousing over the caret icon 5361 if ( submenu.attr( "aria-hidden" ) !== "true" ) { 5362 return; 5363 } 5364 5365 this.timer = this._delay( function() { 5366 this._close(); 5367 this._open( submenu ); 5368 }, this.delay ); 5369 }, 5370 5371 _open: function( submenu ) { 5372 var position = $.extend( { 5373 of: this.active 5374 }, this.options.position ); 5375 5376 clearTimeout( this.timer ); 5377 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) 5378 .hide() 5379 .attr( "aria-hidden", "true" ); 5380 5381 submenu 5382 .show() 5383 .removeAttr( "aria-hidden" ) 5384 .attr( "aria-expanded", "true" ) 5385 .position( position ); 5386 }, 5387 5388 collapseAll: function( event, all ) { 5389 clearTimeout( this.timer ); 5390 this.timer = this._delay( function() { 5391 5392 // If we were passed an event, look for the submenu that contains the event 5393 var currentMenu = all ? this.element : 5394 $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); 5395 5396 // If we found no valid submenu ancestor, use the main menu to close all 5397 // sub menus anyway 5398 if ( !currentMenu.length ) { 5399 currentMenu = this.element; 5400 } 5401 5402 this._close( currentMenu ); 5403 5404 this.blur( event ); 5405 5406 // Work around active item staying active after menu is blurred 5407 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" ); 5408 5409 this.activeMenu = currentMenu; 5410 }, this.delay ); 5411 }, 5412 5413 // With no arguments, closes the currently active menu - if nothing is active 5414 // it closes all menus. If passed an argument, it will search for menus BELOW 5415 _close: function( startMenu ) { 5416 if ( !startMenu ) { 5417 startMenu = this.active ? this.active.parent() : this.element; 5418 } 5419 5420 startMenu.find( ".ui-menu" ) 5421 .hide() 5422 .attr( "aria-hidden", "true" ) 5423 .attr( "aria-expanded", "false" ); 5424 }, 5425 5426 _closeOnDocumentClick: function( event ) { 5427 return !$( event.target ).closest( ".ui-menu" ).length; 5428 }, 5429 5430 _isDivider: function( item ) { 5431 5432 // Match hyphen, em dash, en dash 5433 return !/[^\-\u2014\u2013\s]/.test( item.text() ); 5434 }, 5435 5436 collapse: function( event ) { 5437 var newItem = this.active && 5438 this.active.parent().closest( ".ui-menu-item", this.element ); 5439 if ( newItem && newItem.length ) { 5440 this._close(); 5441 this.focus( event, newItem ); 5442 } 5443 }, 5444 5445 expand: function( event ) { 5446 var newItem = this.active && 5447 this.active 5448 .children( ".ui-menu " ) 5449 .find( this.options.items ) 5450 .first(); 5451 5452 if ( newItem && newItem.length ) { 5453 this._open( newItem.parent() ); 5454 5455 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT 5456 this._delay( function() { 5457 this.focus( event, newItem ); 5458 } ); 5459 } 5460 }, 5461 5462 next: function( event ) { 5463 this._move( "next", "first", event ); 5464 }, 5465 5466 previous: function( event ) { 5467 this._move( "prev", "last", event ); 5468 }, 5469 5470 isFirstItem: function() { 5471 return this.active && !this.active.prevAll( ".ui-menu-item" ).length; 5472 }, 5473 5474 isLastItem: function() { 5475 return this.active && !this.active.nextAll( ".ui-menu-item" ).length; 5476 }, 5477 5478 _move: function( direction, filter, event ) { 5479 var next; 5480 if ( this.active ) { 5481 if ( direction === "first" || direction === "last" ) { 5482 next = this.active 5483 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) 5484 .eq( -1 ); 5485 } else { 5486 next = this.active 5487 [ direction + "All" ]( ".ui-menu-item" ) 5488 .eq( 0 ); 5489 } 5490 } 5491 if ( !next || !next.length || !this.active ) { 5492 next = this.activeMenu.find( this.options.items )[ filter ](); 5493 } 5494 5495 this.focus( event, next ); 5496 }, 5497 5498 nextPage: function( event ) { 5499 var item, base, height; 5500 5501 if ( !this.active ) { 5502 this.next( event ); 5503 return; 5504 } 5505 if ( this.isLastItem() ) { 5506 return; 5507 } 5508 if ( this._hasScroll() ) { 5509 base = this.active.offset().top; 5510 height = this.element.height(); 5511 this.active.nextAll( ".ui-menu-item" ).each( function() { 5512 item = $( this ); 5513 return item.offset().top - base - height < 0; 5514 } ); 5515 5516 this.focus( event, item ); 5517 } else { 5518 this.focus( event, this.activeMenu.find( this.options.items ) 5519 [ !this.active ? "first" : "last" ]() ); 5520 } 5521 }, 5522 5523 previousPage: function( event ) { 5524 var item, base, height; 5525 if ( !this.active ) { 5526 this.next( event ); 5527 return; 5528 } 5529 if ( this.isFirstItem() ) { 5530 return; 5531 } 5532 if ( this._hasScroll() ) { 5533 base = this.active.offset().top; 5534 height = this.element.height(); 5535 this.active.prevAll( ".ui-menu-item" ).each( function() { 5536 item = $( this ); 5537 return item.offset().top - base + height > 0; 5538 } ); 5539 5540 this.focus( event, item ); 5541 } else { 5542 this.focus( event, this.activeMenu.find( this.options.items ).first() ); 5543 } 5544 }, 5545 5546 _hasScroll: function() { 5547 return this.element.outerHeight() < this.element.prop( "scrollHeight" ); 5548 }, 5549 5550 select: function( event ) { 5551 5552 // TODO: It should never be possible to not have an active item at this 5553 // point, but the tests don't trigger mouseenter before click. 5554 this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); 5555 var ui = { item: this.active }; 5556 if ( !this.active.has( ".ui-menu" ).length ) { 5557 this.collapseAll( event, true ); 5558 } 5559 this._trigger( "select", event, ui ); 5560 }, 5561 5562 _filterMenuItems: function( character ) { 5563 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), 5564 regex = new RegExp( "^" + escapedCharacter, "i" ); 5565 5566 return this.activeMenu 5567 .find( this.options.items ) 5568 5569 // Only match on items, not dividers or other content (#10571) 5570 .filter( ".ui-menu-item" ) 5571 .filter( function() { 5572 return regex.test( 5573 $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) ); 5574 } ); 5575 } 5576 } ); 5577 5578 5579 /*! 5580 * jQuery UI Autocomplete 1.12.1 5581 * http://jqueryui.com 5582 * 5583 * Copyright jQuery Foundation and other contributors 5584 * Released under the MIT license. 5585 * http://jquery.org/license 5586 */ 5587 5588 //>>label: Autocomplete 5589 //>>group: Widgets 5590 //>>description: Lists suggested words as the user is typing. 5591 //>>docs: http://api.jqueryui.com/autocomplete/ 5592 //>>demos: http://jqueryui.com/autocomplete/ 5593 //>>css.structure: ../../themes/base/core.css 5594 //>>css.structure: ../../themes/base/autocomplete.css 5595 //>>css.theme: ../../themes/base/theme.css 5596 5597 5598 5599 $.widget( "ui.autocomplete", { 5600 version: "1.12.1", 5601 defaultElement: "<input>", 5602 options: { 5603 appendTo: null, 5604 autoFocus: false, 5605 delay: 300, 5606 minLength: 1, 5607 position: { 5608 my: "left top", 5609 at: "left bottom", 5610 collision: "none" 5611 }, 5612 source: null, 5613 5614 // Callbacks 5615 change: null, 5616 close: null, 5617 focus: null, 5618 open: null, 5619 response: null, 5620 search: null, 5621 select: null 5622 }, 5623 5624 requestIndex: 0, 5625 pending: 0, 5626 5627 _create: function() { 5628 5629 // Some browsers only repeat keydown events, not keypress events, 5630 // so we use the suppressKeyPress flag to determine if we've already 5631 // handled the keydown event. #7269 5632 // Unfortunately the code for & in keypress is the same as the up arrow, 5633 // so we use the suppressKeyPressRepeat flag to avoid handling keypress 5634 // events when we know the keydown event was used to modify the 5635 // search term. #7799 5636 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, 5637 nodeName = this.element[ 0 ].nodeName.toLowerCase(), 5638 isTextarea = nodeName === "textarea", 5639 isInput = nodeName === "input"; 5640 5641 // Textareas are always multi-line 5642 // Inputs are always single-line, even if inside a contentEditable element 5643 // IE also treats inputs as contentEditable 5644 // All other element types are determined by whether or not they're contentEditable 5645 this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element ); 5646 5647 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; 5648 this.isNewMenu = true; 5649 5650 this._addClass( "ui-autocomplete-input" ); 5651 this.element.attr( "autocomplete", "off" ); 5652 5653 this._on( this.element, { 5654 keydown: function( event ) { 5655 if ( this.element.prop( "readOnly" ) ) { 5656 suppressKeyPress = true; 5657 suppressInput = true; 5658 suppressKeyPressRepeat = true; 5659 return; 5660 } 5661 5662 suppressKeyPress = false; 5663 suppressInput = false; 5664 suppressKeyPressRepeat = false; 5665 var keyCode = $.ui.keyCode; 5666 switch ( event.keyCode ) { 5667 case keyCode.PAGE_UP: 5668 suppressKeyPress = true; 5669 this._move( "previousPage", event ); 5670 break; 5671 case keyCode.PAGE_DOWN: 5672 suppressKeyPress = true; 5673 this._move( "nextPage", event ); 5674 break; 5675 case keyCode.UP: 5676 suppressKeyPress = true; 5677 this._keyEvent( "previous", event ); 5678 break; 5679 case keyCode.DOWN: 5680 suppressKeyPress = true; 5681 this._keyEvent( "next", event ); 5682 break; 5683 case keyCode.ENTER: 5684 5685 // when menu is open and has focus 5686 if ( this.menu.active ) { 5687 5688 // #6055 - Opera still allows the keypress to occur 5689 // which causes forms to submit 5690 suppressKeyPress = true; 5691 event.preventDefault(); 5692 this.menu.select( event ); 5693 } 5694 break; 5695 case keyCode.TAB: 5696 if ( this.menu.active ) { 5697 this.menu.select( event ); 5698 } 5699 break; 5700 case keyCode.ESCAPE: 5701 if ( this.menu.element.is( ":visible" ) ) { 5702 if ( !this.isMultiLine ) { 5703 this._value( this.term ); 5704 } 5705 this.close( event ); 5706 5707 // Different browsers have different default behavior for escape 5708 // Single press can mean undo or clear 5709 // Double press in IE means clear the whole form 5710 event.preventDefault(); 5711 } 5712 break; 5713 default: 5714 suppressKeyPressRepeat = true; 5715 5716 // search timeout should be triggered before the input value is changed 5717 this._searchTimeout( event ); 5718 break; 5719 } 5720 }, 5721 keypress: function( event ) { 5722 if ( suppressKeyPress ) { 5723 suppressKeyPress = false; 5724 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 5725 event.preventDefault(); 5726 } 5727 return; 5728 } 5729 if ( suppressKeyPressRepeat ) { 5730 return; 5731 } 5732 5733 // Replicate some key handlers to allow them to repeat in Firefox and Opera 5734 var keyCode = $.ui.keyCode; 5735 switch ( event.keyCode ) { 5736 case keyCode.PAGE_UP: 5737 this._move( "previousPage", event ); 5738 break; 5739 case keyCode.PAGE_DOWN: 5740 this._move( "nextPage", event ); 5741 break; 5742 case keyCode.UP: 5743 this._keyEvent( "previous", event ); 5744 break; 5745 case keyCode.DOWN: 5746 this._keyEvent( "next", event ); 5747 break; 5748 } 5749 }, 5750 input: function( event ) { 5751 if ( suppressInput ) { 5752 suppressInput = false; 5753 event.preventDefault(); 5754 return; 5755 } 5756 this._searchTimeout( event ); 5757 }, 5758 focus: function() { 5759 this.selectedItem = null; 5760 this.previous = this._value(); 5761 }, 5762 blur: function( event ) { 5763 if ( this.cancelBlur ) { 5764 delete this.cancelBlur; 5765 return; 5766 } 5767 5768 clearTimeout( this.searching ); 5769 this.close( event ); 5770 this._change( event ); 5771 } 5772 } ); 5773 5774 this._initSource(); 5775 this.menu = $( "<ul>" ) 5776 .appendTo( this._appendTo() ) 5777 .menu( { 5778 5779 // disable ARIA support, the live region takes care of that 5780 role: null 5781 } ) 5782 .hide() 5783 .menu( "instance" ); 5784 5785 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" ); 5786 this._on( this.menu.element, { 5787 mousedown: function( event ) { 5788 5789 // prevent moving focus out of the text field 5790 event.preventDefault(); 5791 5792 // IE doesn't prevent moving focus even with event.preventDefault() 5793 // so we set a flag to know when we should ignore the blur event 5794 this.cancelBlur = true; 5795 this._delay( function() { 5796 delete this.cancelBlur; 5797 5798 // Support: IE 8 only 5799 // Right clicking a menu item or selecting text from the menu items will 5800 // result in focus moving out of the input. However, we've already received 5801 // and ignored the blur event because of the cancelBlur flag set above. So 5802 // we restore focus to ensure that the menu closes properly based on the user's 5803 // next actions. 5804 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { 5805 this.element.trigger( "focus" ); 5806 } 5807 } ); 5808 }, 5809 menufocus: function( event, ui ) { 5810 var label, item; 5811 5812 // support: Firefox 5813 // Prevent accidental activation of menu items in Firefox (#7024 #9118) 5814 if ( this.isNewMenu ) { 5815 this.isNewMenu = false; 5816 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { 5817 this.menu.blur(); 5818 5819 this.document.one( "mousemove", function() { 5820 $( event.target ).trigger( event.originalEvent ); 5821 } ); 5822 5823 return; 5824 } 5825 } 5826 5827 item = ui.item.data( "ui-autocomplete-item" ); 5828 if ( false !== this._trigger( "focus", event, { item: item } ) ) { 5829 5830 // use value to match what will end up in the input, if it was a key event 5831 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { 5832 this._value( item.value ); 5833 } 5834 } 5835 5836 // Announce the value in the liveRegion 5837 label = ui.item.attr( "aria-label" ) || item.value; 5838 if ( label && $.trim( label ).length ) { 5839 this.liveRegion.children().hide(); 5840 $( "<div>" ).text( label ).appendTo( this.liveRegion ); 5841 } 5842 }, 5843 menuselect: function( event, ui ) { 5844 var item = ui.item.data( "ui-autocomplete-item" ), 5845 previous = this.previous; 5846 5847 // Only trigger when focus was lost (click on menu) 5848 if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) { 5849 this.element.trigger( "focus" ); 5850 this.previous = previous; 5851 5852 // #6109 - IE triggers two focus events and the second 5853 // is asynchronous, so we need to reset the previous 5854 // term synchronously and asynchronously :-( 5855 this._delay( function() { 5856 this.previous = previous; 5857 this.selectedItem = item; 5858 } ); 5859 } 5860 5861 if ( false !== this._trigger( "select", event, { item: item } ) ) { 5862 this._value( item.value ); 5863 } 5864 5865 // reset the term after the select event 5866 // this allows custom select handling to work properly 5867 this.term = this._value(); 5868 5869 this.close( event ); 5870 this.selectedItem = item; 5871 } 5872 } ); 5873 5874 this.liveRegion = $( "<div>", { 5875 role: "status", 5876 "aria-live": "assertive", 5877 "aria-relevant": "additions" 5878 } ) 5879 .appendTo( this.document[ 0 ].body ); 5880 5881 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 5882 5883 // Turning off autocomplete prevents the browser from remembering the 5884 // value when navigating through history, so we re-enable autocomplete 5885 // if the page is unloaded before the widget is destroyed. #7790 5886 this._on( this.window, { 5887 beforeunload: function() { 5888 this.element.removeAttr( "autocomplete" ); 5889 } 5890 } ); 5891 }, 5892 5893 _destroy: function() { 5894 clearTimeout( this.searching ); 5895 this.element.removeAttr( "autocomplete" ); 5896 this.menu.element.remove(); 5897 this.liveRegion.remove(); 5898 }, 5899 5900 _setOption: function( key, value ) { 5901 this._super( key, value ); 5902 if ( key === "source" ) { 5903 this._initSource(); 5904 } 5905 if ( key === "appendTo" ) { 5906 this.menu.element.appendTo( this._appendTo() ); 5907 } 5908 if ( key === "disabled" && value && this.xhr ) { 5909 this.xhr.abort(); 5910 } 5911 }, 5912 5913 _isEventTargetInWidget: function( event ) { 5914 var menuElement = this.menu.element[ 0 ]; 5915 5916 return event.target === this.element[ 0 ] || 5917 event.target === menuElement || 5918 $.contains( menuElement, event.target ); 5919 }, 5920 5921 _closeOnClickOutside: function( event ) { 5922 if ( !this._isEventTargetInWidget( event ) ) { 5923 this.close(); 5924 } 5925 }, 5926 5927 _appendTo: function() { 5928 var element = this.options.appendTo; 5929 5930 if ( element ) { 5931 element = element.jquery || element.nodeType ? 5932 $( element ) : 5933 this.document.find( element ).eq( 0 ); 5934 } 5935 5936 if ( !element || !element[ 0 ] ) { 5937 element = this.element.closest( ".ui-front, dialog" ); 5938 } 5939 5940 if ( !element.length ) { 5941 element = this.document[ 0 ].body; 5942 } 5943 5944 return element; 5945 }, 5946 5947 _initSource: function() { 5948 var array, url, 5949 that = this; 5950 if ( $.isArray( this.options.source ) ) { 5951 array = this.options.source; 5952 this.source = function( request, response ) { 5953 response( $.ui.autocomplete.filter( array, request.term ) ); 5954 }; 5955 } else if ( typeof this.options.source === "string" ) { 5956 url = this.options.source; 5957 this.source = function( request, response ) { 5958 if ( that.xhr ) { 5959 that.xhr.abort(); 5960 } 5961 that.xhr = $.ajax( { 5962 url: url, 5963 data: request, 5964 dataType: "json", 5965 success: function( data ) { 5966 response( data ); 5967 }, 5968 error: function() { 5969 response( [] ); 5970 } 5971 } ); 5972 }; 5973 } else { 5974 this.source = this.options.source; 5975 } 5976 }, 5977 5978 _searchTimeout: function( event ) { 5979 clearTimeout( this.searching ); 5980 this.searching = this._delay( function() { 5981 5982 // Search if the value has changed, or if the user retypes the same value (see #7434) 5983 var equalValues = this.term === this._value(), 5984 menuVisible = this.menu.element.is( ":visible" ), 5985 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; 5986 5987 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { 5988 this.selectedItem = null; 5989 this.search( null, event ); 5990 } 5991 }, this.options.delay ); 5992 }, 5993 5994 search: function( value, event ) { 5995 value = value != null ? value : this._value(); 5996 5997 // Always save the actual value, not the one passed as an argument 5998 this.term = this._value(); 5999 6000 if ( value.length < this.options.minLength ) { 6001 return this.close( event ); 6002 } 6003 6004 if ( this._trigger( "search", event ) === false ) { 6005 return; 6006 } 6007 6008 return this._search( value ); 6009 }, 6010 6011 _search: function( value ) { 6012 this.pending++; 6013 this._addClass( "ui-autocomplete-loading" ); 6014 this.cancelSearch = false; 6015 6016 this.source( { term: value }, this._response() ); 6017 }, 6018 6019 _response: function() { 6020 var index = ++this.requestIndex; 6021 6022 return $.proxy( function( content ) { 6023 if ( index === this.requestIndex ) { 6024 this.__response( content ); 6025 } 6026 6027 this.pending--; 6028 if ( !this.pending ) { 6029 this._removeClass( "ui-autocomplete-loading" ); 6030 } 6031 }, this ); 6032 }, 6033 6034 __response: function( content ) { 6035 if ( content ) { 6036 content = this._normalize( content ); 6037 } 6038 this._trigger( "response", null, { content: content } ); 6039 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { 6040 this._suggest( content ); 6041 this._trigger( "open" ); 6042 } else { 6043 6044 // use ._close() instead of .close() so we don't cancel future searches 6045 this._close(); 6046 } 6047 }, 6048 6049 close: function( event ) { 6050 this.cancelSearch = true; 6051 this._close( event ); 6052 }, 6053 6054 _close: function( event ) { 6055 6056 // Remove the handler that closes the menu on outside clicks 6057 this._off( this.document, "mousedown" ); 6058 6059 if ( this.menu.element.is( ":visible" ) ) { 6060 this.menu.element.hide(); 6061 this.menu.blur(); 6062 this.isNewMenu = true; 6063 this._trigger( "close", event ); 6064 } 6065 }, 6066 6067 _change: function( event ) { 6068 if ( this.previous !== this._value() ) { 6069 this._trigger( "change", event, { item: this.selectedItem } ); 6070 } 6071 }, 6072 6073 _normalize: function( items ) { 6074 6075 // assume all items have the right format when the first item is complete 6076 if ( items.length && items[ 0 ].label && items[ 0 ].value ) { 6077 return items; 6078 } 6079 return $.map( items, function( item ) { 6080 if ( typeof item === "string" ) { 6081 return { 6082 label: item, 6083 value: item 6084 }; 6085 } 6086 return $.extend( {}, item, { 6087 label: item.label || item.value, 6088 value: item.value || item.label 6089 } ); 6090 } ); 6091 }, 6092 6093 _suggest: function( items ) { 6094 var ul = this.menu.element.empty(); 6095 this._renderMenu( ul, items ); 6096 this.isNewMenu = true; 6097 this.menu.refresh(); 6098 6099 // Size and position menu 6100 ul.show(); 6101 this._resizeMenu(); 6102 ul.position( $.extend( { 6103 of: this.element 6104 }, this.options.position ) ); 6105 6106 if ( this.options.autoFocus ) { 6107 this.menu.next(); 6108 } 6109 6110 // Listen for interactions outside of the widget (#6642) 6111 this._on( this.document, { 6112 mousedown: "_closeOnClickOutside" 6113 } ); 6114 }, 6115 6116 _resizeMenu: function() { 6117 var ul = this.menu.element; 6118 ul.outerWidth( Math.max( 6119 6120 // Firefox wraps long text (possibly a rounding bug) 6121 // so we add 1px to avoid the wrapping (#7513) 6122 ul.width( "" ).outerWidth() + 1, 6123 this.element.outerWidth() 6124 ) ); 6125 }, 6126 6127 _renderMenu: function( ul, items ) { 6128 var that = this; 6129 $.each( items, function( index, item ) { 6130 that._renderItemData( ul, item ); 6131 } ); 6132 }, 6133 6134 _renderItemData: function( ul, item ) { 6135 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 6136 }, 6137 6138 _renderItem: function( ul, item ) { 6139 return $( "<li>" ) 6140 .append( $( "<div>" ).text( item.label ) ) 6141 .appendTo( ul ); 6142 }, 6143 6144 _move: function( direction, event ) { 6145 if ( !this.menu.element.is( ":visible" ) ) { 6146 this.search( null, event ); 6147 return; 6148 } 6149 if ( this.menu.isFirstItem() && /^previous/.test( direction ) || 6150 this.menu.isLastItem() && /^next/.test( direction ) ) { 6151 6152 if ( !this.isMultiLine ) { 6153 this._value( this.term ); 6154 } 6155 6156 this.menu.blur(); 6157 return; 6158 } 6159 this.menu[ direction ]( event ); 6160 }, 6161 6162 widget: function() { 6163 return this.menu.element; 6164 }, 6165 6166 _value: function() { 6167 return this.valueMethod.apply( this.element, arguments ); 6168 }, 6169 6170 _keyEvent: function( keyEvent, event ) { 6171 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 6172 this._move( keyEvent, event ); 6173 6174 // Prevents moving cursor to beginning/end of the text field in some browsers 6175 event.preventDefault(); 6176 } 6177 }, 6178 6179 // Support: Chrome <=50 6180 // We should be able to just use this.element.prop( "isContentEditable" ) 6181 // but hidden elements always report false in Chrome. 6182 // https://code.google.com/p/chromium/issues/detail?id=313082 6183 _isContentEditable: function( element ) { 6184 if ( !element.length ) { 6185 return false; 6186 } 6187 6188 var editable = element.prop( "contentEditable" ); 6189 6190 if ( editable === "inherit" ) { 6191 return this._isContentEditable( element.parent() ); 6192 } 6193 6194 return editable === "true"; 6195 } 6196 } ); 6197 6198 $.extend( $.ui.autocomplete, { 6199 escapeRegex: function( value ) { 6200 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 6201 }, 6202 filter: function( array, term ) { 6203 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 6204 return $.grep( array, function( value ) { 6205 return matcher.test( value.label || value.value || value ); 6206 } ); 6207 } 6208 } ); 6209 6210 // Live region extension, adding a `messages` option 6211 // NOTE: This is an experimental API. We are still investigating 6212 // a full solution for string manipulation and internationalization. 6213 $.widget( "ui.autocomplete", $.ui.autocomplete, { 6214 options: { 6215 messages: { 6216 noResults: "No search results.", 6217 results: function( amount ) { 6218 return amount + ( amount > 1 ? " results are" : " result is" ) + 6219 " available, use up and down arrow keys to navigate."; 6220 } 6221 } 6222 }, 6223 6224 __response: function( content ) { 6225 var message; 6226 this._superApply( arguments ); 6227 if ( this.options.disabled || this.cancelSearch ) { 6228 return; 6229 } 6230 if ( content && content.length ) { 6231 message = this.options.messages.results( content.length ); 6232 } else { 6233 message = this.options.messages.noResults; 6234 } 6235 this.liveRegion.children().hide(); 6236 $( "<div>" ).text( message ).appendTo( this.liveRegion ); 6237 } 6238 } ); 6239 6240 var widgetsAutocomplete = $.ui.autocomplete; 6241 6242 6243 /*! 6244 * jQuery UI Controlgroup 1.12.1 6245 * http://jqueryui.com 6246 * 6247 * Copyright jQuery Foundation and other contributors 6248 * Released under the MIT license. 6249 * http://jquery.org/license 6250 */ 6251 6252 //>>label: Controlgroup 6253 //>>group: Widgets 6254 //>>description: Visually groups form control widgets 6255 //>>docs: http://api.jqueryui.com/controlgroup/ 6256 //>>demos: http://jqueryui.com/controlgroup/ 6257 //>>css.structure: ../../themes/base/core.css 6258 //>>css.structure: ../../themes/base/controlgroup.css 6259 //>>css.theme: ../../themes/base/theme.css 6260 6261 6262 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g; 6263 6264 var widgetsControlgroup = $.widget( "ui.controlgroup", { 6265 version: "1.12.1", 6266 defaultElement: "<div>", 6267 options: { 6268 direction: "horizontal", 6269 disabled: null, 6270 onlyVisible: true, 6271 items: { 6272 "button": "input[type=button], input[type=submit], input[type=reset], button, a", 6273 "controlgroupLabel": ".ui-controlgroup-label", 6274 "checkboxradio": "input[type='checkbox'], input[type='radio']", 6275 "selectmenu": "select", 6276 "spinner": ".ui-spinner-input" 6277 } 6278 }, 6279 6280 _create: function() { 6281 this._enhance(); 6282 }, 6283 6284 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation 6285 _enhance: function() { 6286 this.element.attr( "role", "toolbar" ); 6287 this.refresh(); 6288 }, 6289 6290 _destroy: function() { 6291 this._callChildMethod( "destroy" ); 6292 this.childWidgets.removeData( "ui-controlgroup-data" ); 6293 this.element.removeAttr( "role" ); 6294 if ( this.options.items.controlgroupLabel ) { 6295 this.element 6296 .find( this.options.items.controlgroupLabel ) 6297 .find( ".ui-controlgroup-label-contents" ) 6298 .contents().unwrap(); 6299 } 6300 }, 6301 6302 _initWidgets: function() { 6303 var that = this, 6304 childWidgets = []; 6305 6306 // First we iterate over each of the items options 6307 $.each( this.options.items, function( widget, selector ) { 6308 var labels; 6309 var options = {}; 6310 6311 // Make sure the widget has a selector set 6312 if ( !selector ) { 6313 return; 6314 } 6315 6316 if ( widget === "controlgroupLabel" ) { 6317 labels = that.element.find( selector ); 6318 labels.each( function() { 6319 var element = $( this ); 6320 6321 if ( element.children( ".ui-controlgroup-label-contents" ).length ) { 6322 return; 6323 } 6324 element.contents() 6325 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" ); 6326 } ); 6327 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" ); 6328 childWidgets = childWidgets.concat( labels.get() ); 6329 return; 6330 } 6331 6332 // Make sure the widget actually exists 6333 if ( !$.fn[ widget ] ) { 6334 return; 6335 } 6336 6337 // We assume everything is in the middle to start because we can't determine 6338 // first / last elements until all enhancments are done. 6339 if ( that[ "_" + widget + "Options" ] ) { 6340 options = that[ "_" + widget + "Options" ]( "middle" ); 6341 } else { 6342 options = { classes: {} }; 6343 } 6344 6345 // Find instances of this widget inside controlgroup and init them 6346 that.element 6347 .find( selector ) 6348 .each( function() { 6349 var element = $( this ); 6350 var instance = element[ widget ]( "instance" ); 6351 6352 // We need to clone the default options for this type of widget to avoid 6353 // polluting the variable options which has a wider scope than a single widget. 6354 var instanceOptions = $.widget.extend( {}, options ); 6355 6356 // If the button is the child of a spinner ignore it 6357 // TODO: Find a more generic solution 6358 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) { 6359 return; 6360 } 6361 6362 // Create the widget if it doesn't exist 6363 if ( !instance ) { 6364 instance = element[ widget ]()[ widget ]( "instance" ); 6365 } 6366 if ( instance ) { 6367 instanceOptions.classes = 6368 that._resolveClassesValues( instanceOptions.classes, instance ); 6369 } 6370 element[ widget ]( instanceOptions ); 6371 6372 // Store an instance of the controlgroup to be able to reference 6373 // from the outermost element for changing options and refresh 6374 var widgetElement = element[ widget ]( "widget" ); 6375 $.data( widgetElement[ 0 ], "ui-controlgroup-data", 6376 instance ? instance : element[ widget ]( "instance" ) ); 6377 6378 childWidgets.push( widgetElement[ 0 ] ); 6379 } ); 6380 } ); 6381 6382 this.childWidgets = $( $.unique( childWidgets ) ); 6383 this._addClass( this.childWidgets, "ui-controlgroup-item" ); 6384 }, 6385 6386 _callChildMethod: function( method ) { 6387 this.childWidgets.each( function() { 6388 var element = $( this ), 6389 data = element.data( "ui-controlgroup-data" ); 6390 if ( data && data[ method ] ) { 6391 data[ method ](); 6392 } 6393 } ); 6394 }, 6395 6396 _updateCornerClass: function( element, position ) { 6397 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all"; 6398 var add = this._buildSimpleOptions( position, "label" ).classes.label; 6399 6400 this._removeClass( element, null, remove ); 6401 this._addClass( element, null, add ); 6402 }, 6403 6404 _buildSimpleOptions: function( position, key ) { 6405 var direction = this.options.direction === "vertical"; 6406 var result = { 6407 classes: {} 6408 }; 6409 result.classes[ key ] = { 6410 "middle": "", 6411 "first": "ui-corner-" + ( direction ? "top" : "left" ), 6412 "last": "ui-corner-" + ( direction ? "bottom" : "right" ), 6413 "only": "ui-corner-all" 6414 }[ position ]; 6415 6416 return result; 6417 }, 6418 6419 _spinnerOptions: function( position ) { 6420 var options = this._buildSimpleOptions( position, "ui-spinner" ); 6421 6422 options.classes[ "ui-spinner-up" ] = ""; 6423 options.classes[ "ui-spinner-down" ] = ""; 6424 6425 return options; 6426 }, 6427 6428 _buttonOptions: function( position ) { 6429 return this._buildSimpleOptions( position, "ui-button" ); 6430 }, 6431 6432 _checkboxradioOptions: function( position ) { 6433 return this._buildSimpleOptions( position, "ui-checkboxradio-label" ); 6434 }, 6435 6436 _selectmenuOptions: function( position ) { 6437 var direction = this.options.direction === "vertical"; 6438 return { 6439 width: direction ? "auto" : false, 6440 classes: { 6441 middle: { 6442 "ui-selectmenu-button-open": "", 6443 "ui-selectmenu-button-closed": "" 6444 }, 6445 first: { 6446 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ), 6447 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" ) 6448 }, 6449 last: { 6450 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr", 6451 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" ) 6452 }, 6453 only: { 6454 "ui-selectmenu-button-open": "ui-corner-top", 6455 "ui-selectmenu-button-closed": "ui-corner-all" 6456 } 6457 6458 }[ position ] 6459 }; 6460 }, 6461 6462 _resolveClassesValues: function( classes, instance ) { 6463 var result = {}; 6464 $.each( classes, function( key ) { 6465 var current = instance.options.classes[ key ] || ""; 6466 current = $.trim( current.replace( controlgroupCornerRegex, "" ) ); 6467 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " ); 6468 } ); 6469 return result; 6470 }, 6471 6472 _setOption: function( key, value ) { 6473 if ( key === "direction" ) { 6474 this._removeClass( "ui-controlgroup-" + this.options.direction ); 6475 } 6476 6477 this._super( key, value ); 6478 if ( key === "disabled" ) { 6479 this._callChildMethod( value ? "disable" : "enable" ); 6480 return; 6481 } 6482 6483 this.refresh(); 6484 }, 6485 6486 refresh: function() { 6487 var children, 6488 that = this; 6489 6490 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); 6491 6492 if ( this.options.direction === "horizontal" ) { 6493 this._addClass( null, "ui-helper-clearfix" ); 6494 } 6495 this._initWidgets(); 6496 6497 children = this.childWidgets; 6498 6499 // We filter here because we need to track all childWidgets not just the visible ones 6500 if ( this.options.onlyVisible ) { 6501 children = children.filter( ":visible" ); 6502 } 6503 6504 if ( children.length ) { 6505 6506 // We do this last because we need to make sure all enhancment is done 6507 // before determining first and last 6508 $.each( [ "first", "last" ], function( index, value ) { 6509 var instance = children[ value ]().data( "ui-controlgroup-data" ); 6510 6511 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) { 6512 var options = that[ "_" + instance.widgetName + "Options" ]( 6513 children.length === 1 ? "only" : value 6514 ); 6515 options.classes = that._resolveClassesValues( options.classes, instance ); 6516 instance.element[ instance.widgetName ]( options ); 6517 } else { 6518 that._updateCornerClass( children[ value ](), value ); 6519 } 6520 } ); 6521 6522 // Finally call the refresh method on each of the child widgets. 6523 this._callChildMethod( "refresh" ); 6524 } 6525 } 6526 } ); 6527 6528 /*! 6529 * jQuery UI Checkboxradio 1.12.1 6530 * http://jqueryui.com 6531 * 6532 * Copyright jQuery Foundation and other contributors 6533 * Released under the MIT license. 6534 * http://jquery.org/license 6535 */ 6536 6537 //>>label: Checkboxradio 6538 //>>group: Widgets 6539 //>>description: Enhances a form with multiple themeable checkboxes or radio buttons. 6540 //>>docs: http://api.jqueryui.com/checkboxradio/ 6541 //>>demos: http://jqueryui.com/checkboxradio/ 6542 //>>css.structure: ../../themes/base/core.css 6543 //>>css.structure: ../../themes/base/button.css 6544 //>>css.structure: ../../themes/base/checkboxradio.css 6545 //>>css.theme: ../../themes/base/theme.css 6546 6547 6548 6549 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, { 6550 version: "1.12.1", 6551 options: { 6552 disabled: null, 6553 label: null, 6554 icon: true, 6555 classes: { 6556 "ui-checkboxradio-label": "ui-corner-all", 6557 "ui-checkboxradio-icon": "ui-corner-all" 6558 } 6559 }, 6560 6561 _getCreateOptions: function() { 6562 var disabled, labels; 6563 var that = this; 6564 var options = this._super() || {}; 6565 6566 // We read the type here, because it makes more sense to throw a element type error first, 6567 // rather then the error for lack of a label. Often if its the wrong type, it 6568 // won't have a label (e.g. calling on a div, btn, etc) 6569 this._readType(); 6570 6571 labels = this.element.labels(); 6572 6573 // If there are multiple labels, use the last one 6574 this.label = $( labels[ labels.length - 1 ] ); 6575 if ( !this.label.length ) { 6576 $.error( "No label found for checkboxradio widget" ); 6577 } 6578 6579 this.originalLabel = ""; 6580 6581 // We need to get the label text but this may also need to make sure it does not contain the 6582 // input itself. 6583 this.label.contents().not( this.element[ 0 ] ).each( function() { 6584 6585 // The label contents could be text, html, or a mix. We concat each element to get a 6586 // string representation of the label, without the input as part of it. 6587 that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML; 6588 } ); 6589 6590 // Set the label option if we found label text 6591 if ( this.originalLabel ) { 6592 options.label = this.originalLabel; 6593 } 6594 6595 disabled = this.element[ 0 ].disabled; 6596 if ( disabled != null ) { 6597 options.disabled = disabled; 6598 } 6599 return options; 6600 }, 6601 6602 _create: function() { 6603 var checked = this.element[ 0 ].checked; 6604 6605 this._bindFormResetHandler(); 6606 6607 if ( this.options.disabled == null ) { 6608 this.options.disabled = this.element[ 0 ].disabled; 6609 } 6610 6611 this._setOption( "disabled", this.options.disabled ); 6612 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); 6613 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); 6614 6615 if ( this.type === "radio" ) { 6616 this._addClass( this.label, "ui-checkboxradio-radio-label" ); 6617 } 6618 6619 if ( this.options.label && this.options.label !== this.originalLabel ) { 6620 this._updateLabel(); 6621 } else if ( this.originalLabel ) { 6622 this.options.label = this.originalLabel; 6623 } 6624 6625 this._enhance(); 6626 6627 if ( checked ) { 6628 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); 6629 if ( this.icon ) { 6630 this._addClass( this.icon, null, "ui-state-hover" ); 6631 } 6632 } 6633 6634 this._on( { 6635 change: "_toggleClasses", 6636 focus: function() { 6637 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); 6638 }, 6639 blur: function() { 6640 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); 6641 } 6642 } ); 6643 }, 6644 6645 _readType: function() { 6646 var nodeName = this.element[ 0 ].nodeName.toLowerCase(); 6647 this.type = this.element[ 0 ].type; 6648 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { 6649 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + 6650 " and element.type=" + this.type ); 6651 } 6652 }, 6653 6654 // Support jQuery Mobile enhanced option 6655 _enhance: function() { 6656 this._updateIcon( this.element[ 0 ].checked ); 6657 }, 6658 6659 widget: function() { 6660 return this.label; 6661 }, 6662 6663 _getRadioGroup: function() { 6664 var group; 6665 var name = this.element[ 0 ].name; 6666 var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']"; 6667 6668 if ( !name ) { 6669 return $( [] ); 6670 } 6671 6672 if ( this.form.length ) { 6673 group = $( this.form[ 0 ].elements ).filter( nameSelector ); 6674 } else { 6675 6676 // Not inside a form, check all inputs that also are not inside a form 6677 group = $( nameSelector ).filter( function() { 6678 return $( this ).form().length === 0; 6679 } ); 6680 } 6681 6682 return group.not( this.element ); 6683 }, 6684 6685 _toggleClasses: function() { 6686 var checked = this.element[ 0 ].checked; 6687 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 6688 6689 if ( this.options.icon && this.type === "checkbox" ) { 6690 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked ) 6691 ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); 6692 } 6693 6694 if ( this.type === "radio" ) { 6695 this._getRadioGroup() 6696 .each( function() { 6697 var instance = $( this ).checkboxradio( "instance" ); 6698 6699 if ( instance ) { 6700 instance._removeClass( instance.label, 6701 "ui-checkboxradio-checked", "ui-state-active" ); 6702 } 6703 } ); 6704 } 6705 }, 6706 6707 _destroy: function() { 6708 this._unbindFormResetHandler(); 6709 6710 if ( this.icon ) { 6711 this.icon.remove(); 6712 this.iconSpace.remove(); 6713 } 6714 }, 6715 6716 _setOption: function( key, value ) { 6717 6718 // We don't allow the value to be set to nothing 6719 if ( key === "label" && !value ) { 6720 return; 6721 } 6722 6723 this._super( key, value ); 6724 6725 if ( key === "disabled" ) { 6726 this._toggleClass( this.label, null, "ui-state-disabled", value ); 6727 this.element[ 0 ].disabled = value; 6728 6729 // Don't refresh when setting disabled 6730 return; 6731 } 6732 this.refresh(); 6733 }, 6734 6735 _updateIcon: function( checked ) { 6736 var toAdd = "ui-icon ui-icon-background "; 6737 6738 if ( this.options.icon ) { 6739 if ( !this.icon ) { 6740 this.icon = $( "<span>" ); 6741 this.iconSpace = $( "<span> </span>" ); 6742 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); 6743 } 6744 6745 if ( this.type === "checkbox" ) { 6746 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank"; 6747 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); 6748 } else { 6749 toAdd += "ui-icon-blank"; 6750 } 6751 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); 6752 if ( !checked ) { 6753 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" ); 6754 } 6755 this.icon.prependTo( this.label ).after( this.iconSpace ); 6756 } else if ( this.icon !== undefined ) { 6757 this.icon.remove(); 6758 this.iconSpace.remove(); 6759 delete this.icon; 6760 } 6761 }, 6762 6763 _updateLabel: function() { 6764 6765 // Remove the contents of the label ( minus the icon, icon space, and input ) 6766 var contents = this.label.contents().not( this.element[ 0 ] ); 6767 if ( this.icon ) { 6768 contents = contents.not( this.icon[ 0 ] ); 6769 } 6770 if ( this.iconSpace ) { 6771 contents = contents.not( this.iconSpace[ 0 ] ); 6772 } 6773 contents.remove(); 6774 6775 this.label.append( this.options.label ); 6776 }, 6777 6778 refresh: function() { 6779 var checked = this.element[ 0 ].checked, 6780 isDisabled = this.element[ 0 ].disabled; 6781 6782 this._updateIcon( checked ); 6783 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 6784 if ( this.options.label !== null ) { 6785 this._updateLabel(); 6786 } 6787 6788 if ( isDisabled !== this.options.disabled ) { 6789 this._setOptions( { "disabled": isDisabled } ); 6790 } 6791 } 6792 6793 } ] ); 6794 6795 var widgetsCheckboxradio = $.ui.checkboxradio; 6796 6797 6798 /*! 6799 * jQuery UI Button 1.12.1 6800 * http://jqueryui.com 6801 * 6802 * Copyright jQuery Foundation and other contributors 6803 * Released under the MIT license. 6804 * http://jquery.org/license 6805 */ 6806 6807 //>>label: Button 6808 //>>group: Widgets 6809 //>>description: Enhances a form with themeable buttons. 6810 //>>docs: http://api.jqueryui.com/button/ 6811 //>>demos: http://jqueryui.com/button/ 6812 //>>css.structure: ../../themes/base/core.css 6813 //>>css.structure: ../../themes/base/button.css 6814 //>>css.theme: ../../themes/base/theme.css 6815 6816 6817 6818 $.widget( "ui.button", { 6819 version: "1.12.1", 6820 defaultElement: "<button>", 6821 options: { 6822 classes: { 6823 "ui-button": "ui-corner-all" 6824 }, 6825 disabled: null, 6826 icon: null, 6827 iconPosition: "beginning", 6828 label: null, 6829 showLabel: true 6830 }, 6831 6832 _getCreateOptions: function() { 6833 var disabled, 6834 6835 // This is to support cases like in jQuery Mobile where the base widget does have 6836 // an implementation of _getCreateOptions 6837 options = this._super() || {}; 6838 6839 this.isInput = this.element.is( "input" ); 6840 6841 disabled = this.element[ 0 ].disabled; 6842 if ( disabled != null ) { 6843 options.disabled = disabled; 6844 } 6845 6846 this.originalLabel = this.isInput ? this.element.val() : this.element.html(); 6847 if ( this.originalLabel ) { 6848 options.label = this.originalLabel; 6849 } 6850 6851 return options; 6852 }, 6853 6854 _create: function() { 6855 if ( !this.option.showLabel & !this.options.icon ) { 6856 this.options.showLabel = true; 6857 } 6858 6859 // We have to check the option again here even though we did in _getCreateOptions, 6860 // because null may have been passed on init which would override what was set in 6861 // _getCreateOptions 6862 if ( this.options.disabled == null ) { 6863 this.options.disabled = this.element[ 0 ].disabled || false; 6864 } 6865 6866 this.hasTitle = !!this.element.attr( "title" ); 6867 6868 // Check to see if the label needs to be set or if its already correct 6869 if ( this.options.label && this.options.label !== this.originalLabel ) { 6870 if ( this.isInput ) { 6871 this.element.val( this.options.label ); 6872 } else { 6873 this.element.html( this.options.label ); 6874 } 6875 } 6876 this._addClass( "ui-button", "ui-widget" ); 6877 this._setOption( "disabled", this.options.disabled ); 6878 this._enhance(); 6879 6880 if ( this.element.is( "a" ) ) { 6881 this._on( { 6882 "keyup": function( event ) { 6883 if ( event.keyCode === $.ui.keyCode.SPACE ) { 6884 event.preventDefault(); 6885 6886 // Support: PhantomJS <= 1.9, IE 8 Only 6887 // If a native click is available use it so we actually cause navigation 6888 // otherwise just trigger a click event 6889 if ( this.element[ 0 ].click ) { 6890 this.element[ 0 ].click(); 6891 } else { 6892 this.element.trigger( "click" ); 6893 } 6894 } 6895 } 6896 } ); 6897 } 6898 }, 6899 6900 _enhance: function() { 6901 if ( !this.element.is( "button" ) ) { 6902 this.element.attr( "role", "button" ); 6903 } 6904 6905 if ( this.options.icon ) { 6906 this._updateIcon( "icon", this.options.icon ); 6907 this._updateTooltip(); 6908 } 6909 }, 6910 6911 _updateTooltip: function() { 6912 this.title = this.element.attr( "title" ); 6913 6914 if ( !this.options.showLabel && !this.title ) { 6915 this.element.attr( "title", this.options.label ); 6916 } 6917 }, 6918 6919 _updateIcon: function( option, value ) { 6920 var icon = option !== "iconPosition", 6921 position = icon ? this.options.iconPosition : value, 6922 displayBlock = position === "top" || position === "bottom"; 6923 6924 // Create icon 6925 if ( !this.icon ) { 6926 this.icon = $( "<span>" ); 6927 6928 this._addClass( this.icon, "ui-button-icon", "ui-icon" ); 6929 6930 if ( !this.options.showLabel ) { 6931 this._addClass( "ui-button-icon-only" ); 6932 } 6933 } else if ( icon ) { 6934 6935 // If we are updating the icon remove the old icon class 6936 this._removeClass( this.icon, null, this.options.icon ); 6937 } 6938 6939 // If we are updating the icon add the new icon class 6940 if ( icon ) { 6941 this._addClass( this.icon, null, value ); 6942 } 6943 6944 this._attachIcon( position ); 6945 6946 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove 6947 // the iconSpace if there is one. 6948 if ( displayBlock ) { 6949 this._addClass( this.icon, null, "ui-widget-icon-block" ); 6950 if ( this.iconSpace ) { 6951 this.iconSpace.remove(); 6952 } 6953 } else { 6954 6955 // Position is beginning or end so remove the ui-widget-icon-block class and add the 6956 // space if it does not exist 6957 if ( !this.iconSpace ) { 6958 this.iconSpace = $( "<span> </span>" ); 6959 this._addClass( this.iconSpace, "ui-button-icon-space" ); 6960 } 6961 this._removeClass( this.icon, null, "ui-wiget-icon-block" ); 6962 this._attachIconSpace( position ); 6963 } 6964 }, 6965 6966 _destroy: function() { 6967 this.element.removeAttr( "role" ); 6968 6969 if ( this.icon ) { 6970 this.icon.remove(); 6971 } 6972 if ( this.iconSpace ) { 6973 this.iconSpace.remove(); 6974 } 6975 if ( !this.hasTitle ) { 6976 this.element.removeAttr( "title" ); 6977 } 6978 }, 6979 6980 _attachIconSpace: function( iconPosition ) { 6981 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace ); 6982 }, 6983 6984 _attachIcon: function( iconPosition ) { 6985 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon ); 6986 }, 6987 6988 _setOptions: function( options ) { 6989 var newShowLabel = options.showLabel === undefined ? 6990 this.options.showLabel : 6991 options.showLabel, 6992 newIcon = options.icon === undefined ? this.options.icon : options.icon; 6993 6994 if ( !newShowLabel && !newIcon ) { 6995 options.showLabel = true; 6996 } 6997 this._super( options ); 6998 }, 6999 7000 _setOption: function( key, value ) { 7001 if ( key === "icon" ) { 7002 if ( value ) { 7003 this._updateIcon( key, value ); 7004 } else if ( this.icon ) { 7005 this.icon.remove(); 7006 if ( this.iconSpace ) { 7007 this.iconSpace.remove(); 7008 } 7009 } 7010 } 7011 7012 if ( key === "iconPosition" ) { 7013 this._updateIcon( key, value ); 7014 } 7015 7016 // Make sure we can't end up with a button that has neither text nor icon 7017 if ( key === "showLabel" ) { 7018 this._toggleClass( "ui-button-icon-only", null, !value ); 7019 this._updateTooltip(); 7020 } 7021 7022 if ( key === "label" ) { 7023 if ( this.isInput ) { 7024 this.element.val( value ); 7025 } else { 7026 7027 // If there is an icon, append it, else nothing then append the value 7028 // this avoids removal of the icon when setting label text 7029 this.element.html( value ); 7030 if ( this.icon ) { 7031 this._attachIcon( this.options.iconPosition ); 7032 this._attachIconSpace( this.options.iconPosition ); 7033 } 7034 } 7035 } 7036 7037 this._super( key, value ); 7038 7039 if ( key === "disabled" ) { 7040 this._toggleClass( null, "ui-state-disabled", value ); 7041 this.element[ 0 ].disabled = value; 7042 if ( value ) { 7043 this.element.blur(); 7044 } 7045 } 7046 }, 7047 7048 refresh: function() { 7049 7050 // Make sure to only check disabled if its an element that supports this otherwise 7051 // check for the disabled class to determine state 7052 var isDisabled = this.element.is( "input, button" ) ? 7053 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" ); 7054 7055 if ( isDisabled !== this.options.disabled ) { 7056 this._setOptions( { disabled: isDisabled } ); 7057 } 7058 7059 this._updateTooltip(); 7060 } 7061 } ); 7062 7063 // DEPRECATED 7064 if ( $.uiBackCompat !== false ) { 7065 7066 // Text and Icons options 7067 $.widget( "ui.button", $.ui.button, { 7068 options: { 7069 text: true, 7070 icons: { 7071 primary: null, 7072 secondary: null 7073 } 7074 }, 7075 7076 _create: function() { 7077 if ( this.options.showLabel && !this.options.text ) { 7078 this.options.showLabel = this.options.text; 7079 } 7080 if ( !this.options.showLabel && this.options.text ) { 7081 this.options.text = this.options.showLabel; 7082 } 7083 if ( !this.options.icon && ( this.options.icons.primary || 7084 this.options.icons.secondary ) ) { 7085 if ( this.options.icons.primary ) { 7086 this.options.icon = this.options.icons.primary; 7087 } else { 7088 this.options.icon = this.options.icons.secondary; 7089 this.options.iconPosition = "end"; 7090 } 7091 } else if ( this.options.icon ) { 7092 this.options.icons.primary = this.options.icon; 7093 } 7094 this._super(); 7095 }, 7096 7097 _setOption: function( key, value ) { 7098 if ( key === "text" ) { 7099 this._super( "showLabel", value ); 7100 return; 7101 } 7102 if ( key === "showLabel" ) { 7103 this.options.text = value; 7104 } 7105 if ( key === "icon" ) { 7106 this.options.icons.primary = value; 7107 } 7108 if ( key === "icons" ) { 7109 if ( value.primary ) { 7110 this._super( "icon", value.primary ); 7111 this._super( "iconPosition", "beginning" ); 7112 } else if ( value.secondary ) { 7113 this._super( "icon", value.secondary ); 7114 this._super( "iconPosition", "end" ); 7115 } 7116 } 7117 this._superApply( arguments ); 7118 } 7119 } ); 7120 7121 $.fn.button = ( function( orig ) { 7122 return function() { 7123 if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) || 7124 ( this.length && this[ 0 ].tagName === "INPUT" && ( 7125 this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio" 7126 ) ) ) { 7127 return orig.apply( this, arguments ); 7128 } 7129 if ( !$.ui.checkboxradio ) { 7130 $.error( "Checkboxradio widget missing" ); 7131 } 7132 if ( arguments.length === 0 ) { 7133 return this.checkboxradio( { 7134 "icon": false 7135 } ); 7136 } 7137 return this.checkboxradio.apply( this, arguments ); 7138 }; 7139 } )( $.fn.button ); 7140 7141 $.fn.buttonset = function() { 7142 if ( !$.ui.controlgroup ) { 7143 $.error( "Controlgroup widget missing" ); 7144 } 7145 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) { 7146 return this.controlgroup.apply( this, 7147 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] ); 7148 } 7149 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) { 7150 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] ); 7151 } 7152 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) { 7153 arguments[ 0 ].items = { 7154 button: arguments[ 0 ].items 7155 }; 7156 } 7157 return this.controlgroup.apply( this, arguments ); 7158 }; 7159 } 7160 7161 var widgetsButton = $.ui.button; 7162 7163 7164 // jscs:disable maximumLineLength 7165 /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */ 7166 /*! 7167 * jQuery UI Datepicker 1.12.1 7168 * http://jqueryui.com 7169 * 7170 * Copyright jQuery Foundation and other contributors 7171 7172 * Released under the MIT license. 7173 * http://jquery.org/license 7174 */ 7175 7176 //>>label: Datepicker 7177 //>>group: Widgets 7178 //>>description: Displays a calendar from an input or inline for selecting dates. 7179 //>>docs: http://api.jqueryui.com/datepicker/ 7180 //>>demos: http://jqueryui.com/datepicker/ 7181 //>>css.structure: ../../themes/base/core.css 7182 //>>css.structure: ../../themes/base/datepicker.css 7183 //>>css.theme: ../../themes/base/theme.css 7184 7185 7186 7187 $.extend( $.ui, { datepicker: { version: "1.12.1" } } ); 7188 7189 var datepicker_instActive; 7190 7191 function datepicker_getZindex( elem ) { 7192 var position, value; 7193 while ( elem.length && elem[ 0 ] !== document ) { 7194 7195 // Ignore z-index if position is set to a value where z-index is ignored by the browser 7196 // This makes behavior of this function consistent across browsers 7197 // WebKit always returns auto if the element is positioned 7198 position = elem.css( "position" ); 7199 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 7200 7201 // IE returns 0 when zIndex is not specified 7202 // other browsers return a string 7203 // we ignore the case of nested elements with an explicit value of 0 7204 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 7205 value = parseInt( elem.css( "zIndex" ), 10 ); 7206 if ( !isNaN( value ) && value !== 0 ) { 7207 return value; 7208 } 7209 } 7210 elem = elem.parent(); 7211 } 7212 7213 return 0; 7214 } 7215 /* Date picker manager. 7216 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 7217 Settings for (groups of) date pickers are maintained in an instance object, 7218 allowing multiple different settings on the same page. */ 7219 7220 function Datepicker() { 7221 this._curInst = null; // The current instance in use 7222 this._keyEvent = false; // If the last event was a key event 7223 this._disabledInputs = []; // List of date picker inputs that have been disabled 7224 this._datepickerShowing = false; // True if the popup picker is showing , false if not 7225 this._inDialog = false; // True if showing within a "dialog", false if not 7226 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 7227 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 7228 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 7229 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 7230 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 7231 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 7232 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 7233 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 7234 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 7235 this.regional = []; // Available regional settings, indexed by language code 7236 this.regional[ "" ] = { // Default regional settings 7237 closeText: "Done", // Display text for close link 7238 prevText: "Prev", // Display text for previous month link 7239 nextText: "Next", // Display text for next month link 7240 currentText: "Today", // Display text for current month link 7241 monthNames: [ "January","February","March","April","May","June", 7242 "July","August","September","October","November","December" ], // Names of months for drop-down and formatting 7243 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting 7244 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting 7245 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting 7246 dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday 7247 weekHeader: "Wk", // Column header for week of the year 7248 dateFormat: "mm/dd/yy", // See format options on parseDate 7249 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 7250 isRTL: false, // True if right-to-left language, false if left-to-right 7251 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 7252 yearSuffix: "" // Additional text to append to the year in the month headers 7253 }; 7254 this._defaults = { // Global defaults for all the date picker instances 7255 showOn: "focus", // "focus" for popup on focus, 7256 // "button" for trigger button, or "both" for either 7257 showAnim: "fadeIn", // Name of jQuery animation for popup 7258 showOptions: {}, // Options for enhanced animations 7259 defaultDate: null, // Used when field is blank: actual date, 7260 // +/-number for offset from today, null for today 7261 appendText: "", // Display text following the input box, e.g. showing the format 7262 buttonText: "...", // Text for trigger button 7263 buttonImage: "", // URL for trigger button image 7264 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 7265 hideIfNoPrevNext: false, // True to hide next/previous month links 7266 // if not applicable, false to just disable them 7267 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 7268 gotoCurrent: false, // True if today link goes back to current selection instead 7269 changeMonth: false, // True if month can be selected directly, false if only prev/next 7270 changeYear: false, // True if year can be selected directly, false if only prev/next 7271 yearRange: "c-10:c+10", // Range of years to display in drop-down, 7272 // either relative to today's year (-nn:+nn), relative to currently displayed year 7273 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 7274 showOtherMonths: false, // True to show dates in other months, false to leave blank 7275 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 7276 showWeek: false, // True to show week of the year, false to not show it 7277 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 7278 // takes a Date and returns the number of the week for it 7279 shortYearCutoff: "+10", // Short year values < this are in the current century, 7280 // > this are in the previous century, 7281 // string value starting with "+" for current year + value 7282 minDate: null, // The earliest selectable date, or null for no limit 7283 maxDate: null, // The latest selectable date, or null for no limit 7284 duration: "fast", // Duration of display/closure 7285 beforeShowDay: null, // Function that takes a date and returns an array with 7286 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 7287 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 7288 beforeShow: null, // Function that takes an input field and 7289 // returns a set of custom settings for the date picker 7290 onSelect: null, // Define a callback function when a date is selected 7291 onChangeMonthYear: null, // Define a callback function when the month or year is changed 7292 onClose: null, // Define a callback function when the datepicker is closed 7293 numberOfMonths: 1, // Number of months to show at a time 7294 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 7295 stepMonths: 1, // Number of months to step back/forward 7296 stepBigMonths: 12, // Number of months to step back/forward for the big links 7297 altField: "", // Selector for an alternate field to store selected dates into 7298 altFormat: "", // The date format to use for the alternate field 7299 constrainInput: true, // The input is constrained by the current date format 7300 showButtonPanel: false, // True to show button panel, false to not show it 7301 autoSize: false, // True to size the input for the date format, false to leave as is 7302 disabled: false // The initial disabled state 7303 }; 7304 $.extend( this._defaults, this.regional[ "" ] ); 7305 this.regional.en = $.extend( true, {}, this.regional[ "" ] ); 7306 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 7307 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 7308 } 7309 7310 $.extend( Datepicker.prototype, { 7311 /* Class name added to elements to indicate already configured with a date picker. */ 7312 markerClassName: "hasDatepicker", 7313 7314 //Keep track of the maximum number of rows displayed (see #7043) 7315 maxRows: 4, 7316 7317 // TODO rename to "widget" when switching to widget factory 7318 _widgetDatepicker: function() { 7319 return this.dpDiv; 7320 }, 7321 7322 /* Override the default settings for all instances of the date picker. 7323 * @param settings object - the new settings to use as defaults (anonymous object) 7324 * @return the manager object 7325 */ 7326 setDefaults: function( settings ) { 7327 datepicker_extendRemove( this._defaults, settings || {} ); 7328 return this; 7329 }, 7330 7331 /* Attach the date picker to a jQuery selection. 7332 * @param target element - the target input field or division or span 7333 * @param settings object - the new settings to use for this date picker instance (anonymous) 7334 */ 7335 _attachDatepicker: function( target, settings ) { 7336 var nodeName, inline, inst; 7337 nodeName = target.nodeName.toLowerCase(); 7338 inline = ( nodeName === "div" || nodeName === "span" ); 7339 if ( !target.id ) { 7340 this.uuid += 1; 7341 target.id = "dp" + this.uuid; 7342 } 7343 inst = this._newInst( $( target ), inline ); 7344 inst.settings = $.extend( {}, settings || {} ); 7345 if ( nodeName === "input" ) { 7346 this._connectDatepicker( target, inst ); 7347 } else if ( inline ) { 7348 this._inlineDatepicker( target, inst ); 7349 } 7350 }, 7351 7352 /* Create a new instance object. */ 7353 _newInst: function( target, inline ) { 7354 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars 7355 return { id: id, input: target, // associated target 7356 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 7357 drawMonth: 0, drawYear: 0, // month being drawn 7358 inline: inline, // is datepicker inline or not 7359 dpDiv: ( !inline ? this.dpDiv : // presentation div 7360 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) }; 7361 }, 7362 7363 /* Attach the date picker to an input field. */ 7364 _connectDatepicker: function( target, inst ) { 7365 var input = $( target ); 7366 inst.append = $( [] ); 7367 inst.trigger = $( [] ); 7368 if ( input.hasClass( this.markerClassName ) ) { 7369 return; 7370 } 7371 this._attachments( input, inst ); 7372 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ). 7373 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp ); 7374 this._autoSize( inst ); 7375 $.data( target, "datepicker", inst ); 7376 7377 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 7378 if ( inst.settings.disabled ) { 7379 this._disableDatepicker( target ); 7380 } 7381 }, 7382 7383 /* Make attachments based on settings. */ 7384 _attachments: function( input, inst ) { 7385 var showOn, buttonText, buttonImage, 7386 appendText = this._get( inst, "appendText" ), 7387 isRTL = this._get( inst, "isRTL" ); 7388 7389 if ( inst.append ) { 7390 inst.append.remove(); 7391 } 7392 if ( appendText ) { 7393 inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" ); 7394 input[ isRTL ? "before" : "after" ]( inst.append ); 7395 } 7396 7397 input.off( "focus", this._showDatepicker ); 7398 7399 if ( inst.trigger ) { 7400 inst.trigger.remove(); 7401 } 7402 7403 showOn = this._get( inst, "showOn" ); 7404 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field 7405 input.on( "focus", this._showDatepicker ); 7406 } 7407 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked 7408 buttonText = this._get( inst, "buttonText" ); 7409 buttonImage = this._get( inst, "buttonImage" ); 7410 inst.trigger = $( this._get( inst, "buttonImageOnly" ) ? 7411 $( "<img/>" ).addClass( this._triggerClass ). 7412 attr( { src: buttonImage, alt: buttonText, title: buttonText } ) : 7413 $( "<button type='button'></button>" ).addClass( this._triggerClass ). 7414 html( !buttonImage ? buttonText : $( "<img/>" ).attr( 7415 { src:buttonImage, alt:buttonText, title:buttonText } ) ) ); 7416 input[ isRTL ? "before" : "after" ]( inst.trigger ); 7417 inst.trigger.on( "click", function() { 7418 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) { 7419 $.datepicker._hideDatepicker(); 7420 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) { 7421 $.datepicker._hideDatepicker(); 7422 $.datepicker._showDatepicker( input[ 0 ] ); 7423 } else { 7424 $.datepicker._showDatepicker( input[ 0 ] ); 7425 } 7426 return false; 7427 } ); 7428 } 7429 }, 7430 7431 /* Apply the maximum length for the date format. */ 7432 _autoSize: function( inst ) { 7433 if ( this._get( inst, "autoSize" ) && !inst.inline ) { 7434 var findMax, max, maxI, i, 7435 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits 7436 dateFormat = this._get( inst, "dateFormat" ); 7437 7438 if ( dateFormat.match( /[DM]/ ) ) { 7439 findMax = function( names ) { 7440 max = 0; 7441 maxI = 0; 7442 for ( i = 0; i < names.length; i++ ) { 7443 if ( names[ i ].length > max ) { 7444 max = names[ i ].length; 7445 maxI = i; 7446 } 7447 } 7448 return maxI; 7449 }; 7450 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ? 7451 "monthNames" : "monthNamesShort" ) ) ) ); 7452 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ? 7453 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() ); 7454 } 7455 inst.input.attr( "size", this._formatDate( inst, date ).length ); 7456 } 7457 }, 7458 7459 /* Attach an inline date picker to a div. */ 7460 _inlineDatepicker: function( target, inst ) { 7461 var divSpan = $( target ); 7462 if ( divSpan.hasClass( this.markerClassName ) ) { 7463 return; 7464 } 7465 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 7466 $.data( target, "datepicker", inst ); 7467 this._setDate( inst, this._getDefaultDate( inst ), true ); 7468 this._updateDatepicker( inst ); 7469 this._updateAlternate( inst ); 7470 7471 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 7472 if ( inst.settings.disabled ) { 7473 this._disableDatepicker( target ); 7474 } 7475 7476 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 7477 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 7478 inst.dpDiv.css( "display", "block" ); 7479 }, 7480 7481 /* Pop-up the date picker in a "dialog" box. 7482 * @param input element - ignored 7483 * @param date string or Date - the initial date to display 7484 * @param onSelect function - the function to call when a date is selected 7485 * @param settings object - update the dialog date picker instance's settings (anonymous object) 7486 * @param pos int[2] - coordinates for the dialog's position within the screen or 7487 * event - with x/y coordinates or 7488 * leave empty for default (screen centre) 7489 * @return the manager object 7490 */ 7491 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 7492 var id, browserWidth, browserHeight, scrollX, scrollY, 7493 inst = this._dialogInst; // internal instance 7494 7495 if ( !inst ) { 7496 this.uuid += 1; 7497 id = "dp" + this.uuid; 7498 this._dialogInput = $( "<input type='text' id='" + id + 7499 "' style='position: absolute; top: -100px; width: 0px;'/>" ); 7500 this._dialogInput.on( "keydown", this._doKeyDown ); 7501 $( "body" ).append( this._dialogInput ); 7502 inst = this._dialogInst = this._newInst( this._dialogInput, false ); 7503 inst.settings = {}; 7504 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7505 } 7506 datepicker_extendRemove( inst.settings, settings || {} ); 7507 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date ); 7508 this._dialogInput.val( date ); 7509 7510 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null ); 7511 if ( !this._pos ) { 7512 browserWidth = document.documentElement.clientWidth; 7513 browserHeight = document.documentElement.clientHeight; 7514 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 7515 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 7516 this._pos = // should use actual width/height below 7517 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 7518 } 7519 7520 // Move input on screen for focus, but hidden behind dialog 7521 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" ); 7522 inst.settings.onSelect = onSelect; 7523 this._inDialog = true; 7524 this.dpDiv.addClass( this._dialogClass ); 7525 this._showDatepicker( this._dialogInput[ 0 ] ); 7526 if ( $.blockUI ) { 7527 $.blockUI( this.dpDiv ); 7528 } 7529 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7530 return this; 7531 }, 7532 7533 /* Detach a datepicker from its control. 7534 * @param target element - the target input field or division or span 7535 */ 7536 _destroyDatepicker: function( target ) { 7537 var nodeName, 7538 $target = $( target ), 7539 inst = $.data( target, "datepicker" ); 7540 7541 if ( !$target.hasClass( this.markerClassName ) ) { 7542 return; 7543 } 7544 7545 nodeName = target.nodeName.toLowerCase(); 7546 $.removeData( target, "datepicker" ); 7547 if ( nodeName === "input" ) { 7548 inst.append.remove(); 7549 inst.trigger.remove(); 7550 $target.removeClass( this.markerClassName ). 7551 off( "focus", this._showDatepicker ). 7552 off( "keydown", this._doKeyDown ). 7553 off( "keypress", this._doKeyPress ). 7554 off( "keyup", this._doKeyUp ); 7555 } else if ( nodeName === "div" || nodeName === "span" ) { 7556 $target.removeClass( this.markerClassName ).empty(); 7557 } 7558 7559 if ( datepicker_instActive === inst ) { 7560 datepicker_instActive = null; 7561 } 7562 }, 7563 7564 /* Enable the date picker to a jQuery selection. 7565 * @param target element - the target input field or division or span 7566 */ 7567 _enableDatepicker: function( target ) { 7568 var nodeName, inline, 7569 $target = $( target ), 7570 inst = $.data( target, "datepicker" ); 7571 7572 if ( !$target.hasClass( this.markerClassName ) ) { 7573 return; 7574 } 7575 7576 nodeName = target.nodeName.toLowerCase(); 7577 if ( nodeName === "input" ) { 7578 target.disabled = false; 7579 inst.trigger.filter( "button" ). 7580 each( function() { this.disabled = false; } ).end(). 7581 filter( "img" ).css( { opacity: "1.0", cursor: "" } ); 7582 } else if ( nodeName === "div" || nodeName === "span" ) { 7583 inline = $target.children( "." + this._inlineClass ); 7584 inline.children().removeClass( "ui-state-disabled" ); 7585 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7586 prop( "disabled", false ); 7587 } 7588 this._disabledInputs = $.map( this._disabledInputs, 7589 function( value ) { return ( value === target ? null : value ); } ); // delete entry 7590 }, 7591 7592 /* Disable the date picker to a jQuery selection. 7593 * @param target element - the target input field or division or span 7594 */ 7595 _disableDatepicker: function( target ) { 7596 var nodeName, inline, 7597 $target = $( target ), 7598 inst = $.data( target, "datepicker" ); 7599 7600 if ( !$target.hasClass( this.markerClassName ) ) { 7601 return; 7602 } 7603 7604 nodeName = target.nodeName.toLowerCase(); 7605 if ( nodeName === "input" ) { 7606 target.disabled = true; 7607 inst.trigger.filter( "button" ). 7608 each( function() { this.disabled = true; } ).end(). 7609 filter( "img" ).css( { opacity: "0.5", cursor: "default" } ); 7610 } else if ( nodeName === "div" || nodeName === "span" ) { 7611 inline = $target.children( "." + this._inlineClass ); 7612 inline.children().addClass( "ui-state-disabled" ); 7613 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7614 prop( "disabled", true ); 7615 } 7616 this._disabledInputs = $.map( this._disabledInputs, 7617 function( value ) { return ( value === target ? null : value ); } ); // delete entry 7618 this._disabledInputs[ this._disabledInputs.length ] = target; 7619 }, 7620 7621 /* Is the first field in a jQuery collection disabled as a datepicker? 7622 * @param target element - the target input field or division or span 7623 * @return boolean - true if disabled, false if enabled 7624 */ 7625 _isDisabledDatepicker: function( target ) { 7626 if ( !target ) { 7627 return false; 7628 } 7629 for ( var i = 0; i < this._disabledInputs.length; i++ ) { 7630 if ( this._disabledInputs[ i ] === target ) { 7631 return true; 7632 } 7633 } 7634 return false; 7635 }, 7636 7637 /* Retrieve the instance data for the target control. 7638 * @param target element - the target input field or division or span 7639 * @return object - the associated instance data 7640 * @throws error if a jQuery problem getting data 7641 */ 7642 _getInst: function( target ) { 7643 try { 7644 return $.data( target, "datepicker" ); 7645 } 7646 catch ( err ) { 7647 throw "Missing instance data for this datepicker"; 7648 } 7649 }, 7650 7651 /* Update or retrieve the settings for a date picker attached to an input field or division. 7652 * @param target element - the target input field or division or span 7653 * @param name object - the new settings to update or 7654 * string - the name of the setting to change or retrieve, 7655 * when retrieving also "all" for all instance settings or 7656 * "defaults" for all global defaults 7657 * @param value any - the new value for the setting 7658 * (omit if above is an object or to retrieve a value) 7659 */ 7660 _optionDatepicker: function( target, name, value ) { 7661 var settings, date, minDate, maxDate, 7662 inst = this._getInst( target ); 7663 7664 if ( arguments.length === 2 && typeof name === "string" ) { 7665 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) : 7666 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) : 7667 this._get( inst, name ) ) : null ) ); 7668 } 7669 7670 settings = name || {}; 7671 if ( typeof name === "string" ) { 7672 settings = {}; 7673 settings[ name ] = value; 7674 } 7675 7676 if ( inst ) { 7677 if ( this._curInst === inst ) { 7678 this._hideDatepicker(); 7679 } 7680 7681 date = this._getDateDatepicker( target, true ); 7682 minDate = this._getMinMaxDate( inst, "min" ); 7683 maxDate = this._getMinMaxDate( inst, "max" ); 7684 datepicker_extendRemove( inst.settings, settings ); 7685 7686 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 7687 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 7688 inst.settings.minDate = this._formatDate( inst, minDate ); 7689 } 7690 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 7691 inst.settings.maxDate = this._formatDate( inst, maxDate ); 7692 } 7693 if ( "disabled" in settings ) { 7694 if ( settings.disabled ) { 7695 this._disableDatepicker( target ); 7696 } else { 7697 this._enableDatepicker( target ); 7698 } 7699 } 7700 this._attachments( $( target ), inst ); 7701 this._autoSize( inst ); 7702 this._setDate( inst, date ); 7703 this._updateAlternate( inst ); 7704 this._updateDatepicker( inst ); 7705 } 7706 }, 7707 7708 // Change method deprecated 7709 _changeDatepicker: function( target, name, value ) { 7710 this._optionDatepicker( target, name, value ); 7711 }, 7712 7713 /* Redraw the date picker attached to an input field or division. 7714 * @param target element - the target input field or division or span 7715 */ 7716 _refreshDatepicker: function( target ) { 7717 var inst = this._getInst( target ); 7718 if ( inst ) { 7719 this._updateDatepicker( inst ); 7720 } 7721 }, 7722 7723 /* Set the dates for a jQuery selection. 7724 * @param target element - the target input field or division or span 7725 * @param date Date - the new date 7726 */ 7727 _setDateDatepicker: function( target, date ) { 7728 var inst = this._getInst( target ); 7729 if ( inst ) { 7730 this._setDate( inst, date ); 7731 this._updateDatepicker( inst ); 7732 this._updateAlternate( inst ); 7733 } 7734 }, 7735 7736 /* Get the date(s) for the first entry in a jQuery selection. 7737 * @param target element - the target input field or division or span 7738 * @param noDefault boolean - true if no default date is to be used 7739 * @return Date - the current date 7740 */ 7741 _getDateDatepicker: function( target, noDefault ) { 7742 var inst = this._getInst( target ); 7743 if ( inst && !inst.inline ) { 7744 this._setDateFromField( inst, noDefault ); 7745 } 7746 return ( inst ? this._getDate( inst ) : null ); 7747 }, 7748 7749 /* Handle keystrokes. */ 7750 _doKeyDown: function( event ) { 7751 var onSelect, dateStr, sel, 7752 inst = $.datepicker._getInst( event.target ), 7753 handled = true, 7754 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" ); 7755 7756 inst._keyEvent = true; 7757 if ( $.datepicker._datepickerShowing ) { 7758 switch ( event.keyCode ) { 7759 case 9: $.datepicker._hideDatepicker(); 7760 handled = false; 7761 break; // hide on tab out 7762 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." + 7763 $.datepicker._currentClass + ")", inst.dpDiv ); 7764 if ( sel[ 0 ] ) { 7765 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 7766 } 7767 7768 onSelect = $.datepicker._get( inst, "onSelect" ); 7769 if ( onSelect ) { 7770 dateStr = $.datepicker._formatDate( inst ); 7771 7772 // Trigger custom callback 7773 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); 7774 } else { 7775 $.datepicker._hideDatepicker(); 7776 } 7777 7778 return false; // don't submit the form 7779 case 27: $.datepicker._hideDatepicker(); 7780 break; // hide on escape 7781 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7782 -$.datepicker._get( inst, "stepBigMonths" ) : 7783 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7784 break; // previous month/year on page up/+ ctrl 7785 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7786 +$.datepicker._get( inst, "stepBigMonths" ) : 7787 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7788 break; // next month/year on page down/+ ctrl 7789 case 35: if ( event.ctrlKey || event.metaKey ) { 7790 $.datepicker._clearDate( event.target ); 7791 } 7792 handled = event.ctrlKey || event.metaKey; 7793 break; // clear on ctrl or command +end 7794 case 36: if ( event.ctrlKey || event.metaKey ) { 7795 $.datepicker._gotoToday( event.target ); 7796 } 7797 handled = event.ctrlKey || event.metaKey; 7798 break; // current on ctrl or command +home 7799 case 37: if ( event.ctrlKey || event.metaKey ) { 7800 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" ); 7801 } 7802 handled = event.ctrlKey || event.metaKey; 7803 7804 // -1 day on ctrl or command +left 7805 if ( event.originalEvent.altKey ) { 7806 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7807 -$.datepicker._get( inst, "stepBigMonths" ) : 7808 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7809 } 7810 7811 // next month/year on alt +left on Mac 7812 break; 7813 case 38: if ( event.ctrlKey || event.metaKey ) { 7814 $.datepicker._adjustDate( event.target, -7, "D" ); 7815 } 7816 handled = event.ctrlKey || event.metaKey; 7817 break; // -1 week on ctrl or command +up 7818 case 39: if ( event.ctrlKey || event.metaKey ) { 7819 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" ); 7820 } 7821 handled = event.ctrlKey || event.metaKey; 7822 7823 // +1 day on ctrl or command +right 7824 if ( event.originalEvent.altKey ) { 7825 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7826 +$.datepicker._get( inst, "stepBigMonths" ) : 7827 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7828 } 7829 7830 // next month/year on alt +right 7831 break; 7832 case 40: if ( event.ctrlKey || event.metaKey ) { 7833 $.datepicker._adjustDate( event.target, +7, "D" ); 7834 } 7835 handled = event.ctrlKey || event.metaKey; 7836 break; // +1 week on ctrl or command +down 7837 default: handled = false; 7838 } 7839 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home 7840 $.datepicker._showDatepicker( this ); 7841 } else { 7842 handled = false; 7843 } 7844 7845 if ( handled ) { 7846 event.preventDefault(); 7847 event.stopPropagation(); 7848 } 7849 }, 7850 7851 /* Filter entered characters - based on date format. */ 7852 _doKeyPress: function( event ) { 7853 var chars, chr, 7854 inst = $.datepicker._getInst( event.target ); 7855 7856 if ( $.datepicker._get( inst, "constrainInput" ) ) { 7857 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) ); 7858 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode ); 7859 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 ); 7860 } 7861 }, 7862 7863 /* Synchronise manual entry and field/alternate field. */ 7864 _doKeyUp: function( event ) { 7865 var date, 7866 inst = $.datepicker._getInst( event.target ); 7867 7868 if ( inst.input.val() !== inst.lastVal ) { 7869 try { 7870 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 7871 ( inst.input ? inst.input.val() : null ), 7872 $.datepicker._getFormatConfig( inst ) ); 7873 7874 if ( date ) { // only if valid 7875 $.datepicker._setDateFromField( inst ); 7876 $.datepicker._updateAlternate( inst ); 7877 $.datepicker._updateDatepicker( inst ); 7878 } 7879 } 7880 catch ( err ) { 7881 } 7882 } 7883 return true; 7884 }, 7885 7886 /* Pop-up the date picker for a given input field. 7887 * If false returned from beforeShow event handler do not show. 7888 * @param input element - the input field attached to the date picker or 7889 * event - if triggered by focus 7890 */ 7891 _showDatepicker: function( input ) { 7892 input = input.target || input; 7893 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger 7894 input = $( "input", input.parentNode )[ 0 ]; 7895 } 7896 7897 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here 7898 return; 7899 } 7900 7901 var inst, beforeShow, beforeShowSettings, isFixed, 7902 offset, showAnim, duration; 7903 7904 inst = $.datepicker._getInst( input ); 7905 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) { 7906 $.datepicker._curInst.dpDiv.stop( true, true ); 7907 if ( inst && $.datepicker._datepickerShowing ) { 7908 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] ); 7909 } 7910 } 7911 7912 beforeShow = $.datepicker._get( inst, "beforeShow" ); 7913 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 7914 if ( beforeShowSettings === false ) { 7915 return; 7916 } 7917 datepicker_extendRemove( inst.settings, beforeShowSettings ); 7918 7919 inst.lastVal = null; 7920 $.datepicker._lastInput = input; 7921 $.datepicker._setDateFromField( inst ); 7922 7923 if ( $.datepicker._inDialog ) { // hide cursor 7924 input.value = ""; 7925 } 7926 if ( !$.datepicker._pos ) { // position below input 7927 $.datepicker._pos = $.datepicker._findPos( input ); 7928 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height 7929 } 7930 7931 isFixed = false; 7932 $( input ).parents().each( function() { 7933 isFixed |= $( this ).css( "position" ) === "fixed"; 7934 return !isFixed; 7935 } ); 7936 7937 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] }; 7938 $.datepicker._pos = null; 7939 7940 //to avoid flashes on Firefox 7941 inst.dpDiv.empty(); 7942 7943 // determine sizing offscreen 7944 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } ); 7945 $.datepicker._updateDatepicker( inst ); 7946 7947 // fix width for dynamic number of date pickers 7948 // and adjust position before showing 7949 offset = $.datepicker._checkOffset( inst, offset, isFixed ); 7950 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ? 7951 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none", 7952 left: offset.left + "px", top: offset.top + "px" } ); 7953 7954 if ( !inst.inline ) { 7955 showAnim = $.datepicker._get( inst, "showAnim" ); 7956 duration = $.datepicker._get( inst, "duration" ); 7957 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 7958 $.datepicker._datepickerShowing = true; 7959 7960 if ( $.effects && $.effects.effect[ showAnim ] ) { 7961 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration ); 7962 } else { 7963 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null ); 7964 } 7965 7966 if ( $.datepicker._shouldFocusInput( inst ) ) { 7967 inst.input.trigger( "focus" ); 7968 } 7969 7970 $.datepicker._curInst = inst; 7971 } 7972 }, 7973 7974 /* Generate the date picker content. */ 7975 _updateDatepicker: function( inst ) { 7976 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 7977 datepicker_instActive = inst; // for delegate hover events 7978 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 7979 this._attachHandlers( inst ); 7980 7981 var origyearshtml, 7982 numMonths = this._getNumberOfMonths( inst ), 7983 cols = numMonths[ 1 ], 7984 width = 17, 7985 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); 7986 7987 if ( activeCell.length > 0 ) { 7988 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 7989 } 7990 7991 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" ); 7992 if ( cols > 1 ) { 7993 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" ); 7994 } 7995 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) + 7996 "Class" ]( "ui-datepicker-multi" ); 7997 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) + 7998 "Class" ]( "ui-datepicker-rtl" ); 7999 8000 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 8001 inst.input.trigger( "focus" ); 8002 } 8003 8004 // Deffered render of the years select (to avoid flashes on Firefox) 8005 if ( inst.yearshtml ) { 8006 origyearshtml = inst.yearshtml; 8007 setTimeout( function() { 8008 8009 //assure that inst.yearshtml didn't change. 8010 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) { 8011 inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml ); 8012 } 8013 origyearshtml = inst.yearshtml = null; 8014 }, 0 ); 8015 } 8016 }, 8017 8018 // #6694 - don't focus the input if it's already focused 8019 // this breaks the change event in IE 8020 // Support: IE and jQuery <1.9 8021 _shouldFocusInput: function( inst ) { 8022 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); 8023 }, 8024 8025 /* Check positioning to remain on screen. */ 8026 _checkOffset: function( inst, offset, isFixed ) { 8027 var dpWidth = inst.dpDiv.outerWidth(), 8028 dpHeight = inst.dpDiv.outerHeight(), 8029 inputWidth = inst.input ? inst.input.outerWidth() : 0, 8030 inputHeight = inst.input ? inst.input.outerHeight() : 0, 8031 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 8032 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 8033 8034 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 ); 8035 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0; 8036 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0; 8037 8038 // Now check if datepicker is showing outside window viewport - move to a better place if so. 8039 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ? 8040 Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 8041 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ? 8042 Math.abs( dpHeight + inputHeight ) : 0 ); 8043 8044 return offset; 8045 }, 8046 8047 /* Find an object's position on the screen. */ 8048 _findPos: function( obj ) { 8049 var position, 8050 inst = this._getInst( obj ), 8051 isRTL = this._get( inst, "isRTL" ); 8052 8053 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) { 8054 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ]; 8055 } 8056 8057 position = $( obj ).offset(); 8058 return [ position.left, position.top ]; 8059 }, 8060 8061 /* Hide the date picker from view. 8062 * @param input element - the input field attached to the date picker 8063 */ 8064 _hideDatepicker: function( input ) { 8065 var showAnim, duration, postProcess, onClose, 8066 inst = this._curInst; 8067 8068 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) { 8069 return; 8070 } 8071 8072 if ( this._datepickerShowing ) { 8073 showAnim = this._get( inst, "showAnim" ); 8074 duration = this._get( inst, "duration" ); 8075 postProcess = function() { 8076 $.datepicker._tidyDialog( inst ); 8077 }; 8078 8079 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 8080 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 8081 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess ); 8082 } else { 8083 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" : 8084 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess ); 8085 } 8086 8087 if ( !showAnim ) { 8088 postProcess(); 8089 } 8090 this._datepickerShowing = false; 8091 8092 onClose = this._get( inst, "onClose" ); 8093 if ( onClose ) { 8094 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] ); 8095 } 8096 8097 this._lastInput = null; 8098 if ( this._inDialog ) { 8099 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } ); 8100 if ( $.blockUI ) { 8101 $.unblockUI(); 8102 $( "body" ).append( this.dpDiv ); 8103 } 8104 } 8105 this._inDialog = false; 8106 } 8107 }, 8108 8109 /* Tidy up after a dialog display. */ 8110 _tidyDialog: function( inst ) { 8111 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" ); 8112 }, 8113 8114 /* Close date picker if clicked elsewhere. */ 8115 _checkExternalClick: function( event ) { 8116 if ( !$.datepicker._curInst ) { 8117 return; 8118 } 8119 8120 var $target = $( event.target ), 8121 inst = $.datepicker._getInst( $target[ 0 ] ); 8122 8123 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId && 8124 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 && 8125 !$target.hasClass( $.datepicker.markerClassName ) && 8126 !$target.closest( "." + $.datepicker._triggerClass ).length && 8127 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) || 8128 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) { 8129 $.datepicker._hideDatepicker(); 8130 } 8131 }, 8132 8133 /* Adjust one of the date sub-fields. */ 8134 _adjustDate: function( id, offset, period ) { 8135 var target = $( id ), 8136 inst = this._getInst( target[ 0 ] ); 8137 8138 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 8139 return; 8140 } 8141 this._adjustInstDate( inst, offset + 8142 ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning 8143 period ); 8144 this._updateDatepicker( inst ); 8145 }, 8146 8147 /* Action for current link. */ 8148 _gotoToday: function( id ) { 8149 var date, 8150 target = $( id ), 8151 inst = this._getInst( target[ 0 ] ); 8152 8153 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) { 8154 inst.selectedDay = inst.currentDay; 8155 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 8156 inst.drawYear = inst.selectedYear = inst.currentYear; 8157 } else { 8158 date = new Date(); 8159 inst.selectedDay = date.getDate(); 8160 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8161 inst.drawYear = inst.selectedYear = date.getFullYear(); 8162 } 8163 this._notifyChange( inst ); 8164 this._adjustDate( target ); 8165 }, 8166 8167 /* Action for selecting a new month/year. */ 8168 _selectMonthYear: function( id, select, period ) { 8169 var target = $( id ), 8170 inst = this._getInst( target[ 0 ] ); 8171 8172 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] = 8173 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] = 8174 parseInt( select.options[ select.selectedIndex ].value, 10 ); 8175 8176 this._notifyChange( inst ); 8177 this._adjustDate( target ); 8178 }, 8179 8180 /* Action for selecting a day. */ 8181 _selectDay: function( id, month, year, td ) { 8182 var inst, 8183 target = $( id ); 8184 8185 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 8186 return; 8187 } 8188 8189 inst = this._getInst( target[ 0 ] ); 8190 inst.selectedDay = inst.currentDay = $( "a", td ).html(); 8191 inst.selectedMonth = inst.currentMonth = month; 8192 inst.selectedYear = inst.currentYear = year; 8193 this._selectDate( id, this._formatDate( inst, 8194 inst.currentDay, inst.currentMonth, inst.currentYear ) ); 8195 }, 8196 8197 /* Erase the input field and hide the date picker. */ 8198 _clearDate: function( id ) { 8199 var target = $( id ); 8200 this._selectDate( target, "" ); 8201 }, 8202 8203 /* Update the input field with the selected date. */ 8204 _selectDate: function( id, dateStr ) { 8205 var onSelect, 8206 target = $( id ), 8207 inst = this._getInst( target[ 0 ] ); 8208 8209 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) ); 8210 if ( inst.input ) { 8211 inst.input.val( dateStr ); 8212 } 8213 this._updateAlternate( inst ); 8214 8215 onSelect = this._get( inst, "onSelect" ); 8216 if ( onSelect ) { 8217 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback 8218 } else if ( inst.input ) { 8219 inst.input.trigger( "change" ); // fire the change event 8220 } 8221 8222 if ( inst.inline ) { 8223 this._updateDatepicker( inst ); 8224 } else { 8225 this._hideDatepicker(); 8226 this._lastInput = inst.input[ 0 ]; 8227 if ( typeof( inst.input[ 0 ] ) !== "object" ) { 8228 inst.input.trigger( "focus" ); // restore focus 8229 } 8230 this._lastInput = null; 8231 } 8232 }, 8233 8234 /* Update any alternate field to synchronise with the main field. */ 8235 _updateAlternate: function( inst ) { 8236 var altFormat, date, dateStr, 8237 altField = this._get( inst, "altField" ); 8238 8239 if ( altField ) { // update alternate field too 8240 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" ); 8241 date = this._getDate( inst ); 8242 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 8243 $( altField ).val( dateStr ); 8244 } 8245 }, 8246 8247 /* Set as beforeShowDay function to prevent selection of weekends. 8248 * @param date Date - the date to customise 8249 * @return [boolean, string] - is this date selectable?, what is its CSS class? 8250 */ 8251 noWeekends: function( date ) { 8252 var day = date.getDay(); 8253 return [ ( day > 0 && day < 6 ), "" ]; 8254 }, 8255 8256 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 8257 * @param date Date - the date to get the week for 8258 * @return number - the number of the week within the year that contains this date 8259 */ 8260 iso8601Week: function( date ) { 8261 var time, 8262 checkDate = new Date( date.getTime() ); 8263 8264 // Find Thursday of this week starting on Monday 8265 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 8266 8267 time = checkDate.getTime(); 8268 checkDate.setMonth( 0 ); // Compare with Jan 1 8269 checkDate.setDate( 1 ); 8270 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 8271 }, 8272 8273 /* Parse a string value into a date object. 8274 * See formatDate below for the possible formats. 8275 * 8276 * @param format string - the expected format of the date 8277 * @param value string - the date in the above format 8278 * @param settings Object - attributes include: 8279 * shortYearCutoff number - the cutoff year for determining the century (optional) 8280 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8281 * dayNames string[7] - names of the days from Sunday (optional) 8282 * monthNamesShort string[12] - abbreviated names of the months (optional) 8283 * monthNames string[12] - names of the months (optional) 8284 * @return Date - the extracted date value or null if value is blank 8285 */ 8286 parseDate: function( format, value, settings ) { 8287 if ( format == null || value == null ) { 8288 throw "Invalid arguments"; 8289 } 8290 8291 value = ( typeof value === "object" ? value.toString() : value + "" ); 8292 if ( value === "" ) { 8293 return null; 8294 } 8295 8296 var iFormat, dim, extra, 8297 iValue = 0, 8298 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff, 8299 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 8300 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ), 8301 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8302 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8303 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8304 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8305 year = -1, 8306 month = -1, 8307 day = -1, 8308 doy = -1, 8309 literal = false, 8310 date, 8311 8312 // Check whether a format character is doubled 8313 lookAhead = function( match ) { 8314 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8315 if ( matches ) { 8316 iFormat++; 8317 } 8318 return matches; 8319 }, 8320 8321 // Extract a number from the string value 8322 getNumber = function( match ) { 8323 var isDoubled = lookAhead( match ), 8324 size = ( match === "@" ? 14 : ( match === "!" ? 20 : 8325 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ), 8326 minSize = ( match === "y" ? size : 1 ), 8327 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ), 8328 num = value.substring( iValue ).match( digits ); 8329 if ( !num ) { 8330 throw "Missing number at position " + iValue; 8331 } 8332 iValue += num[ 0 ].length; 8333 return parseInt( num[ 0 ], 10 ); 8334 }, 8335 8336 // Extract a name from the string value and convert to an index 8337 getName = function( match, shortNames, longNames ) { 8338 var index = -1, 8339 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 8340 return [ [ k, v ] ]; 8341 } ).sort( function( a, b ) { 8342 return -( a[ 1 ].length - b[ 1 ].length ); 8343 } ); 8344 8345 $.each( names, function( i, pair ) { 8346 var name = pair[ 1 ]; 8347 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) { 8348 index = pair[ 0 ]; 8349 iValue += name.length; 8350 return false; 8351 } 8352 } ); 8353 if ( index !== -1 ) { 8354 return index + 1; 8355 } else { 8356 throw "Unknown name at position " + iValue; 8357 } 8358 }, 8359 8360 // Confirm that a literal character matches the string value 8361 checkLiteral = function() { 8362 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 8363 throw "Unexpected literal at position " + iValue; 8364 } 8365 iValue++; 8366 }; 8367 8368 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8369 if ( literal ) { 8370 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8371 literal = false; 8372 } else { 8373 checkLiteral(); 8374 } 8375 } else { 8376 switch ( format.charAt( iFormat ) ) { 8377 case "d": 8378 day = getNumber( "d" ); 8379 break; 8380 case "D": 8381 getName( "D", dayNamesShort, dayNames ); 8382 break; 8383 case "o": 8384 doy = getNumber( "o" ); 8385 break; 8386 case "m": 8387 month = getNumber( "m" ); 8388 break; 8389 case "M": 8390 month = getName( "M", monthNamesShort, monthNames ); 8391 break; 8392 case "y": 8393 year = getNumber( "y" ); 8394 break; 8395 case "@": 8396 date = new Date( getNumber( "@" ) ); 8397 year = date.getFullYear(); 8398 month = date.getMonth() + 1; 8399 day = date.getDate(); 8400 break; 8401 case "!": 8402 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 ); 8403 year = date.getFullYear(); 8404 month = date.getMonth() + 1; 8405 day = date.getDate(); 8406 break; 8407 case "'": 8408 if ( lookAhead( "'" ) ) { 8409 checkLiteral(); 8410 } else { 8411 literal = true; 8412 } 8413 break; 8414 default: 8415 checkLiteral(); 8416 } 8417 } 8418 } 8419 8420 if ( iValue < value.length ) { 8421 extra = value.substr( iValue ); 8422 if ( !/^\s+/.test( extra ) ) { 8423 throw "Extra/unparsed characters found in date: " + extra; 8424 } 8425 } 8426 8427 if ( year === -1 ) { 8428 year = new Date().getFullYear(); 8429 } else if ( year < 100 ) { 8430 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 8431 ( year <= shortYearCutoff ? 0 : -100 ); 8432 } 8433 8434 if ( doy > -1 ) { 8435 month = 1; 8436 day = doy; 8437 do { 8438 dim = this._getDaysInMonth( year, month - 1 ); 8439 if ( day <= dim ) { 8440 break; 8441 } 8442 month++; 8443 day -= dim; 8444 } while ( true ); 8445 } 8446 8447 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 8448 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 8449 throw "Invalid date"; // E.g. 31/02/00 8450 } 8451 return date; 8452 }, 8453 8454 /* Standard date formats. */ 8455 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 8456 COOKIE: "D, dd M yy", 8457 ISO_8601: "yy-mm-dd", 8458 RFC_822: "D, d M y", 8459 RFC_850: "DD, dd-M-y", 8460 RFC_1036: "D, d M y", 8461 RFC_1123: "D, d M yy", 8462 RFC_2822: "D, d M yy", 8463 RSS: "D, d M y", // RFC 822 8464 TICKS: "!", 8465 TIMESTAMP: "@", 8466 W3C: "yy-mm-dd", // ISO 8601 8467 8468 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + 8469 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ), 8470 8471 /* Format a date object into a string value. 8472 * The format can be combinations of the following: 8473 * d - day of month (no leading zero) 8474 * dd - day of month (two digit) 8475 * o - day of year (no leading zeros) 8476 * oo - day of year (three digit) 8477 * D - day name short 8478 * DD - day name long 8479 * m - month of year (no leading zero) 8480 * mm - month of year (two digit) 8481 * M - month name short 8482 * MM - month name long 8483 * y - year (two digit) 8484 * yy - year (four digit) 8485 * @ - Unix timestamp (ms since 01/01/1970) 8486 * ! - Windows ticks (100ns since 01/01/0001) 8487 * "..." - literal text 8488 * '' - single quote 8489 * 8490 * @param format string - the desired format of the date 8491 * @param date Date - the date value to format 8492 * @param settings Object - attributes include: 8493 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8494 * dayNames string[7] - names of the days from Sunday (optional) 8495 * monthNamesShort string[12] - abbreviated names of the months (optional) 8496 * monthNames string[12] - names of the months (optional) 8497 * @return string - the date in the above format 8498 */ 8499 formatDate: function( format, date, settings ) { 8500 if ( !date ) { 8501 return ""; 8502 } 8503 8504 var iFormat, 8505 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8506 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8507 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8508 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8509 8510 // Check whether a format character is doubled 8511 lookAhead = function( match ) { 8512 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8513 if ( matches ) { 8514 iFormat++; 8515 } 8516 return matches; 8517 }, 8518 8519 // Format a number, with leading zero if necessary 8520 formatNumber = function( match, value, len ) { 8521 var num = "" + value; 8522 if ( lookAhead( match ) ) { 8523 while ( num.length < len ) { 8524 num = "0" + num; 8525 } 8526 } 8527 return num; 8528 }, 8529 8530 // Format a name, short or long as requested 8531 formatName = function( match, value, shortNames, longNames ) { 8532 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] ); 8533 }, 8534 output = "", 8535 literal = false; 8536 8537 if ( date ) { 8538 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8539 if ( literal ) { 8540 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8541 literal = false; 8542 } else { 8543 output += format.charAt( iFormat ); 8544 } 8545 } else { 8546 switch ( format.charAt( iFormat ) ) { 8547 case "d": 8548 output += formatNumber( "d", date.getDate(), 2 ); 8549 break; 8550 case "D": 8551 output += formatName( "D", date.getDay(), dayNamesShort, dayNames ); 8552 break; 8553 case "o": 8554 output += formatNumber( "o", 8555 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 8556 break; 8557 case "m": 8558 output += formatNumber( "m", date.getMonth() + 1, 2 ); 8559 break; 8560 case "M": 8561 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames ); 8562 break; 8563 case "y": 8564 output += ( lookAhead( "y" ) ? date.getFullYear() : 8565 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 ); 8566 break; 8567 case "@": 8568 output += date.getTime(); 8569 break; 8570 case "!": 8571 output += date.getTime() * 10000 + this._ticksTo1970; 8572 break; 8573 case "'": 8574 if ( lookAhead( "'" ) ) { 8575 output += "'"; 8576 } else { 8577 literal = true; 8578 } 8579 break; 8580 default: 8581 output += format.charAt( iFormat ); 8582 } 8583 } 8584 } 8585 } 8586 return output; 8587 }, 8588 8589 /* Extract all possible characters from the date format. */ 8590 _possibleChars: function( format ) { 8591 var iFormat, 8592 chars = "", 8593 literal = false, 8594 8595 // Check whether a format character is doubled 8596 lookAhead = function( match ) { 8597 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8598 if ( matches ) { 8599 iFormat++; 8600 } 8601 return matches; 8602 }; 8603 8604 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8605 if ( literal ) { 8606 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8607 literal = false; 8608 } else { 8609 chars += format.charAt( iFormat ); 8610 } 8611 } else { 8612 switch ( format.charAt( iFormat ) ) { 8613 case "d": case "m": case "y": case "@": 8614 chars += "0123456789"; 8615 break; 8616 case "D": case "M": 8617 return null; // Accept anything 8618 case "'": 8619 if ( lookAhead( "'" ) ) { 8620 chars += "'"; 8621 } else { 8622 literal = true; 8623 } 8624 break; 8625 default: 8626 chars += format.charAt( iFormat ); 8627 } 8628 } 8629 } 8630 return chars; 8631 }, 8632 8633 /* Get a setting value, defaulting if necessary. */ 8634 _get: function( inst, name ) { 8635 return inst.settings[ name ] !== undefined ? 8636 inst.settings[ name ] : this._defaults[ name ]; 8637 }, 8638 8639 /* Parse existing date and initialise date picker. */ 8640 _setDateFromField: function( inst, noDefault ) { 8641 if ( inst.input.val() === inst.lastVal ) { 8642 return; 8643 } 8644 8645 var dateFormat = this._get( inst, "dateFormat" ), 8646 dates = inst.lastVal = inst.input ? inst.input.val() : null, 8647 defaultDate = this._getDefaultDate( inst ), 8648 date = defaultDate, 8649 settings = this._getFormatConfig( inst ); 8650 8651 try { 8652 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 8653 } catch ( event ) { 8654 dates = ( noDefault ? "" : dates ); 8655 } 8656 inst.selectedDay = date.getDate(); 8657 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8658 inst.drawYear = inst.selectedYear = date.getFullYear(); 8659 inst.currentDay = ( dates ? date.getDate() : 0 ); 8660 inst.currentMonth = ( dates ? date.getMonth() : 0 ); 8661 inst.currentYear = ( dates ? date.getFullYear() : 0 ); 8662 this._adjustInstDate( inst ); 8663 }, 8664 8665 /* Retrieve the default date shown on opening. */ 8666 _getDefaultDate: function( inst ) { 8667 return this._restrictMinMax( inst, 8668 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) ); 8669 }, 8670 8671 /* A date may be specified as an exact value or a relative one. */ 8672 _determineDate: function( inst, date, defaultDate ) { 8673 var offsetNumeric = function( offset ) { 8674 var date = new Date(); 8675 date.setDate( date.getDate() + offset ); 8676 return date; 8677 }, 8678 offsetString = function( offset ) { 8679 try { 8680 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 8681 offset, $.datepicker._getFormatConfig( inst ) ); 8682 } 8683 catch ( e ) { 8684 8685 // Ignore 8686 } 8687 8688 var date = ( offset.toLowerCase().match( /^c/ ) ? 8689 $.datepicker._getDate( inst ) : null ) || new Date(), 8690 year = date.getFullYear(), 8691 month = date.getMonth(), 8692 day = date.getDate(), 8693 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 8694 matches = pattern.exec( offset ); 8695 8696 while ( matches ) { 8697 switch ( matches[ 2 ] || "d" ) { 8698 case "d" : case "D" : 8699 day += parseInt( matches[ 1 ], 10 ); break; 8700 case "w" : case "W" : 8701 day += parseInt( matches[ 1 ], 10 ) * 7; break; 8702 case "m" : case "M" : 8703 month += parseInt( matches[ 1 ], 10 ); 8704 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8705 break; 8706 case "y": case "Y" : 8707 year += parseInt( matches[ 1 ], 10 ); 8708 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8709 break; 8710 } 8711 matches = pattern.exec( offset ); 8712 } 8713 return new Date( year, month, day ); 8714 }, 8715 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) : 8716 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) ); 8717 8718 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate ); 8719 if ( newDate ) { 8720 newDate.setHours( 0 ); 8721 newDate.setMinutes( 0 ); 8722 newDate.setSeconds( 0 ); 8723 newDate.setMilliseconds( 0 ); 8724 } 8725 return this._daylightSavingAdjust( newDate ); 8726 }, 8727 8728 /* Handle switch to/from daylight saving. 8729 * Hours may be non-zero on daylight saving cut-over: 8730 * > 12 when midnight changeover, but then cannot generate 8731 * midnight datetime, so jump to 1AM, otherwise reset. 8732 * @param date (Date) the date to check 8733 * @return (Date) the corrected date 8734 */ 8735 _daylightSavingAdjust: function( date ) { 8736 if ( !date ) { 8737 return null; 8738 } 8739 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 8740 return date; 8741 }, 8742 8743 /* Set the date(s) directly. */ 8744 _setDate: function( inst, date, noChange ) { 8745 var clear = !date, 8746 origMonth = inst.selectedMonth, 8747 origYear = inst.selectedYear, 8748 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 8749 8750 inst.selectedDay = inst.currentDay = newDate.getDate(); 8751 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 8752 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 8753 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) { 8754 this._notifyChange( inst ); 8755 } 8756 this._adjustInstDate( inst ); 8757 if ( inst.input ) { 8758 inst.input.val( clear ? "" : this._formatDate( inst ) ); 8759 } 8760 }, 8761 8762 /* Retrieve the date(s) directly. */ 8763 _getDate: function( inst ) { 8764 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null : 8765 this._daylightSavingAdjust( new Date( 8766 inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 8767 return startDate; 8768 }, 8769 8770 /* Attach the onxxx handlers. These are declared statically so 8771 * they work with static code transformers like Caja. 8772 */ 8773 _attachHandlers: function( inst ) { 8774 var stepMonths = this._get( inst, "stepMonths" ), 8775 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 8776 inst.dpDiv.find( "[data-handler]" ).map( function() { 8777 var handler = { 8778 prev: function() { 8779 $.datepicker._adjustDate( id, -stepMonths, "M" ); 8780 }, 8781 next: function() { 8782 $.datepicker._adjustDate( id, +stepMonths, "M" ); 8783 }, 8784 hide: function() { 8785 $.datepicker._hideDatepicker(); 8786 }, 8787 today: function() { 8788 $.datepicker._gotoToday( id ); 8789 }, 8790 selectDay: function() { 8791 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this ); 8792 return false; 8793 }, 8794 selectMonth: function() { 8795 $.datepicker._selectMonthYear( id, this, "M" ); 8796 return false; 8797 }, 8798 selectYear: function() { 8799 $.datepicker._selectMonthYear( id, this, "Y" ); 8800 return false; 8801 } 8802 }; 8803 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] ); 8804 } ); 8805 }, 8806 8807 /* Generate the HTML for the current state of the date picker. */ 8808 _generateHTML: function( inst ) { 8809 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 8810 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 8811 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 8812 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 8813 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 8814 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 8815 tempDate = new Date(), 8816 today = this._daylightSavingAdjust( 8817 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 8818 isRTL = this._get( inst, "isRTL" ), 8819 showButtonPanel = this._get( inst, "showButtonPanel" ), 8820 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ), 8821 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ), 8822 numMonths = this._getNumberOfMonths( inst ), 8823 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ), 8824 stepMonths = this._get( inst, "stepMonths" ), 8825 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ), 8826 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) : 8827 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ), 8828 minDate = this._getMinMaxDate( inst, "min" ), 8829 maxDate = this._getMinMaxDate( inst, "max" ), 8830 drawMonth = inst.drawMonth - showCurrentAtPos, 8831 drawYear = inst.drawYear; 8832 8833 if ( drawMonth < 0 ) { 8834 drawMonth += 12; 8835 drawYear--; 8836 } 8837 if ( maxDate ) { 8838 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), 8839 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 8840 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw ); 8841 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 8842 drawMonth--; 8843 if ( drawMonth < 0 ) { 8844 drawMonth = 11; 8845 drawYear--; 8846 } 8847 } 8848 } 8849 inst.drawMonth = drawMonth; 8850 inst.drawYear = drawYear; 8851 8852 prevText = this._get( inst, "prevText" ); 8853 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText, 8854 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), 8855 this._getFormatConfig( inst ) ) ); 8856 8857 prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ? 8858 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + 8859 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" : 8860 ( 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>" ) ); 8861 8862 nextText = this._get( inst, "nextText" ); 8863 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText, 8864 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), 8865 this._getFormatConfig( inst ) ) ); 8866 8867 next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ? 8868 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + 8869 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" : 8870 ( 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>" ) ); 8871 8872 currentText = this._get( inst, "currentText" ); 8873 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today ); 8874 currentText = ( !navigationAsDateFormat ? currentText : 8875 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) ); 8876 8877 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'>" + 8878 this._get( inst, "closeText" ) + "</button>" : "" ); 8879 8880 buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) + 8881 ( 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'" + 8882 ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : ""; 8883 8884 firstDay = parseInt( this._get( inst, "firstDay" ), 10 ); 8885 firstDay = ( isNaN( firstDay ) ? 0 : firstDay ); 8886 8887 showWeek = this._get( inst, "showWeek" ); 8888 dayNames = this._get( inst, "dayNames" ); 8889 dayNamesMin = this._get( inst, "dayNamesMin" ); 8890 monthNames = this._get( inst, "monthNames" ); 8891 monthNamesShort = this._get( inst, "monthNamesShort" ); 8892 beforeShowDay = this._get( inst, "beforeShowDay" ); 8893 showOtherMonths = this._get( inst, "showOtherMonths" ); 8894 selectOtherMonths = this._get( inst, "selectOtherMonths" ); 8895 defaultDate = this._getDefaultDate( inst ); 8896 html = ""; 8897 8898 for ( row = 0; row < numMonths[ 0 ]; row++ ) { 8899 group = ""; 8900 this.maxRows = 4; 8901 for ( col = 0; col < numMonths[ 1 ]; col++ ) { 8902 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 8903 cornerClass = " ui-corner-all"; 8904 calender = ""; 8905 if ( isMultiMonth ) { 8906 calender += "<div class='ui-datepicker-group"; 8907 if ( numMonths[ 1 ] > 1 ) { 8908 switch ( col ) { 8909 case 0: calender += " ui-datepicker-group-first"; 8910 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break; 8911 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last"; 8912 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break; 8913 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 8914 } 8915 } 8916 calender += "'>"; 8917 } 8918 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 8919 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) + 8920 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) + 8921 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate, 8922 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers 8923 "</div><table class='ui-datepicker-calendar'><thead>" + 8924 "<tr>"; 8925 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" ); 8926 for ( dow = 0; dow < 7; dow++ ) { // days of the week 8927 day = ( dow + firstDay ) % 7; 8928 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" + 8929 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>"; 8930 } 8931 calender += thead + "</tr></thead><tbody>"; 8932 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 8933 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 8934 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 8935 } 8936 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 8937 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate 8938 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043) 8939 this.maxRows = numRows; 8940 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 8941 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows 8942 calender += "<tr>"; 8943 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 8944 this._get( inst, "calculateWeek" )( printDate ) + "</td>" ); 8945 for ( dow = 0; dow < 7; dow++ ) { // create date picker days 8946 daySettings = ( beforeShowDay ? 8947 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] ); 8948 otherMonth = ( printDate.getMonth() !== drawMonth ); 8949 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] || 8950 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 8951 tbody += "<td class='" + 8952 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends 8953 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months 8954 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key 8955 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? 8956 8957 // or defaultDate is current printedDate and defaultDate is selectedDate 8958 " " + this._dayOverClass : "" ) + // highlight selected day 8959 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days 8960 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates 8961 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day 8962 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different) 8963 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title 8964 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions 8965 ( otherMonth && !showOtherMonths ? " " : // display for other months 8966 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 8967 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) + 8968 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day 8969 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months 8970 "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date 8971 printDate.setDate( printDate.getDate() + 1 ); 8972 printDate = this._daylightSavingAdjust( printDate ); 8973 } 8974 calender += tbody + "</tr>"; 8975 } 8976 drawMonth++; 8977 if ( drawMonth > 11 ) { 8978 drawMonth = 0; 8979 drawYear++; 8980 } 8981 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" + 8982 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" ); 8983 group += calender; 8984 } 8985 html += group; 8986 } 8987 html += buttonPanel; 8988 inst._keyEvent = false; 8989 return html; 8990 }, 8991 8992 /* Generate the month and year header. */ 8993 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, 8994 secondary, monthNames, monthNamesShort ) { 8995 8996 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 8997 changeMonth = this._get( inst, "changeMonth" ), 8998 changeYear = this._get( inst, "changeYear" ), 8999 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ), 9000 html = "<div class='ui-datepicker-title'>", 9001 monthHtml = ""; 9002 9003 // Month selection 9004 if ( secondary || !changeMonth ) { 9005 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>"; 9006 } else { 9007 inMinYear = ( minDate && minDate.getFullYear() === drawYear ); 9008 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear ); 9009 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; 9010 for ( month = 0; month < 12; month++ ) { 9011 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) { 9012 monthHtml += "<option value='" + month + "'" + 9013 ( month === drawMonth ? " selected='selected'" : "" ) + 9014 ">" + monthNamesShort[ month ] + "</option>"; 9015 } 9016 } 9017 monthHtml += "</select>"; 9018 } 9019 9020 if ( !showMonthAfterYear ) { 9021 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" ); 9022 } 9023 9024 // Year selection 9025 if ( !inst.yearshtml ) { 9026 inst.yearshtml = ""; 9027 if ( secondary || !changeYear ) { 9028 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 9029 } else { 9030 9031 // determine range of years to display 9032 years = this._get( inst, "yearRange" ).split( ":" ); 9033 thisYear = new Date().getFullYear(); 9034 determineYear = function( value ) { 9035 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : 9036 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) : 9037 parseInt( value, 10 ) ) ); 9038 return ( isNaN( year ) ? thisYear : year ); 9039 }; 9040 year = determineYear( years[ 0 ] ); 9041 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) ); 9042 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year ); 9043 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear ); 9044 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; 9045 for ( ; year <= endYear; year++ ) { 9046 inst.yearshtml += "<option value='" + year + "'" + 9047 ( year === drawYear ? " selected='selected'" : "" ) + 9048 ">" + year + "</option>"; 9049 } 9050 inst.yearshtml += "</select>"; 9051 9052 html += inst.yearshtml; 9053 inst.yearshtml = null; 9054 } 9055 } 9056 9057 html += this._get( inst, "yearSuffix" ); 9058 if ( showMonthAfterYear ) { 9059 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml; 9060 } 9061 html += "</div>"; // Close datepicker_header 9062 return html; 9063 }, 9064 9065 /* Adjust one of the date sub-fields. */ 9066 _adjustInstDate: function( inst, offset, period ) { 9067 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ), 9068 month = inst.selectedMonth + ( period === "M" ? offset : 0 ), 9069 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ), 9070 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 9071 9072 inst.selectedDay = date.getDate(); 9073 inst.drawMonth = inst.selectedMonth = date.getMonth(); 9074 inst.drawYear = inst.selectedYear = date.getFullYear(); 9075 if ( period === "M" || period === "Y" ) { 9076 this._notifyChange( inst ); 9077 } 9078 }, 9079 9080 /* Ensure a date is within any min/max bounds. */ 9081 _restrictMinMax: function( inst, date ) { 9082 var minDate = this._getMinMaxDate( inst, "min" ), 9083 maxDate = this._getMinMaxDate( inst, "max" ), 9084 newDate = ( minDate && date < minDate ? minDate : date ); 9085 return ( maxDate && newDate > maxDate ? maxDate : newDate ); 9086 }, 9087 9088 /* Notify change of month/year. */ 9089 _notifyChange: function( inst ) { 9090 var onChange = this._get( inst, "onChangeMonthYear" ); 9091 if ( onChange ) { 9092 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ), 9093 [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 9094 } 9095 }, 9096 9097 /* Determine the number of months to show. */ 9098 _getNumberOfMonths: function( inst ) { 9099 var numMonths = this._get( inst, "numberOfMonths" ); 9100 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) ); 9101 }, 9102 9103 /* Determine the current maximum date - ensure no time components are set. */ 9104 _getMinMaxDate: function( inst, minMax ) { 9105 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null ); 9106 }, 9107 9108 /* Find the number of days in a given month. */ 9109 _getDaysInMonth: function( year, month ) { 9110 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 9111 }, 9112 9113 /* Find the day of the week of the first of a month. */ 9114 _getFirstDayOfMonth: function( year, month ) { 9115 return new Date( year, month, 1 ).getDay(); 9116 }, 9117 9118 /* Determines if we should allow a "next/prev" month display change. */ 9119 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 9120 var numMonths = this._getNumberOfMonths( inst ), 9121 date = this._daylightSavingAdjust( new Date( curYear, 9122 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 9123 9124 if ( offset < 0 ) { 9125 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 9126 } 9127 return this._isInRange( inst, date ); 9128 }, 9129 9130 /* Is the given date in the accepted range? */ 9131 _isInRange: function( inst, date ) { 9132 var yearSplit, currentYear, 9133 minDate = this._getMinMaxDate( inst, "min" ), 9134 maxDate = this._getMinMaxDate( inst, "max" ), 9135 minYear = null, 9136 maxYear = null, 9137 years = this._get( inst, "yearRange" ); 9138 if ( years ) { 9139 yearSplit = years.split( ":" ); 9140 currentYear = new Date().getFullYear(); 9141 minYear = parseInt( yearSplit[ 0 ], 10 ); 9142 maxYear = parseInt( yearSplit[ 1 ], 10 ); 9143 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) { 9144 minYear += currentYear; 9145 } 9146 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) { 9147 maxYear += currentYear; 9148 } 9149 } 9150 9151 return ( ( !minDate || date.getTime() >= minDate.getTime() ) && 9152 ( !maxDate || date.getTime() <= maxDate.getTime() ) && 9153 ( !minYear || date.getFullYear() >= minYear ) && 9154 ( !maxYear || date.getFullYear() <= maxYear ) ); 9155 }, 9156 9157 /* Provide the configuration settings for formatting/parsing. */ 9158 _getFormatConfig: function( inst ) { 9159 var shortYearCutoff = this._get( inst, "shortYearCutoff" ); 9160 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff : 9161 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) ); 9162 return { shortYearCutoff: shortYearCutoff, 9163 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ), 9164 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) }; 9165 }, 9166 9167 /* Format the given date for display. */ 9168 _formatDate: function( inst, day, month, year ) { 9169 if ( !day ) { 9170 inst.currentDay = inst.selectedDay; 9171 inst.currentMonth = inst.selectedMonth; 9172 inst.currentYear = inst.selectedYear; 9173 } 9174 var date = ( day ? ( typeof day === "object" ? day : 9175 this._daylightSavingAdjust( new Date( year, month, day ) ) ) : 9176 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 9177 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) ); 9178 } 9179 } ); 9180 9181 /* 9182 * Bind hover events for datepicker elements. 9183 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 9184 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 9185 */ 9186 function datepicker_bindHover( dpDiv ) { 9187 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 9188 return dpDiv.on( "mouseout", selector, function() { 9189 $( this ).removeClass( "ui-state-hover" ); 9190 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9191 $( this ).removeClass( "ui-datepicker-prev-hover" ); 9192 } 9193 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9194 $( this ).removeClass( "ui-datepicker-next-hover" ); 9195 } 9196 } ) 9197 .on( "mouseover", selector, datepicker_handleMouseover ); 9198 } 9199 9200 function datepicker_handleMouseover() { 9201 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 9202 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" ); 9203 $( this ).addClass( "ui-state-hover" ); 9204 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9205 $( this ).addClass( "ui-datepicker-prev-hover" ); 9206 } 9207 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9208 $( this ).addClass( "ui-datepicker-next-hover" ); 9209 } 9210 } 9211 } 9212 9213 /* jQuery extend now ignores nulls! */ 9214 function datepicker_extendRemove( target, props ) { 9215 $.extend( target, props ); 9216 for ( var name in props ) { 9217 if ( props[ name ] == null ) { 9218 target[ name ] = props[ name ]; 9219 } 9220 } 9221 return target; 9222 } 9223 9224 /* Invoke the datepicker functionality. 9225 @param options string - a command, optionally followed by additional parameters or 9226 Object - settings for attaching new datepicker functionality 9227 @return jQuery object */ 9228 $.fn.datepicker = function( options ) { 9229 9230 /* Verify an empty collection wasn't passed - Fixes #6976 */ 9231 if ( !this.length ) { 9232 return this; 9233 } 9234 9235 /* Initialise the date picker. */ 9236 if ( !$.datepicker.initialized ) { 9237 $( document ).on( "mousedown", $.datepicker._checkExternalClick ); 9238 $.datepicker.initialized = true; 9239 } 9240 9241 /* Append datepicker main container to body if not exist. */ 9242 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) { 9243 $( "body" ).append( $.datepicker.dpDiv ); 9244 } 9245 9246 var otherArgs = Array.prototype.slice.call( arguments, 1 ); 9247 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) { 9248 return $.datepicker[ "_" + options + "Datepicker" ]. 9249 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9250 } 9251 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) { 9252 return $.datepicker[ "_" + options + "Datepicker" ]. 9253 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9254 } 9255 return this.each( function() { 9256 typeof options === "string" ? 9257 $.datepicker[ "_" + options + "Datepicker" ]. 9258 apply( $.datepicker, [ this ].concat( otherArgs ) ) : 9259 $.datepicker._attachDatepicker( this, options ); 9260 } ); 9261 }; 9262 9263 $.datepicker = new Datepicker(); // singleton instance 9264 $.datepicker.initialized = false; 9265 $.datepicker.uuid = new Date().getTime(); 9266 $.datepicker.version = "1.12.1"; 9267 9268 var widgetsDatepicker = $.datepicker; 9269 9270 9271 9272 9273 // This file is deprecated 9274 var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); 9275 9276 /*! 9277 * jQuery UI Mouse 1.12.1 9278 * http://jqueryui.com 9279 * 9280 * Copyright jQuery Foundation and other contributors 9281 * Released under the MIT license. 9282 * http://jquery.org/license 9283 */ 9284 9285 //>>label: Mouse 9286 //>>group: Widgets 9287 //>>description: Abstracts mouse-based interactions to assist in creating certain widgets. 9288 //>>docs: http://api.jqueryui.com/mouse/ 9289 9290 9291 9292 var mouseHandled = false; 9293 $( document ).on( "mouseup", function() { 9294 mouseHandled = false; 9295 } ); 9296 9297 var widgetsMouse = $.widget( "ui.mouse", { 9298 version: "1.12.1", 9299 options: { 9300 cancel: "input, textarea, button, select, option", 9301 distance: 1, 9302 delay: 0 9303 }, 9304 _mouseInit: function() { 9305 var that = this; 9306 9307 this.element 9308 .on( "mousedown." + this.widgetName, function( event ) { 9309 return that._mouseDown( event ); 9310 } ) 9311 .on( "click." + this.widgetName, function( event ) { 9312 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { 9313 $.removeData( event.target, that.widgetName + ".preventClickEvent" ); 9314 event.stopImmediatePropagation(); 9315 return false; 9316 } 9317 } ); 9318 9319 this.started = false; 9320 }, 9321 9322 // TODO: make sure destroying one instance of mouse doesn't mess with 9323 // other instances of mouse 9324 _mouseDestroy: function() { 9325 this.element.off( "." + this.widgetName ); 9326 if ( this._mouseMoveDelegate ) { 9327 this.document 9328 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9329 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9330 } 9331 }, 9332 9333 _mouseDown: function( event ) { 9334 9335 // don't let more than one widget handle mouseStart 9336 if ( mouseHandled ) { 9337 return; 9338 } 9339 9340 this._mouseMoved = false; 9341 9342 // We may have missed mouseup (out of window) 9343 ( this._mouseStarted && this._mouseUp( event ) ); 9344 9345 this._mouseDownEvent = event; 9346 9347 var that = this, 9348 btnIsLeft = ( event.which === 1 ), 9349 9350 // event.target.nodeName works around a bug in IE 8 with 9351 // disabled inputs (#7620) 9352 elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ? 9353 $( event.target ).closest( this.options.cancel ).length : false ); 9354 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { 9355 return true; 9356 } 9357 9358 this.mouseDelayMet = !this.options.delay; 9359 if ( !this.mouseDelayMet ) { 9360 this._mouseDelayTimer = setTimeout( function() { 9361 that.mouseDelayMet = true; 9362 }, this.options.delay ); 9363 } 9364 9365 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9366 this._mouseStarted = ( this._mouseStart( event ) !== false ); 9367 if ( !this._mouseStarted ) { 9368 event.preventDefault(); 9369 return true; 9370 } 9371 } 9372 9373 // Click event may never have fired (Gecko & Opera) 9374 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { 9375 $.removeData( event.target, this.widgetName + ".preventClickEvent" ); 9376 } 9377 9378 // These delegates are required to keep context 9379 this._mouseMoveDelegate = function( event ) { 9380 return that._mouseMove( event ); 9381 }; 9382 this._mouseUpDelegate = function( event ) { 9383 return that._mouseUp( event ); 9384 }; 9385 9386 this.document 9387 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9388 .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9389 9390 event.preventDefault(); 9391 9392 mouseHandled = true; 9393 return true; 9394 }, 9395 9396 _mouseMove: function( event ) { 9397 9398 // Only check for mouseups outside the document if you've moved inside the document 9399 // at least once. This prevents the firing of mouseup in the case of IE<9, which will 9400 // fire a mousemove event if content is placed under the cursor. See #7778 9401 // Support: IE <9 9402 if ( this._mouseMoved ) { 9403 9404 // IE mouseup check - mouseup happened when mouse was out of window 9405 if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && 9406 !event.button ) { 9407 return this._mouseUp( event ); 9408 9409 // Iframe mouseup check - mouseup occurred in another document 9410 } else if ( !event.which ) { 9411 9412 // Support: Safari <=8 - 9 9413 // Safari sets which to 0 if you press any of the following keys 9414 // during a drag (#14461) 9415 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || 9416 event.originalEvent.metaKey || event.originalEvent.shiftKey ) { 9417 this.ignoreMissingWhich = true; 9418 } else if ( !this.ignoreMissingWhich ) { 9419 return this._mouseUp( event ); 9420 } 9421 } 9422 } 9423 9424 if ( event.which || event.button ) { 9425 this._mouseMoved = true; 9426 } 9427 9428 if ( this._mouseStarted ) { 9429 this._mouseDrag( event ); 9430 return event.preventDefault(); 9431 } 9432 9433 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9434 this._mouseStarted = 9435 ( this._mouseStart( this._mouseDownEvent, event ) !== false ); 9436 ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) ); 9437 } 9438 9439 return !this._mouseStarted; 9440 }, 9441 9442 _mouseUp: function( event ) { 9443 this.document 9444 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9445 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9446 9447 if ( this._mouseStarted ) { 9448 this._mouseStarted = false; 9449 9450 if ( event.target === this._mouseDownEvent.target ) { 9451 $.data( event.target, this.widgetName + ".preventClickEvent", true ); 9452 } 9453 9454 this._mouseStop( event ); 9455 } 9456 9457 if ( this._mouseDelayTimer ) { 9458 clearTimeout( this._mouseDelayTimer ); 9459 delete this._mouseDelayTimer; 9460 } 9461 9462 this.ignoreMissingWhich = false; 9463 mouseHandled = false; 9464 event.preventDefault(); 9465 }, 9466 9467 _mouseDistanceMet: function( event ) { 9468 return ( Math.max( 9469 Math.abs( this._mouseDownEvent.pageX - event.pageX ), 9470 Math.abs( this._mouseDownEvent.pageY - event.pageY ) 9471 ) >= this.options.distance 9472 ); 9473 }, 9474 9475 _mouseDelayMet: function( /* event */ ) { 9476 return this.mouseDelayMet; 9477 }, 9478 9479 // These are placeholder methods, to be overriden by extending plugin 9480 _mouseStart: function( /* event */ ) {}, 9481 _mouseDrag: function( /* event */ ) {}, 9482 _mouseStop: function( /* event */ ) {}, 9483 _mouseCapture: function( /* event */ ) { return true; } 9484 } ); 9485 9486 9487 9488 9489 // $.ui.plugin is deprecated. Use $.widget() extensions instead. 9490 var plugin = $.ui.plugin = { 9491 add: function( module, option, set ) { 9492 var i, 9493 proto = $.ui[ module ].prototype; 9494 for ( i in set ) { 9495 proto.plugins[ i ] = proto.plugins[ i ] || []; 9496 proto.plugins[ i ].push( [ option, set[ i ] ] ); 9497 } 9498 }, 9499 call: function( instance, name, args, allowDisconnected ) { 9500 var i, 9501 set = instance.plugins[ name ]; 9502 9503 if ( !set ) { 9504 return; 9505 } 9506 9507 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || 9508 instance.element[ 0 ].parentNode.nodeType === 11 ) ) { 9509 return; 9510 } 9511 9512 for ( i = 0; i < set.length; i++ ) { 9513 if ( instance.options[ set[ i ][ 0 ] ] ) { 9514 set[ i ][ 1 ].apply( instance.element, args ); 9515 } 9516 } 9517 } 9518 }; 9519 9520 9521 9522 var safeBlur = $.ui.safeBlur = function( element ) { 9523 9524 // Support: IE9 - 10 only 9525 // If the <body> is blurred, IE will switch windows, see #9420 9526 if ( element && element.nodeName.toLowerCase() !== "body" ) { 9527 $( element ).trigger( "blur" ); 9528 } 9529 }; 9530 9531 9532 /*! 9533 * jQuery UI Draggable 1.12.1 9534 * http://jqueryui.com 9535 * 9536 * Copyright jQuery Foundation and other contributors 9537 * Released under the MIT license. 9538 * http://jquery.org/license 9539 */ 9540 9541 //>>label: Draggable 9542 //>>group: Interactions 9543 //>>description: Enables dragging functionality for any element. 9544 //>>docs: http://api.jqueryui.com/draggable/ 9545 //>>demos: http://jqueryui.com/draggable/ 9546 //>>css.structure: ../../themes/base/draggable.css 9547 9548 9549 9550 $.widget( "ui.draggable", $.ui.mouse, { 9551 version: "1.12.1", 9552 widgetEventPrefix: "drag", 9553 options: { 9554 addClasses: true, 9555 appendTo: "parent", 9556 axis: false, 9557 connectToSortable: false, 9558 containment: false, 9559 cursor: "auto", 9560 cursorAt: false, 9561 grid: false, 9562 handle: false, 9563 helper: "original", 9564 iframeFix: false, 9565 opacity: false, 9566 refreshPositions: false, 9567 revert: false, 9568 revertDuration: 500, 9569 scope: "default", 9570 scroll: true, 9571 scrollSensitivity: 20, 9572 scrollSpeed: 20, 9573 snap: false, 9574 snapMode: "both", 9575 snapTolerance: 20, 9576 stack: false, 9577 zIndex: false, 9578 9579 // Callbacks 9580 drag: null, 9581 start: null, 9582 stop: null 9583 }, 9584 _create: function() { 9585 9586 if ( this.options.helper === "original" ) { 9587 this._setPositionRelative(); 9588 } 9589 if ( this.options.addClasses ) { 9590 this._addClass( "ui-draggable" ); 9591 } 9592 this._setHandleClassName(); 9593 9594 this._mouseInit(); 9595 }, 9596 9597 _setOption: function( key, value ) { 9598 this._super( key, value ); 9599 if ( key === "handle" ) { 9600 this._removeHandleClassName(); 9601 this._setHandleClassName(); 9602 } 9603 }, 9604 9605 _destroy: function() { 9606 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { 9607 this.destroyOnClear = true; 9608 return; 9609 } 9610 this._removeHandleClassName(); 9611 this._mouseDestroy(); 9612 }, 9613 9614 _mouseCapture: function( event ) { 9615 var o = this.options; 9616 9617 // Among others, prevent a drag on a resizable-handle 9618 if ( this.helper || o.disabled || 9619 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) { 9620 return false; 9621 } 9622 9623 //Quit if we're not on a valid handle 9624 this.handle = this._getHandle( event ); 9625 if ( !this.handle ) { 9626 return false; 9627 } 9628 9629 this._blurActiveElement( event ); 9630 9631 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); 9632 9633 return true; 9634 9635 }, 9636 9637 _blockFrames: function( selector ) { 9638 this.iframeBlocks = this.document.find( selector ).map( function() { 9639 var iframe = $( this ); 9640 9641 return $( "<div>" ) 9642 .css( "position", "absolute" ) 9643 .appendTo( iframe.parent() ) 9644 .outerWidth( iframe.outerWidth() ) 9645 .outerHeight( iframe.outerHeight() ) 9646 .offset( iframe.offset() )[ 0 ]; 9647 } ); 9648 }, 9649 9650 _unblockFrames: function() { 9651 if ( this.iframeBlocks ) { 9652 this.iframeBlocks.remove(); 9653 delete this.iframeBlocks; 9654 } 9655 }, 9656 9657 _blurActiveElement: function( event ) { 9658 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ), 9659 target = $( event.target ); 9660 9661 // Don't blur if the event occurred on an element that is within 9662 // the currently focused element 9663 // See #10527, #12472 9664 if ( target.closest( activeElement ).length ) { 9665 return; 9666 } 9667 9668 // Blur any element that currently has focus, see #4261 9669 $.ui.safeBlur( activeElement ); 9670 }, 9671 9672 _mouseStart: function( event ) { 9673 9674 var o = this.options; 9675 9676 //Create and append the visible helper 9677 this.helper = this._createHelper( event ); 9678 9679 this._addClass( this.helper, "ui-draggable-dragging" ); 9680 9681 //Cache the helper size 9682 this._cacheHelperProportions(); 9683 9684 //If ddmanager is used for droppables, set the global draggable 9685 if ( $.ui.ddmanager ) { 9686 $.ui.ddmanager.current = this; 9687 } 9688 9689 /* 9690 * - Position generation - 9691 * This block generates everything position related - it's the core of draggables. 9692 */ 9693 9694 //Cache the margins of the original element 9695 this._cacheMargins(); 9696 9697 //Store the helper's css position 9698 this.cssPosition = this.helper.css( "position" ); 9699 this.scrollParent = this.helper.scrollParent( true ); 9700 this.offsetParent = this.helper.offsetParent(); 9701 this.hasFixedAncestor = this.helper.parents().filter( function() { 9702 return $( this ).css( "position" ) === "fixed"; 9703 } ).length > 0; 9704 9705 //The element's absolute position on the page minus margins 9706 this.positionAbs = this.element.offset(); 9707 this._refreshOffsets( event ); 9708 9709 //Generate the original position 9710 this.originalPosition = this.position = this._generatePosition( event, false ); 9711 this.originalPageX = event.pageX; 9712 this.originalPageY = event.pageY; 9713 9714 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 9715 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) ); 9716 9717 //Set a containment if given in the options 9718 this._setContainment(); 9719 9720 //Trigger event + callbacks 9721 if ( this._trigger( "start", event ) === false ) { 9722 this._clear(); 9723 return false; 9724 } 9725 9726 //Recache the helper size 9727 this._cacheHelperProportions(); 9728 9729 //Prepare the droppable offsets 9730 if ( $.ui.ddmanager && !o.dropBehaviour ) { 9731 $.ui.ddmanager.prepareOffsets( this, event ); 9732 } 9733 9734 // Execute the drag once - this causes the helper not to be visible before getting its 9735 // correct position 9736 this._mouseDrag( event, true ); 9737 9738 // If the ddmanager is used for droppables, inform the manager that dragging has started 9739 // (see #5003) 9740 if ( $.ui.ddmanager ) { 9741 $.ui.ddmanager.dragStart( this, event ); 9742 } 9743 9744 return true; 9745 }, 9746 9747 _refreshOffsets: function( event ) { 9748 this.offset = { 9749 top: this.positionAbs.top - this.margins.top, 9750 left: this.positionAbs.left - this.margins.left, 9751 scroll: false, 9752 parent: this._getParentOffset(), 9753 relative: this._getRelativeOffset() 9754 }; 9755 9756 this.offset.click = { 9757 left: event.pageX - this.offset.left, 9758 top: event.pageY - this.offset.top 9759 }; 9760 }, 9761 9762 _mouseDrag: function( event, noPropagation ) { 9763 9764 // reset any necessary cached properties (see #5009) 9765 if ( this.hasFixedAncestor ) { 9766 this.offset.parent = this._getParentOffset(); 9767 } 9768 9769 //Compute the helpers position 9770 this.position = this._generatePosition( event, true ); 9771 this.positionAbs = this._convertPositionTo( "absolute" ); 9772 9773 //Call plugins and callbacks and use the resulting position if something is returned 9774 if ( !noPropagation ) { 9775 var ui = this._uiHash(); 9776 if ( this._trigger( "drag", event, ui ) === false ) { 9777 this._mouseUp( new $.Event( "mouseup", event ) ); 9778 return false; 9779 } 9780 this.position = ui.position; 9781 } 9782 9783 this.helper[ 0 ].style.left = this.position.left + "px"; 9784 this.helper[ 0 ].style.top = this.position.top + "px"; 9785 9786 if ( $.ui.ddmanager ) { 9787 $.ui.ddmanager.drag( this, event ); 9788 } 9789 9790 return false; 9791 }, 9792 9793 _mouseStop: function( event ) { 9794 9795 //If we are using droppables, inform the manager about the drop 9796 var that = this, 9797 dropped = false; 9798 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 9799 dropped = $.ui.ddmanager.drop( this, event ); 9800 } 9801 9802 //if a drop comes from outside (a sortable) 9803 if ( this.dropped ) { 9804 dropped = this.dropped; 9805 this.dropped = false; 9806 } 9807 9808 if ( ( this.options.revert === "invalid" && !dropped ) || 9809 ( this.options.revert === "valid" && dropped ) || 9810 this.options.revert === true || ( $.isFunction( this.options.revert ) && 9811 this.options.revert.call( this.element, dropped ) ) 9812 ) { 9813 $( this.helper ).animate( 9814 this.originalPosition, 9815 parseInt( this.options.revertDuration, 10 ), 9816 function() { 9817 if ( that._trigger( "stop", event ) !== false ) { 9818 that._clear(); 9819 } 9820 } 9821 ); 9822 } else { 9823 if ( this._trigger( "stop", event ) !== false ) { 9824 this._clear(); 9825 } 9826 } 9827 9828 return false; 9829 }, 9830 9831 _mouseUp: function( event ) { 9832 this._unblockFrames(); 9833 9834 // If the ddmanager is used for droppables, inform the manager that dragging has stopped 9835 // (see #5003) 9836 if ( $.ui.ddmanager ) { 9837 $.ui.ddmanager.dragStop( this, event ); 9838 } 9839 9840 // Only need to focus if the event occurred on the draggable itself, see #10527 9841 if ( this.handleElement.is( event.target ) ) { 9842 9843 // The interaction is over; whether or not the click resulted in a drag, 9844 // focus the element 9845 this.element.trigger( "focus" ); 9846 } 9847 9848 return $.ui.mouse.prototype._mouseUp.call( this, event ); 9849 }, 9850 9851 cancel: function() { 9852 9853 if ( this.helper.is( ".ui-draggable-dragging" ) ) { 9854 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) ); 9855 } else { 9856 this._clear(); 9857 } 9858 9859 return this; 9860 9861 }, 9862 9863 _getHandle: function( event ) { 9864 return this.options.handle ? 9865 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : 9866 true; 9867 }, 9868 9869 _setHandleClassName: function() { 9870 this.handleElement = this.options.handle ? 9871 this.element.find( this.options.handle ) : this.element; 9872 this._addClass( this.handleElement, "ui-draggable-handle" ); 9873 }, 9874 9875 _removeHandleClassName: function() { 9876 this._removeClass( this.handleElement, "ui-draggable-handle" ); 9877 }, 9878 9879 _createHelper: function( event ) { 9880 9881 var o = this.options, 9882 helperIsFunction = $.isFunction( o.helper ), 9883 helper = helperIsFunction ? 9884 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : 9885 ( o.helper === "clone" ? 9886 this.element.clone().removeAttr( "id" ) : 9887 this.element ); 9888 9889 if ( !helper.parents( "body" ).length ) { 9890 helper.appendTo( ( o.appendTo === "parent" ? 9891 this.element[ 0 ].parentNode : 9892 o.appendTo ) ); 9893 } 9894 9895 // Http://bugs.jqueryui.com/ticket/9446 9896 // a helper function can return the original element 9897 // which wouldn't have been set to relative in _create 9898 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { 9899 this._setPositionRelative(); 9900 } 9901 9902 if ( helper[ 0 ] !== this.element[ 0 ] && 9903 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) { 9904 helper.css( "position", "absolute" ); 9905 } 9906 9907 return helper; 9908 9909 }, 9910 9911 _setPositionRelative: function() { 9912 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { 9913 this.element[ 0 ].style.position = "relative"; 9914 } 9915 }, 9916 9917 _adjustOffsetFromHelper: function( obj ) { 9918 if ( typeof obj === "string" ) { 9919 obj = obj.split( " " ); 9920 } 9921 if ( $.isArray( obj ) ) { 9922 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 9923 } 9924 if ( "left" in obj ) { 9925 this.offset.click.left = obj.left + this.margins.left; 9926 } 9927 if ( "right" in obj ) { 9928 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 9929 } 9930 if ( "top" in obj ) { 9931 this.offset.click.top = obj.top + this.margins.top; 9932 } 9933 if ( "bottom" in obj ) { 9934 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 9935 } 9936 }, 9937 9938 _isRootNode: function( element ) { 9939 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; 9940 }, 9941 9942 _getParentOffset: function() { 9943 9944 //Get the offsetParent and cache its position 9945 var po = this.offsetParent.offset(), 9946 document = this.document[ 0 ]; 9947 9948 // This is a special case where we need to modify a offset calculated on start, since the 9949 // following happened: 9950 // 1. The position of the helper is absolute, so it's position is calculated based on the 9951 // next positioned parent 9952 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 9953 // the document, which means that the scroll is included in the initial calculation of the 9954 // offset of the parent, and never recalculated upon drag 9955 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document && 9956 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 9957 po.left += this.scrollParent.scrollLeft(); 9958 po.top += this.scrollParent.scrollTop(); 9959 } 9960 9961 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { 9962 po = { top: 0, left: 0 }; 9963 } 9964 9965 return { 9966 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 9967 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 9968 }; 9969 9970 }, 9971 9972 _getRelativeOffset: function() { 9973 if ( this.cssPosition !== "relative" ) { 9974 return { top: 0, left: 0 }; 9975 } 9976 9977 var p = this.element.position(), 9978 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 9979 9980 return { 9981 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 9982 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), 9983 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 9984 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) 9985 }; 9986 9987 }, 9988 9989 _cacheMargins: function() { 9990 this.margins = { 9991 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ), 9992 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ), 9993 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ), 9994 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 ) 9995 }; 9996 }, 9997 9998 _cacheHelperProportions: function() { 9999 this.helperProportions = { 10000 width: this.helper.outerWidth(), 10001 height: this.helper.outerHeight() 10002 }; 10003 }, 10004 10005 _setContainment: function() { 10006 10007 var isUserScrollable, c, ce, 10008 o = this.options, 10009 document = this.document[ 0 ]; 10010 10011 this.relativeContainer = null; 10012 10013 if ( !o.containment ) { 10014 this.containment = null; 10015 return; 10016 } 10017 10018 if ( o.containment === "window" ) { 10019 this.containment = [ 10020 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 10021 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, 10022 $( window ).scrollLeft() + $( window ).width() - 10023 this.helperProportions.width - this.margins.left, 10024 $( window ).scrollTop() + 10025 ( $( window ).height() || document.body.parentNode.scrollHeight ) - 10026 this.helperProportions.height - this.margins.top 10027 ]; 10028 return; 10029 } 10030 10031 if ( o.containment === "document" ) { 10032 this.containment = [ 10033 0, 10034 0, 10035 $( document ).width() - this.helperProportions.width - this.margins.left, 10036 ( $( document ).height() || document.body.parentNode.scrollHeight ) - 10037 this.helperProportions.height - this.margins.top 10038 ]; 10039 return; 10040 } 10041 10042 if ( o.containment.constructor === Array ) { 10043 this.containment = o.containment; 10044 return; 10045 } 10046 10047 if ( o.containment === "parent" ) { 10048 o.containment = this.helper[ 0 ].parentNode; 10049 } 10050 10051 c = $( o.containment ); 10052 ce = c[ 0 ]; 10053 10054 if ( !ce ) { 10055 return; 10056 } 10057 10058 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); 10059 10060 this.containment = [ 10061 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + 10062 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), 10063 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + 10064 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), 10065 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 10066 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - 10067 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - 10068 this.helperProportions.width - 10069 this.margins.left - 10070 this.margins.right, 10071 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 10072 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - 10073 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - 10074 this.helperProportions.height - 10075 this.margins.top - 10076 this.margins.bottom 10077 ]; 10078 this.relativeContainer = c; 10079 }, 10080 10081 _convertPositionTo: function( d, pos ) { 10082 10083 if ( !pos ) { 10084 pos = this.position; 10085 } 10086 10087 var mod = d === "absolute" ? 1 : -1, 10088 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 10089 10090 return { 10091 top: ( 10092 10093 // The absolute mouse position 10094 pos.top + 10095 10096 // Only for relative positioned nodes: Relative offset from element to offset parent 10097 this.offset.relative.top * mod + 10098 10099 // The offsetParent's offset without borders (offset + border) 10100 this.offset.parent.top * mod - 10101 ( ( this.cssPosition === "fixed" ? 10102 -this.offset.scroll.top : 10103 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod ) 10104 ), 10105 left: ( 10106 10107 // The absolute mouse position 10108 pos.left + 10109 10110 // Only for relative positioned nodes: Relative offset from element to offset parent 10111 this.offset.relative.left * mod + 10112 10113 // The offsetParent's offset without borders (offset + border) 10114 this.offset.parent.left * mod - 10115 ( ( this.cssPosition === "fixed" ? 10116 -this.offset.scroll.left : 10117 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod ) 10118 ) 10119 }; 10120 10121 }, 10122 10123 _generatePosition: function( event, constrainPosition ) { 10124 10125 var containment, co, top, left, 10126 o = this.options, 10127 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), 10128 pageX = event.pageX, 10129 pageY = event.pageY; 10130 10131 // Cache the scroll 10132 if ( !scrollIsRootNode || !this.offset.scroll ) { 10133 this.offset.scroll = { 10134 top: this.scrollParent.scrollTop(), 10135 left: this.scrollParent.scrollLeft() 10136 }; 10137 } 10138 10139 /* 10140 * - Position constraining - 10141 * Constrain the position to a mix of grid, containment. 10142 */ 10143 10144 // If we are not dragging yet, we won't check for options 10145 if ( constrainPosition ) { 10146 if ( this.containment ) { 10147 if ( this.relativeContainer ) { 10148 co = this.relativeContainer.offset(); 10149 containment = [ 10150 this.containment[ 0 ] + co.left, 10151 this.containment[ 1 ] + co.top, 10152 this.containment[ 2 ] + co.left, 10153 this.containment[ 3 ] + co.top 10154 ]; 10155 } else { 10156 containment = this.containment; 10157 } 10158 10159 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) { 10160 pageX = containment[ 0 ] + this.offset.click.left; 10161 } 10162 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) { 10163 pageY = containment[ 1 ] + this.offset.click.top; 10164 } 10165 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) { 10166 pageX = containment[ 2 ] + this.offset.click.left; 10167 } 10168 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) { 10169 pageY = containment[ 3 ] + this.offset.click.top; 10170 } 10171 } 10172 10173 if ( o.grid ) { 10174 10175 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid 10176 // argument errors in IE (see ticket #6950) 10177 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY - 10178 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY; 10179 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] || 10180 top - this.offset.click.top > containment[ 3 ] ) ? 10181 top : 10182 ( ( top - this.offset.click.top >= containment[ 1 ] ) ? 10183 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top; 10184 10185 left = o.grid[ 0 ] ? this.originalPageX + 10186 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] : 10187 this.originalPageX; 10188 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] || 10189 left - this.offset.click.left > containment[ 2 ] ) ? 10190 left : 10191 ( ( left - this.offset.click.left >= containment[ 0 ] ) ? 10192 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left; 10193 } 10194 10195 if ( o.axis === "y" ) { 10196 pageX = this.originalPageX; 10197 } 10198 10199 if ( o.axis === "x" ) { 10200 pageY = this.originalPageY; 10201 } 10202 } 10203 10204 return { 10205 top: ( 10206 10207 // The absolute mouse position 10208 pageY - 10209 10210 // Click offset (relative to the element) 10211 this.offset.click.top - 10212 10213 // Only for relative positioned nodes: Relative offset from element to offset parent 10214 this.offset.relative.top - 10215 10216 // The offsetParent's offset without borders (offset + border) 10217 this.offset.parent.top + 10218 ( this.cssPosition === "fixed" ? 10219 -this.offset.scroll.top : 10220 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) 10221 ), 10222 left: ( 10223 10224 // The absolute mouse position 10225 pageX - 10226 10227 // Click offset (relative to the element) 10228 this.offset.click.left - 10229 10230 // Only for relative positioned nodes: Relative offset from element to offset parent 10231 this.offset.relative.left - 10232 10233 // The offsetParent's offset without borders (offset + border) 10234 this.offset.parent.left + 10235 ( this.cssPosition === "fixed" ? 10236 -this.offset.scroll.left : 10237 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) 10238 ) 10239 }; 10240 10241 }, 10242 10243 _clear: function() { 10244 this._removeClass( this.helper, "ui-draggable-dragging" ); 10245 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) { 10246 this.helper.remove(); 10247 } 10248 this.helper = null; 10249 this.cancelHelperRemoval = false; 10250 if ( this.destroyOnClear ) { 10251 this.destroy(); 10252 } 10253 }, 10254 10255 // From now on bulk stuff - mainly helpers 10256 10257 _trigger: function( type, event, ui ) { 10258 ui = ui || this._uiHash(); 10259 $.ui.plugin.call( this, type, [ event, ui, this ], true ); 10260 10261 // Absolute position and offset (see #6884 ) have to be recalculated after plugins 10262 if ( /^(drag|start|stop)/.test( type ) ) { 10263 this.positionAbs = this._convertPositionTo( "absolute" ); 10264 ui.offset = this.positionAbs; 10265 } 10266 return $.Widget.prototype._trigger.call( this, type, event, ui ); 10267 }, 10268 10269 plugins: {}, 10270 10271 _uiHash: function() { 10272 return { 10273 helper: this.helper, 10274 position: this.position, 10275 originalPosition: this.originalPosition, 10276 offset: this.positionAbs 10277 }; 10278 } 10279 10280 } ); 10281 10282 $.ui.plugin.add( "draggable", "connectToSortable", { 10283 start: function( event, ui, draggable ) { 10284 var uiSortable = $.extend( {}, ui, { 10285 item: draggable.element 10286 } ); 10287 10288 draggable.sortables = []; 10289 $( draggable.options.connectToSortable ).each( function() { 10290 var sortable = $( this ).sortable( "instance" ); 10291 10292 if ( sortable && !sortable.options.disabled ) { 10293 draggable.sortables.push( sortable ); 10294 10295 // RefreshPositions is called at drag start to refresh the containerCache 10296 // which is used in drag. This ensures it's initialized and synchronized 10297 // with any changes that might have happened on the page since initialization. 10298 sortable.refreshPositions(); 10299 sortable._trigger( "activate", event, uiSortable ); 10300 } 10301 } ); 10302 }, 10303 stop: function( event, ui, draggable ) { 10304 var uiSortable = $.extend( {}, ui, { 10305 item: draggable.element 10306 } ); 10307 10308 draggable.cancelHelperRemoval = false; 10309 10310 $.each( draggable.sortables, function() { 10311 var sortable = this; 10312 10313 if ( sortable.isOver ) { 10314 sortable.isOver = 0; 10315 10316 // Allow this sortable to handle removing the helper 10317 draggable.cancelHelperRemoval = true; 10318 sortable.cancelHelperRemoval = false; 10319 10320 // Use _storedCSS To restore properties in the sortable, 10321 // as this also handles revert (#9675) since the draggable 10322 // may have modified them in unexpected ways (#8809) 10323 sortable._storedCSS = { 10324 position: sortable.placeholder.css( "position" ), 10325 top: sortable.placeholder.css( "top" ), 10326 left: sortable.placeholder.css( "left" ) 10327 }; 10328 10329 sortable._mouseStop( event ); 10330 10331 // Once drag has ended, the sortable should return to using 10332 // its original helper, not the shared helper from draggable 10333 sortable.options.helper = sortable.options._helper; 10334 } else { 10335 10336 // Prevent this Sortable from removing the helper. 10337 // However, don't set the draggable to remove the helper 10338 // either as another connected Sortable may yet handle the removal. 10339 sortable.cancelHelperRemoval = true; 10340 10341 sortable._trigger( "deactivate", event, uiSortable ); 10342 } 10343 } ); 10344 }, 10345 drag: function( event, ui, draggable ) { 10346 $.each( draggable.sortables, function() { 10347 var innermostIntersecting = false, 10348 sortable = this; 10349 10350 // Copy over variables that sortable's _intersectsWith uses 10351 sortable.positionAbs = draggable.positionAbs; 10352 sortable.helperProportions = draggable.helperProportions; 10353 sortable.offset.click = draggable.offset.click; 10354 10355 if ( sortable._intersectsWith( sortable.containerCache ) ) { 10356 innermostIntersecting = true; 10357 10358 $.each( draggable.sortables, function() { 10359 10360 // Copy over variables that sortable's _intersectsWith uses 10361 this.positionAbs = draggable.positionAbs; 10362 this.helperProportions = draggable.helperProportions; 10363 this.offset.click = draggable.offset.click; 10364 10365 if ( this !== sortable && 10366 this._intersectsWith( this.containerCache ) && 10367 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { 10368 innermostIntersecting = false; 10369 } 10370 10371 return innermostIntersecting; 10372 } ); 10373 } 10374 10375 if ( innermostIntersecting ) { 10376 10377 // If it intersects, we use a little isOver variable and set it once, 10378 // so that the move-in stuff gets fired only once. 10379 if ( !sortable.isOver ) { 10380 sortable.isOver = 1; 10381 10382 // Store draggable's parent in case we need to reappend to it later. 10383 draggable._parent = ui.helper.parent(); 10384 10385 sortable.currentItem = ui.helper 10386 .appendTo( sortable.element ) 10387 .data( "ui-sortable-item", true ); 10388 10389 // Store helper option to later restore it 10390 sortable.options._helper = sortable.options.helper; 10391 10392 sortable.options.helper = function() { 10393 return ui.helper[ 0 ]; 10394 }; 10395 10396 // Fire the start events of the sortable with our passed browser event, 10397 // and our own helper (so it doesn't create a new one) 10398 event.target = sortable.currentItem[ 0 ]; 10399 sortable._mouseCapture( event, true ); 10400 sortable._mouseStart( event, true, true ); 10401 10402 // Because the browser event is way off the new appended portlet, 10403 // modify necessary variables to reflect the changes 10404 sortable.offset.click.top = draggable.offset.click.top; 10405 sortable.offset.click.left = draggable.offset.click.left; 10406 sortable.offset.parent.left -= draggable.offset.parent.left - 10407 sortable.offset.parent.left; 10408 sortable.offset.parent.top -= draggable.offset.parent.top - 10409 sortable.offset.parent.top; 10410 10411 draggable._trigger( "toSortable", event ); 10412 10413 // Inform draggable that the helper is in a valid drop zone, 10414 // used solely in the revert option to handle "valid/invalid". 10415 draggable.dropped = sortable.element; 10416 10417 // Need to refreshPositions of all sortables in the case that 10418 // adding to one sortable changes the location of the other sortables (#9675) 10419 $.each( draggable.sortables, function() { 10420 this.refreshPositions(); 10421 } ); 10422 10423 // Hack so receive/update callbacks work (mostly) 10424 draggable.currentItem = draggable.element; 10425 sortable.fromOutside = draggable; 10426 } 10427 10428 if ( sortable.currentItem ) { 10429 sortable._mouseDrag( event ); 10430 10431 // Copy the sortable's position because the draggable's can potentially reflect 10432 // a relative position, while sortable is always absolute, which the dragged 10433 // element has now become. (#8809) 10434 ui.position = sortable.position; 10435 } 10436 } else { 10437 10438 // If it doesn't intersect with the sortable, and it intersected before, 10439 // we fake the drag stop of the sortable, but make sure it doesn't remove 10440 // the helper by using cancelHelperRemoval. 10441 if ( sortable.isOver ) { 10442 10443 sortable.isOver = 0; 10444 sortable.cancelHelperRemoval = true; 10445 10446 // Calling sortable's mouseStop would trigger a revert, 10447 // so revert must be temporarily false until after mouseStop is called. 10448 sortable.options._revert = sortable.options.revert; 10449 sortable.options.revert = false; 10450 10451 sortable._trigger( "out", event, sortable._uiHash( sortable ) ); 10452 sortable._mouseStop( event, true ); 10453 10454 // Restore sortable behaviors that were modfied 10455 // when the draggable entered the sortable area (#9481) 10456 sortable.options.revert = sortable.options._revert; 10457 sortable.options.helper = sortable.options._helper; 10458 10459 if ( sortable.placeholder ) { 10460 sortable.placeholder.remove(); 10461 } 10462 10463 // Restore and recalculate the draggable's offset considering the sortable 10464 // may have modified them in unexpected ways. (#8809, #10669) 10465 ui.helper.appendTo( draggable._parent ); 10466 draggable._refreshOffsets( event ); 10467 ui.position = draggable._generatePosition( event, true ); 10468 10469 draggable._trigger( "fromSortable", event ); 10470 10471 // Inform draggable that the helper is no longer in a valid drop zone 10472 draggable.dropped = false; 10473 10474 // Need to refreshPositions of all sortables just in case removing 10475 // from one sortable changes the location of other sortables (#9675) 10476 $.each( draggable.sortables, function() { 10477 this.refreshPositions(); 10478 } ); 10479 } 10480 } 10481 } ); 10482 } 10483 } ); 10484 10485 $.ui.plugin.add( "draggable", "cursor", { 10486 start: function( event, ui, instance ) { 10487 var t = $( "body" ), 10488 o = instance.options; 10489 10490 if ( t.css( "cursor" ) ) { 10491 o._cursor = t.css( "cursor" ); 10492 } 10493 t.css( "cursor", o.cursor ); 10494 }, 10495 stop: function( event, ui, instance ) { 10496 var o = instance.options; 10497 if ( o._cursor ) { 10498 $( "body" ).css( "cursor", o._cursor ); 10499 } 10500 } 10501 } ); 10502 10503 $.ui.plugin.add( "draggable", "opacity", { 10504 start: function( event, ui, instance ) { 10505 var t = $( ui.helper ), 10506 o = instance.options; 10507 if ( t.css( "opacity" ) ) { 10508 o._opacity = t.css( "opacity" ); 10509 } 10510 t.css( "opacity", o.opacity ); 10511 }, 10512 stop: function( event, ui, instance ) { 10513 var o = instance.options; 10514 if ( o._opacity ) { 10515 $( ui.helper ).css( "opacity", o._opacity ); 10516 } 10517 } 10518 } ); 10519 10520 $.ui.plugin.add( "draggable", "scroll", { 10521 start: function( event, ui, i ) { 10522 if ( !i.scrollParentNotHidden ) { 10523 i.scrollParentNotHidden = i.helper.scrollParent( false ); 10524 } 10525 10526 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && 10527 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { 10528 i.overflowOffset = i.scrollParentNotHidden.offset(); 10529 } 10530 }, 10531 drag: function( event, ui, i ) { 10532 10533 var o = i.options, 10534 scrolled = false, 10535 scrollParent = i.scrollParentNotHidden[ 0 ], 10536 document = i.document[ 0 ]; 10537 10538 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { 10539 if ( !o.axis || o.axis !== "x" ) { 10540 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < 10541 o.scrollSensitivity ) { 10542 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; 10543 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { 10544 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; 10545 } 10546 } 10547 10548 if ( !o.axis || o.axis !== "y" ) { 10549 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < 10550 o.scrollSensitivity ) { 10551 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; 10552 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { 10553 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; 10554 } 10555 } 10556 10557 } else { 10558 10559 if ( !o.axis || o.axis !== "x" ) { 10560 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) { 10561 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed ); 10562 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) < 10563 o.scrollSensitivity ) { 10564 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed ); 10565 } 10566 } 10567 10568 if ( !o.axis || o.axis !== "y" ) { 10569 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) { 10570 scrolled = $( document ).scrollLeft( 10571 $( document ).scrollLeft() - o.scrollSpeed 10572 ); 10573 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) < 10574 o.scrollSensitivity ) { 10575 scrolled = $( document ).scrollLeft( 10576 $( document ).scrollLeft() + o.scrollSpeed 10577 ); 10578 } 10579 } 10580 10581 } 10582 10583 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 10584 $.ui.ddmanager.prepareOffsets( i, event ); 10585 } 10586 10587 } 10588 } ); 10589 10590 $.ui.plugin.add( "draggable", "snap", { 10591 start: function( event, ui, i ) { 10592 10593 var o = i.options; 10594 10595 i.snapElements = []; 10596 10597 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap ) 10598 .each( function() { 10599 var $t = $( this ), 10600 $o = $t.offset(); 10601 if ( this !== i.element[ 0 ] ) { 10602 i.snapElements.push( { 10603 item: this, 10604 width: $t.outerWidth(), height: $t.outerHeight(), 10605 top: $o.top, left: $o.left 10606 } ); 10607 } 10608 } ); 10609 10610 }, 10611 drag: function( event, ui, inst ) { 10612 10613 var ts, bs, ls, rs, l, r, t, b, i, first, 10614 o = inst.options, 10615 d = o.snapTolerance, 10616 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 10617 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 10618 10619 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) { 10620 10621 l = inst.snapElements[ i ].left - inst.margins.left; 10622 r = l + inst.snapElements[ i ].width; 10623 t = inst.snapElements[ i ].top - inst.margins.top; 10624 b = t + inst.snapElements[ i ].height; 10625 10626 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || 10627 !$.contains( inst.snapElements[ i ].item.ownerDocument, 10628 inst.snapElements[ i ].item ) ) { 10629 if ( inst.snapElements[ i ].snapping ) { 10630 ( inst.options.snap.release && 10631 inst.options.snap.release.call( 10632 inst.element, 10633 event, 10634 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } ) 10635 ) ); 10636 } 10637 inst.snapElements[ i ].snapping = false; 10638 continue; 10639 } 10640 10641 if ( o.snapMode !== "inner" ) { 10642 ts = Math.abs( t - y2 ) <= d; 10643 bs = Math.abs( b - y1 ) <= d; 10644 ls = Math.abs( l - x2 ) <= d; 10645 rs = Math.abs( r - x1 ) <= d; 10646 if ( ts ) { 10647 ui.position.top = inst._convertPositionTo( "relative", { 10648 top: t - inst.helperProportions.height, 10649 left: 0 10650 } ).top; 10651 } 10652 if ( bs ) { 10653 ui.position.top = inst._convertPositionTo( "relative", { 10654 top: b, 10655 left: 0 10656 } ).top; 10657 } 10658 if ( ls ) { 10659 ui.position.left = inst._convertPositionTo( "relative", { 10660 top: 0, 10661 left: l - inst.helperProportions.width 10662 } ).left; 10663 } 10664 if ( rs ) { 10665 ui.position.left = inst._convertPositionTo( "relative", { 10666 top: 0, 10667 left: r 10668 } ).left; 10669 } 10670 } 10671 10672 first = ( ts || bs || ls || rs ); 10673 10674 if ( o.snapMode !== "outer" ) { 10675 ts = Math.abs( t - y1 ) <= d; 10676 bs = Math.abs( b - y2 ) <= d; 10677 ls = Math.abs( l - x1 ) <= d; 10678 rs = Math.abs( r - x2 ) <= d; 10679 if ( ts ) { 10680 ui.position.top = inst._convertPositionTo( "relative", { 10681 top: t, 10682 left: 0 10683 } ).top; 10684 } 10685 if ( bs ) { 10686 ui.position.top = inst._convertPositionTo( "relative", { 10687 top: b - inst.helperProportions.height, 10688 left: 0 10689 } ).top; 10690 } 10691 if ( ls ) { 10692 ui.position.left = inst._convertPositionTo( "relative", { 10693 top: 0, 10694 left: l 10695 } ).left; 10696 } 10697 if ( rs ) { 10698 ui.position.left = inst._convertPositionTo( "relative", { 10699 top: 0, 10700 left: r - inst.helperProportions.width 10701 } ).left; 10702 } 10703 } 10704 10705 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) { 10706 ( inst.options.snap.snap && 10707 inst.options.snap.snap.call( 10708 inst.element, 10709 event, 10710 $.extend( inst._uiHash(), { 10711 snapItem: inst.snapElements[ i ].item 10712 } ) ) ); 10713 } 10714 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first ); 10715 10716 } 10717 10718 } 10719 } ); 10720 10721 $.ui.plugin.add( "draggable", "stack", { 10722 start: function( event, ui, instance ) { 10723 var min, 10724 o = instance.options, 10725 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) { 10726 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) - 10727 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 ); 10728 } ); 10729 10730 if ( !group.length ) { return; } 10731 10732 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0; 10733 $( group ).each( function( i ) { 10734 $( this ).css( "zIndex", min + i ); 10735 } ); 10736 this.css( "zIndex", ( min + group.length ) ); 10737 } 10738 } ); 10739 10740 $.ui.plugin.add( "draggable", "zIndex", { 10741 start: function( event, ui, instance ) { 10742 var t = $( ui.helper ), 10743 o = instance.options; 10744 10745 if ( t.css( "zIndex" ) ) { 10746 o._zIndex = t.css( "zIndex" ); 10747 } 10748 t.css( "zIndex", o.zIndex ); 10749 }, 10750 stop: function( event, ui, instance ) { 10751 var o = instance.options; 10752 10753 if ( o._zIndex ) { 10754 $( ui.helper ).css( "zIndex", o._zIndex ); 10755 } 10756 } 10757 } ); 10758 10759 var widgetsDraggable = $.ui.draggable; 10760 10761 10762 /*! 10763 * jQuery UI Resizable 1.12.1 10764 * http://jqueryui.com 10765 * 10766 * Copyright jQuery Foundation and other contributors 10767 * Released under the MIT license. 10768 * http://jquery.org/license 10769 */ 10770 10771 //>>label: Resizable 10772 //>>group: Interactions 10773 //>>description: Enables resize functionality for any element. 10774 //>>docs: http://api.jqueryui.com/resizable/ 10775 //>>demos: http://jqueryui.com/resizable/ 10776 //>>css.structure: ../../themes/base/core.css 10777 //>>css.structure: ../../themes/base/resizable.css 10778 //>>css.theme: ../../themes/base/theme.css 10779 10780 10781 10782 $.widget( "ui.resizable", $.ui.mouse, { 10783 version: "1.12.1", 10784 widgetEventPrefix: "resize", 10785 options: { 10786 alsoResize: false, 10787 animate: false, 10788 animateDuration: "slow", 10789 animateEasing: "swing", 10790 aspectRatio: false, 10791 autoHide: false, 10792 classes: { 10793 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se" 10794 }, 10795 containment: false, 10796 ghost: false, 10797 grid: false, 10798 handles: "e,s,se", 10799 helper: false, 10800 maxHeight: null, 10801 maxWidth: null, 10802 minHeight: 10, 10803 minWidth: 10, 10804 10805 // See #7960 10806 zIndex: 90, 10807 10808 // Callbacks 10809 resize: null, 10810 start: null, 10811 stop: null 10812 }, 10813 10814 _num: function( value ) { 10815 return parseFloat( value ) || 0; 10816 }, 10817 10818 _isNumber: function( value ) { 10819 return !isNaN( parseFloat( value ) ); 10820 }, 10821 10822 _hasScroll: function( el, a ) { 10823 10824 if ( $( el ).css( "overflow" ) === "hidden" ) { 10825 return false; 10826 } 10827 10828 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", 10829 has = false; 10830 10831 if ( el[ scroll ] > 0 ) { 10832 return true; 10833 } 10834 10835 // TODO: determine which cases actually cause this to happen 10836 // if the element doesn't have the scroll set, see if it's possible to 10837 // set the scroll 10838 el[ scroll ] = 1; 10839 has = ( el[ scroll ] > 0 ); 10840 el[ scroll ] = 0; 10841 return has; 10842 }, 10843 10844 _create: function() { 10845 10846 var margins, 10847 o = this.options, 10848 that = this; 10849 this._addClass( "ui-resizable" ); 10850 10851 $.extend( this, { 10852 _aspectRatio: !!( o.aspectRatio ), 10853 aspectRatio: o.aspectRatio, 10854 originalElement: this.element, 10855 _proportionallyResizeElements: [], 10856 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null 10857 } ); 10858 10859 // Wrap the element if it cannot hold child nodes 10860 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) { 10861 10862 this.element.wrap( 10863 $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( { 10864 position: this.element.css( "position" ), 10865 width: this.element.outerWidth(), 10866 height: this.element.outerHeight(), 10867 top: this.element.css( "top" ), 10868 left: this.element.css( "left" ) 10869 } ) 10870 ); 10871 10872 this.element = this.element.parent().data( 10873 "ui-resizable", this.element.resizable( "instance" ) 10874 ); 10875 10876 this.elementIsWrapper = true; 10877 10878 margins = { 10879 marginTop: this.originalElement.css( "marginTop" ), 10880 marginRight: this.originalElement.css( "marginRight" ), 10881 marginBottom: this.originalElement.css( "marginBottom" ), 10882 marginLeft: this.originalElement.css( "marginLeft" ) 10883 }; 10884 10885 this.element.css( margins ); 10886 this.originalElement.css( "margin", 0 ); 10887 10888 // support: Safari 10889 // Prevent Safari textarea resize 10890 this.originalResizeStyle = this.originalElement.css( "resize" ); 10891 this.originalElement.css( "resize", "none" ); 10892 10893 this._proportionallyResizeElements.push( this.originalElement.css( { 10894 position: "static", 10895 zoom: 1, 10896 display: "block" 10897 } ) ); 10898 10899 // Support: IE9 10900 // avoid IE jump (hard set the margin) 10901 this.originalElement.css( margins ); 10902 10903 this._proportionallyResize(); 10904 } 10905 10906 this._setupHandles(); 10907 10908 if ( o.autoHide ) { 10909 $( this.element ) 10910 .on( "mouseenter", function() { 10911 if ( o.disabled ) { 10912 return; 10913 } 10914 that._removeClass( "ui-resizable-autohide" ); 10915 that._handles.show(); 10916 } ) 10917 .on( "mouseleave", function() { 10918 if ( o.disabled ) { 10919 return; 10920 } 10921 if ( !that.resizing ) { 10922 that._addClass( "ui-resizable-autohide" ); 10923 that._handles.hide(); 10924 } 10925 } ); 10926 } 10927 10928 this._mouseInit(); 10929 }, 10930 10931 _destroy: function() { 10932 10933 this._mouseDestroy(); 10934 10935 var wrapper, 10936 _destroy = function( exp ) { 10937 $( exp ) 10938 .removeData( "resizable" ) 10939 .removeData( "ui-resizable" ) 10940 .off( ".resizable" ) 10941 .find( ".ui-resizable-handle" ) 10942 .remove(); 10943 }; 10944 10945 // TODO: Unwrap at same DOM position 10946 if ( this.elementIsWrapper ) { 10947 _destroy( this.element ); 10948 wrapper = this.element; 10949 this.originalElement.css( { 10950 position: wrapper.css( "position" ), 10951 width: wrapper.outerWidth(), 10952 height: wrapper.outerHeight(), 10953 top: wrapper.css( "top" ), 10954 left: wrapper.css( "left" ) 10955 } ).insertAfter( wrapper ); 10956 wrapper.remove(); 10957 } 10958 10959 this.originalElement.css( "resize", this.originalResizeStyle ); 10960 _destroy( this.originalElement ); 10961 10962 return this; 10963 }, 10964 10965 _setOption: function( key, value ) { 10966 this._super( key, value ); 10967 10968 switch ( key ) { 10969 case "handles": 10970 this._removeHandles(); 10971 this._setupHandles(); 10972 break; 10973 default: 10974 break; 10975 } 10976 }, 10977 10978 _setupHandles: function() { 10979 var o = this.options, handle, i, n, hname, axis, that = this; 10980 this.handles = o.handles || 10981 ( !$( ".ui-resizable-handle", this.element ).length ? 10982 "e,s,se" : { 10983 n: ".ui-resizable-n", 10984 e: ".ui-resizable-e", 10985 s: ".ui-resizable-s", 10986 w: ".ui-resizable-w", 10987 se: ".ui-resizable-se", 10988 sw: ".ui-resizable-sw", 10989 ne: ".ui-resizable-ne", 10990 nw: ".ui-resizable-nw" 10991 } ); 10992 10993 this._handles = $(); 10994 if ( this.handles.constructor === String ) { 10995 10996 if ( this.handles === "all" ) { 10997 this.handles = "n,e,s,w,se,sw,ne,nw"; 10998 } 10999 11000 n = this.handles.split( "," ); 11001 this.handles = {}; 11002 11003 for ( i = 0; i < n.length; i++ ) { 11004 11005 handle = $.trim( n[ i ] ); 11006 hname = "ui-resizable-" + handle; 11007 axis = $( "<div>" ); 11008 this._addClass( axis, "ui-resizable-handle " + hname ); 11009 11010 axis.css( { zIndex: o.zIndex } ); 11011 11012 this.handles[ handle ] = ".ui-resizable-" + handle; 11013 this.element.append( axis ); 11014 } 11015 11016 } 11017 11018 this._renderAxis = function( target ) { 11019 11020 var i, axis, padPos, padWrapper; 11021 11022 target = target || this.element; 11023 11024 for ( i in this.handles ) { 11025 11026 if ( this.handles[ i ].constructor === String ) { 11027 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show(); 11028 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { 11029 this.handles[ i ] = $( this.handles[ i ] ); 11030 this._on( this.handles[ i ], { "mousedown": that._mouseDown } ); 11031 } 11032 11033 if ( this.elementIsWrapper && 11034 this.originalElement[ 0 ] 11035 .nodeName 11036 .match( /^(textarea|input|select|button)$/i ) ) { 11037 axis = $( this.handles[ i ], this.element ); 11038 11039 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ? 11040 axis.outerHeight() : 11041 axis.outerWidth(); 11042 11043 padPos = [ "padding", 11044 /ne|nw|n/.test( i ) ? "Top" : 11045 /se|sw|s/.test( i ) ? "Bottom" : 11046 /^e$/.test( i ) ? "Right" : "Left" ].join( "" ); 11047 11048 target.css( padPos, padWrapper ); 11049 11050 this._proportionallyResize(); 11051 } 11052 11053 this._handles = this._handles.add( this.handles[ i ] ); 11054 } 11055 }; 11056 11057 // TODO: make renderAxis a prototype function 11058 this._renderAxis( this.element ); 11059 11060 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); 11061 this._handles.disableSelection(); 11062 11063 this._handles.on( "mouseover", function() { 11064 if ( !that.resizing ) { 11065 if ( this.className ) { 11066 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i ); 11067 } 11068 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se"; 11069 } 11070 } ); 11071 11072 if ( o.autoHide ) { 11073 this._handles.hide(); 11074 this._addClass( "ui-resizable-autohide" ); 11075 } 11076 }, 11077 11078 _removeHandles: function() { 11079 this._handles.remove(); 11080 }, 11081 11082 _mouseCapture: function( event ) { 11083 var i, handle, 11084 capture = false; 11085 11086 for ( i in this.handles ) { 11087 handle = $( this.handles[ i ] )[ 0 ]; 11088 if ( handle === event.target || $.contains( handle, event.target ) ) { 11089 capture = true; 11090 } 11091 } 11092 11093 return !this.options.disabled && capture; 11094 }, 11095 11096 _mouseStart: function( event ) { 11097 11098 var curleft, curtop, cursor, 11099 o = this.options, 11100 el = this.element; 11101 11102 this.resizing = true; 11103 11104 this._renderProxy(); 11105 11106 curleft = this._num( this.helper.css( "left" ) ); 11107 curtop = this._num( this.helper.css( "top" ) ); 11108 11109 if ( o.containment ) { 11110 curleft += $( o.containment ).scrollLeft() || 0; 11111 curtop += $( o.containment ).scrollTop() || 0; 11112 } 11113 11114 this.offset = this.helper.offset(); 11115 this.position = { left: curleft, top: curtop }; 11116 11117 this.size = this._helper ? { 11118 width: this.helper.width(), 11119 height: this.helper.height() 11120 } : { 11121 width: el.width(), 11122 height: el.height() 11123 }; 11124 11125 this.originalSize = this._helper ? { 11126 width: el.outerWidth(), 11127 height: el.outerHeight() 11128 } : { 11129 width: el.width(), 11130 height: el.height() 11131 }; 11132 11133 this.sizeDiff = { 11134 width: el.outerWidth() - el.width(), 11135 height: el.outerHeight() - el.height() 11136 }; 11137 11138 this.originalPosition = { left: curleft, top: curtop }; 11139 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 11140 11141 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ? 11142 o.aspectRatio : 11143 ( ( this.originalSize.width / this.originalSize.height ) || 1 ); 11144 11145 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" ); 11146 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor ); 11147 11148 this._addClass( "ui-resizable-resizing" ); 11149 this._propagate( "start", event ); 11150 return true; 11151 }, 11152 11153 _mouseDrag: function( event ) { 11154 11155 var data, props, 11156 smp = this.originalMousePosition, 11157 a = this.axis, 11158 dx = ( event.pageX - smp.left ) || 0, 11159 dy = ( event.pageY - smp.top ) || 0, 11160 trigger = this._change[ a ]; 11161 11162 this._updatePrevProperties(); 11163 11164 if ( !trigger ) { 11165 return false; 11166 } 11167 11168 data = trigger.apply( this, [ event, dx, dy ] ); 11169 11170 this._updateVirtualBoundaries( event.shiftKey ); 11171 if ( this._aspectRatio || event.shiftKey ) { 11172 data = this._updateRatio( data, event ); 11173 } 11174 11175 data = this._respectSize( data, event ); 11176 11177 this._updateCache( data ); 11178 11179 this._propagate( "resize", event ); 11180 11181 props = this._applyChanges(); 11182 11183 if ( !this._helper && this._proportionallyResizeElements.length ) { 11184 this._proportionallyResize(); 11185 } 11186 11187 if ( !$.isEmptyObject( props ) ) { 11188 this._updatePrevProperties(); 11189 this._trigger( "resize", event, this.ui() ); 11190 this._applyChanges(); 11191 } 11192 11193 return false; 11194 }, 11195 11196 _mouseStop: function( event ) { 11197 11198 this.resizing = false; 11199 var pr, ista, soffseth, soffsetw, s, left, top, 11200 o = this.options, that = this; 11201 11202 if ( this._helper ) { 11203 11204 pr = this._proportionallyResizeElements; 11205 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ); 11206 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height; 11207 soffsetw = ista ? 0 : that.sizeDiff.width; 11208 11209 s = { 11210 width: ( that.helper.width() - soffsetw ), 11211 height: ( that.helper.height() - soffseth ) 11212 }; 11213 left = ( parseFloat( that.element.css( "left" ) ) + 11214 ( that.position.left - that.originalPosition.left ) ) || null; 11215 top = ( parseFloat( that.element.css( "top" ) ) + 11216 ( that.position.top - that.originalPosition.top ) ) || null; 11217 11218 if ( !o.animate ) { 11219 this.element.css( $.extend( s, { top: top, left: left } ) ); 11220 } 11221 11222 that.helper.height( that.size.height ); 11223 that.helper.width( that.size.width ); 11224 11225 if ( this._helper && !o.animate ) { 11226 this._proportionallyResize(); 11227 } 11228 } 11229 11230 $( "body" ).css( "cursor", "auto" ); 11231 11232 this._removeClass( "ui-resizable-resizing" ); 11233 11234 this._propagate( "stop", event ); 11235 11236 if ( this._helper ) { 11237 this.helper.remove(); 11238 } 11239 11240 return false; 11241 11242 }, 11243 11244 _updatePrevProperties: function() { 11245 this.prevPosition = { 11246 top: this.position.top, 11247 left: this.position.left 11248 }; 11249 this.prevSize = { 11250 width: this.size.width, 11251 height: this.size.height 11252 }; 11253 }, 11254 11255 _applyChanges: function() { 11256 var props = {}; 11257 11258 if ( this.position.top !== this.prevPosition.top ) { 11259 props.top = this.position.top + "px"; 11260 } 11261 if ( this.position.left !== this.prevPosition.left ) { 11262 props.left = this.position.left + "px"; 11263 } 11264 if ( this.size.width !== this.prevSize.width ) { 11265 props.width = this.size.width + "px"; 11266 } 11267 if ( this.size.height !== this.prevSize.height ) { 11268 props.height = this.size.height + "px"; 11269 } 11270 11271 this.helper.css( props ); 11272 11273 return props; 11274 }, 11275 11276 _updateVirtualBoundaries: function( forceAspectRatio ) { 11277 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, 11278 o = this.options; 11279 11280 b = { 11281 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0, 11282 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity, 11283 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0, 11284 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity 11285 }; 11286 11287 if ( this._aspectRatio || forceAspectRatio ) { 11288 pMinWidth = b.minHeight * this.aspectRatio; 11289 pMinHeight = b.minWidth / this.aspectRatio; 11290 pMaxWidth = b.maxHeight * this.aspectRatio; 11291 pMaxHeight = b.maxWidth / this.aspectRatio; 11292 11293 if ( pMinWidth > b.minWidth ) { 11294 b.minWidth = pMinWidth; 11295 } 11296 if ( pMinHeight > b.minHeight ) { 11297 b.minHeight = pMinHeight; 11298 } 11299 if ( pMaxWidth < b.maxWidth ) { 11300 b.maxWidth = pMaxWidth; 11301 } 11302 if ( pMaxHeight < b.maxHeight ) { 11303 b.maxHeight = pMaxHeight; 11304 } 11305 } 11306 this._vBoundaries = b; 11307 }, 11308 11309 _updateCache: function( data ) { 11310 this.offset = this.helper.offset(); 11311 if ( this._isNumber( data.left ) ) { 11312 this.position.left = data.left; 11313 } 11314 if ( this._isNumber( data.top ) ) { 11315 this.position.top = data.top; 11316 } 11317 if ( this._isNumber( data.height ) ) { 11318 this.size.height = data.height; 11319 } 11320 if ( this._isNumber( data.width ) ) { 11321 this.size.width = data.width; 11322 } 11323 }, 11324 11325 _updateRatio: function( data ) { 11326 11327 var cpos = this.position, 11328 csize = this.size, 11329 a = this.axis; 11330 11331 if ( this._isNumber( data.height ) ) { 11332 data.width = ( data.height * this.aspectRatio ); 11333 } else if ( this._isNumber( data.width ) ) { 11334 data.height = ( data.width / this.aspectRatio ); 11335 } 11336 11337 if ( a === "sw" ) { 11338 data.left = cpos.left + ( csize.width - data.width ); 11339 data.top = null; 11340 } 11341 if ( a === "nw" ) { 11342 data.top = cpos.top + ( csize.height - data.height ); 11343 data.left = cpos.left + ( csize.width - data.width ); 11344 } 11345 11346 return data; 11347 }, 11348 11349 _respectSize: function( data ) { 11350 11351 var o = this._vBoundaries, 11352 a = this.axis, 11353 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ), 11354 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ), 11355 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ), 11356 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ), 11357 dw = this.originalPosition.left + this.originalSize.width, 11358 dh = this.originalPosition.top + this.originalSize.height, 11359 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a ); 11360 if ( isminw ) { 11361 data.width = o.minWidth; 11362 } 11363 if ( isminh ) { 11364 data.height = o.minHeight; 11365 } 11366 if ( ismaxw ) { 11367 data.width = o.maxWidth; 11368 } 11369 if ( ismaxh ) { 11370 data.height = o.maxHeight; 11371 } 11372 11373 if ( isminw && cw ) { 11374 data.left = dw - o.minWidth; 11375 } 11376 if ( ismaxw && cw ) { 11377 data.left = dw - o.maxWidth; 11378 } 11379 if ( isminh && ch ) { 11380 data.top = dh - o.minHeight; 11381 } 11382 if ( ismaxh && ch ) { 11383 data.top = dh - o.maxHeight; 11384 } 11385 11386 // Fixing jump error on top/left - bug #2330 11387 if ( !data.width && !data.height && !data.left && data.top ) { 11388 data.top = null; 11389 } else if ( !data.width && !data.height && !data.top && data.left ) { 11390 data.left = null; 11391 } 11392 11393 return data; 11394 }, 11395 11396 _getPaddingPlusBorderDimensions: function( element ) { 11397 var i = 0, 11398 widths = [], 11399 borders = [ 11400 element.css( "borderTopWidth" ), 11401 element.css( "borderRightWidth" ), 11402 element.css( "borderBottomWidth" ), 11403 element.css( "borderLeftWidth" ) 11404 ], 11405 paddings = [ 11406 element.css( "paddingTop" ), 11407 element.css( "paddingRight" ), 11408 element.css( "paddingBottom" ), 11409 element.css( "paddingLeft" ) 11410 ]; 11411 11412 for ( ; i < 4; i++ ) { 11413 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 ); 11414 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 ); 11415 } 11416 11417 return { 11418 height: widths[ 0 ] + widths[ 2 ], 11419 width: widths[ 1 ] + widths[ 3 ] 11420 }; 11421 }, 11422 11423 _proportionallyResize: function() { 11424 11425 if ( !this._proportionallyResizeElements.length ) { 11426 return; 11427 } 11428 11429 var prel, 11430 i = 0, 11431 element = this.helper || this.element; 11432 11433 for ( ; i < this._proportionallyResizeElements.length; i++ ) { 11434 11435 prel = this._proportionallyResizeElements[ i ]; 11436 11437 // TODO: Seems like a bug to cache this.outerDimensions 11438 // considering that we are in a loop. 11439 if ( !this.outerDimensions ) { 11440 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); 11441 } 11442 11443 prel.css( { 11444 height: ( element.height() - this.outerDimensions.height ) || 0, 11445 width: ( element.width() - this.outerDimensions.width ) || 0 11446 } ); 11447 11448 } 11449 11450 }, 11451 11452 _renderProxy: function() { 11453 11454 var el = this.element, o = this.options; 11455 this.elementOffset = el.offset(); 11456 11457 if ( this._helper ) { 11458 11459 this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" ); 11460 11461 this._addClass( this.helper, this._helper ); 11462 this.helper.css( { 11463 width: this.element.outerWidth(), 11464 height: this.element.outerHeight(), 11465 position: "absolute", 11466 left: this.elementOffset.left + "px", 11467 top: this.elementOffset.top + "px", 11468 zIndex: ++o.zIndex //TODO: Don't modify option 11469 } ); 11470 11471 this.helper 11472 .appendTo( "body" ) 11473 .disableSelection(); 11474 11475 } else { 11476 this.helper = this.element; 11477 } 11478 11479 }, 11480 11481 _change: { 11482 e: function( event, dx ) { 11483 return { width: this.originalSize.width + dx }; 11484 }, 11485 w: function( event, dx ) { 11486 var cs = this.originalSize, sp = this.originalPosition; 11487 return { left: sp.left + dx, width: cs.width - dx }; 11488 }, 11489 n: function( event, dx, dy ) { 11490 var cs = this.originalSize, sp = this.originalPosition; 11491 return { top: sp.top + dy, height: cs.height - dy }; 11492 }, 11493 s: function( event, dx, dy ) { 11494 return { height: this.originalSize.height + dy }; 11495 }, 11496 se: function( event, dx, dy ) { 11497 return $.extend( this._change.s.apply( this, arguments ), 11498 this._change.e.apply( this, [ event, dx, dy ] ) ); 11499 }, 11500 sw: function( event, dx, dy ) { 11501 return $.extend( this._change.s.apply( this, arguments ), 11502 this._change.w.apply( this, [ event, dx, dy ] ) ); 11503 }, 11504 ne: function( event, dx, dy ) { 11505 return $.extend( this._change.n.apply( this, arguments ), 11506 this._change.e.apply( this, [ event, dx, dy ] ) ); 11507 }, 11508 nw: function( event, dx, dy ) { 11509 return $.extend( this._change.n.apply( this, arguments ), 11510 this._change.w.apply( this, [ event, dx, dy ] ) ); 11511 } 11512 }, 11513 11514 _propagate: function( n, event ) { 11515 $.ui.plugin.call( this, n, [ event, this.ui() ] ); 11516 ( n !== "resize" && this._trigger( n, event, this.ui() ) ); 11517 }, 11518 11519 plugins: {}, 11520 11521 ui: function() { 11522 return { 11523 originalElement: this.originalElement, 11524 element: this.element, 11525 helper: this.helper, 11526 position: this.position, 11527 size: this.size, 11528 originalSize: this.originalSize, 11529 originalPosition: this.originalPosition 11530 }; 11531 } 11532 11533 } ); 11534 11535 /* 11536 * Resizable Extensions 11537 */ 11538 11539 $.ui.plugin.add( "resizable", "animate", { 11540 11541 stop: function( event ) { 11542 var that = $( this ).resizable( "instance" ), 11543 o = that.options, 11544 pr = that._proportionallyResizeElements, 11545 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ), 11546 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height, 11547 soffsetw = ista ? 0 : that.sizeDiff.width, 11548 style = { 11549 width: ( that.size.width - soffsetw ), 11550 height: ( that.size.height - soffseth ) 11551 }, 11552 left = ( parseFloat( that.element.css( "left" ) ) + 11553 ( that.position.left - that.originalPosition.left ) ) || null, 11554 top = ( parseFloat( that.element.css( "top" ) ) + 11555 ( that.position.top - that.originalPosition.top ) ) || null; 11556 11557 that.element.animate( 11558 $.extend( style, top && left ? { top: top, left: left } : {} ), { 11559 duration: o.animateDuration, 11560 easing: o.animateEasing, 11561 step: function() { 11562 11563 var data = { 11564 width: parseFloat( that.element.css( "width" ) ), 11565 height: parseFloat( that.element.css( "height" ) ), 11566 top: parseFloat( that.element.css( "top" ) ), 11567 left: parseFloat( that.element.css( "left" ) ) 11568 }; 11569 11570 if ( pr && pr.length ) { 11571 $( pr[ 0 ] ).css( { width: data.width, height: data.height } ); 11572 } 11573 11574 // Propagating resize, and updating values for each animation step 11575 that._updateCache( data ); 11576 that._propagate( "resize", event ); 11577 11578 } 11579 } 11580 ); 11581 } 11582 11583 } ); 11584 11585 $.ui.plugin.add( "resizable", "containment", { 11586 11587 start: function() { 11588 var element, p, co, ch, cw, width, height, 11589 that = $( this ).resizable( "instance" ), 11590 o = that.options, 11591 el = that.element, 11592 oc = o.containment, 11593 11594 ce = ( oc instanceof $ ) ? 11595 oc.get( 0 ) : 11596 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; 11597 11598 if ( !ce ) { 11599 return; 11600 } 11601 11602 that.containerElement = $( ce ); 11603 11604 if ( /document/.test( oc ) || oc === document ) { 11605 that.containerOffset = { 11606 left: 0, 11607 top: 0 11608 }; 11609 that.containerPosition = { 11610 left: 0, 11611 top: 0 11612 }; 11613 11614 that.parentData = { 11615 element: $( document ), 11616 left: 0, 11617 top: 0, 11618 width: $( document ).width(), 11619 height: $( document ).height() || document.body.parentNode.scrollHeight 11620 }; 11621 } else { 11622 element = $( ce ); 11623 p = []; 11624 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) { 11625 p[ i ] = that._num( element.css( "padding" + name ) ); 11626 } ); 11627 11628 that.containerOffset = element.offset(); 11629 that.containerPosition = element.position(); 11630 that.containerSize = { 11631 height: ( element.innerHeight() - p[ 3 ] ), 11632 width: ( element.innerWidth() - p[ 1 ] ) 11633 }; 11634 11635 co = that.containerOffset; 11636 ch = that.containerSize.height; 11637 cw = that.containerSize.width; 11638 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw ); 11639 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ; 11640 11641 that.parentData = { 11642 element: ce, 11643 left: co.left, 11644 top: co.top, 11645 width: width, 11646 height: height 11647 }; 11648 } 11649 }, 11650 11651 resize: function( event ) { 11652 var woset, hoset, isParent, isOffsetRelative, 11653 that = $( this ).resizable( "instance" ), 11654 o = that.options, 11655 co = that.containerOffset, 11656 cp = that.position, 11657 pRatio = that._aspectRatio || event.shiftKey, 11658 cop = { 11659 top: 0, 11660 left: 0 11661 }, 11662 ce = that.containerElement, 11663 continueResize = true; 11664 11665 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { 11666 cop = co; 11667 } 11668 11669 if ( cp.left < ( that._helper ? co.left : 0 ) ) { 11670 that.size.width = that.size.width + 11671 ( that._helper ? 11672 ( that.position.left - co.left ) : 11673 ( that.position.left - cop.left ) ); 11674 11675 if ( pRatio ) { 11676 that.size.height = that.size.width / that.aspectRatio; 11677 continueResize = false; 11678 } 11679 that.position.left = o.helper ? co.left : 0; 11680 } 11681 11682 if ( cp.top < ( that._helper ? co.top : 0 ) ) { 11683 that.size.height = that.size.height + 11684 ( that._helper ? 11685 ( that.position.top - co.top ) : 11686 that.position.top ); 11687 11688 if ( pRatio ) { 11689 that.size.width = that.size.height * that.aspectRatio; 11690 continueResize = false; 11691 } 11692 that.position.top = that._helper ? co.top : 0; 11693 } 11694 11695 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); 11696 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); 11697 11698 if ( isParent && isOffsetRelative ) { 11699 that.offset.left = that.parentData.left + that.position.left; 11700 that.offset.top = that.parentData.top + that.position.top; 11701 } else { 11702 that.offset.left = that.element.offset().left; 11703 that.offset.top = that.element.offset().top; 11704 } 11705 11706 woset = Math.abs( that.sizeDiff.width + 11707 ( that._helper ? 11708 that.offset.left - cop.left : 11709 ( that.offset.left - co.left ) ) ); 11710 11711 hoset = Math.abs( that.sizeDiff.height + 11712 ( that._helper ? 11713 that.offset.top - cop.top : 11714 ( that.offset.top - co.top ) ) ); 11715 11716 if ( woset + that.size.width >= that.parentData.width ) { 11717 that.size.width = that.parentData.width - woset; 11718 if ( pRatio ) { 11719 that.size.height = that.size.width / that.aspectRatio; 11720 continueResize = false; 11721 } 11722 } 11723 11724 if ( hoset + that.size.height >= that.parentData.height ) { 11725 that.size.height = that.parentData.height - hoset; 11726 if ( pRatio ) { 11727 that.size.width = that.size.height * that.aspectRatio; 11728 continueResize = false; 11729 } 11730 } 11731 11732 if ( !continueResize ) { 11733 that.position.left = that.prevPosition.left; 11734 that.position.top = that.prevPosition.top; 11735 that.size.width = that.prevSize.width; 11736 that.size.height = that.prevSize.height; 11737 } 11738 }, 11739 11740 stop: function() { 11741 var that = $( this ).resizable( "instance" ), 11742 o = that.options, 11743 co = that.containerOffset, 11744 cop = that.containerPosition, 11745 ce = that.containerElement, 11746 helper = $( that.helper ), 11747 ho = helper.offset(), 11748 w = helper.outerWidth() - that.sizeDiff.width, 11749 h = helper.outerHeight() - that.sizeDiff.height; 11750 11751 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { 11752 $( this ).css( { 11753 left: ho.left - cop.left - co.left, 11754 width: w, 11755 height: h 11756 } ); 11757 } 11758 11759 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { 11760 $( this ).css( { 11761 left: ho.left - cop.left - co.left, 11762 width: w, 11763 height: h 11764 } ); 11765 } 11766 } 11767 } ); 11768 11769 $.ui.plugin.add( "resizable", "alsoResize", { 11770 11771 start: function() { 11772 var that = $( this ).resizable( "instance" ), 11773 o = that.options; 11774 11775 $( o.alsoResize ).each( function() { 11776 var el = $( this ); 11777 el.data( "ui-resizable-alsoresize", { 11778 width: parseFloat( el.width() ), height: parseFloat( el.height() ), 11779 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) 11780 } ); 11781 } ); 11782 }, 11783 11784 resize: function( event, ui ) { 11785 var that = $( this ).resizable( "instance" ), 11786 o = that.options, 11787 os = that.originalSize, 11788 op = that.originalPosition, 11789 delta = { 11790 height: ( that.size.height - os.height ) || 0, 11791 width: ( that.size.width - os.width ) || 0, 11792 top: ( that.position.top - op.top ) || 0, 11793 left: ( that.position.left - op.left ) || 0 11794 }; 11795 11796 $( o.alsoResize ).each( function() { 11797 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {}, 11798 css = el.parents( ui.originalElement[ 0 ] ).length ? 11799 [ "width", "height" ] : 11800 [ "width", "height", "top", "left" ]; 11801 11802 $.each( css, function( i, prop ) { 11803 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 ); 11804 if ( sum && sum >= 0 ) { 11805 style[ prop ] = sum || null; 11806 } 11807 } ); 11808 11809 el.css( style ); 11810 } ); 11811 }, 11812 11813 stop: function() { 11814 $( this ).removeData( "ui-resizable-alsoresize" ); 11815 } 11816 } ); 11817 11818 $.ui.plugin.add( "resizable", "ghost", { 11819 11820 start: function() { 11821 11822 var that = $( this ).resizable( "instance" ), cs = that.size; 11823 11824 that.ghost = that.originalElement.clone(); 11825 that.ghost.css( { 11826 opacity: 0.25, 11827 display: "block", 11828 position: "relative", 11829 height: cs.height, 11830 width: cs.width, 11831 margin: 0, 11832 left: 0, 11833 top: 0 11834 } ); 11835 11836 that._addClass( that.ghost, "ui-resizable-ghost" ); 11837 11838 // DEPRECATED 11839 // TODO: remove after 1.12 11840 if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) { 11841 11842 // Ghost option 11843 that.ghost.addClass( this.options.ghost ); 11844 } 11845 11846 that.ghost.appendTo( that.helper ); 11847 11848 }, 11849 11850 resize: function() { 11851 var that = $( this ).resizable( "instance" ); 11852 if ( that.ghost ) { 11853 that.ghost.css( { 11854 position: "relative", 11855 height: that.size.height, 11856 width: that.size.width 11857 } ); 11858 } 11859 }, 11860 11861 stop: function() { 11862 var that = $( this ).resizable( "instance" ); 11863 if ( that.ghost && that.helper ) { 11864 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) ); 11865 } 11866 } 11867 11868 } ); 11869 11870 $.ui.plugin.add( "resizable", "grid", { 11871 11872 resize: function() { 11873 var outerDimensions, 11874 that = $( this ).resizable( "instance" ), 11875 o = that.options, 11876 cs = that.size, 11877 os = that.originalSize, 11878 op = that.originalPosition, 11879 a = that.axis, 11880 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, 11881 gridX = ( grid[ 0 ] || 1 ), 11882 gridY = ( grid[ 1 ] || 1 ), 11883 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX, 11884 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY, 11885 newWidth = os.width + ox, 11886 newHeight = os.height + oy, 11887 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ), 11888 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ), 11889 isMinWidth = o.minWidth && ( o.minWidth > newWidth ), 11890 isMinHeight = o.minHeight && ( o.minHeight > newHeight ); 11891 11892 o.grid = grid; 11893 11894 if ( isMinWidth ) { 11895 newWidth += gridX; 11896 } 11897 if ( isMinHeight ) { 11898 newHeight += gridY; 11899 } 11900 if ( isMaxWidth ) { 11901 newWidth -= gridX; 11902 } 11903 if ( isMaxHeight ) { 11904 newHeight -= gridY; 11905 } 11906 11907 if ( /^(se|s|e)$/.test( a ) ) { 11908 that.size.width = newWidth; 11909 that.size.height = newHeight; 11910 } else if ( /^(ne)$/.test( a ) ) { 11911 that.size.width = newWidth; 11912 that.size.height = newHeight; 11913 that.position.top = op.top - oy; 11914 } else if ( /^(sw)$/.test( a ) ) { 11915 that.size.width = newWidth; 11916 that.size.height = newHeight; 11917 that.position.left = op.left - ox; 11918 } else { 11919 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) { 11920 outerDimensions = that._getPaddingPlusBorderDimensions( this ); 11921 } 11922 11923 if ( newHeight - gridY > 0 ) { 11924 that.size.height = newHeight; 11925 that.position.top = op.top - oy; 11926 } else { 11927 newHeight = gridY - outerDimensions.height; 11928 that.size.height = newHeight; 11929 that.position.top = op.top + os.height - newHeight; 11930 } 11931 if ( newWidth - gridX > 0 ) { 11932 that.size.width = newWidth; 11933 that.position.left = op.left - ox; 11934 } else { 11935 newWidth = gridX - outerDimensions.width; 11936 that.size.width = newWidth; 11937 that.position.left = op.left + os.width - newWidth; 11938 } 11939 } 11940 } 11941 11942 } ); 11943 11944 var widgetsResizable = $.ui.resizable; 11945 11946 11947 /*! 11948 * jQuery UI Dialog 1.12.1 11949 * http://jqueryui.com 11950 * 11951 * Copyright jQuery Foundation and other contributors 11952 * Released under the MIT license. 11953 * http://jquery.org/license 11954 */ 11955 11956 //>>label: Dialog 11957 //>>group: Widgets 11958 //>>description: Displays customizable dialog windows. 11959 //>>docs: http://api.jqueryui.com/dialog/ 11960 //>>demos: http://jqueryui.com/dialog/ 11961 //>>css.structure: ../../themes/base/core.css 11962 //>>css.structure: ../../themes/base/dialog.css 11963 //>>css.theme: ../../themes/base/theme.css 11964 11965 11966 11967 $.widget( "ui.dialog", { 11968 version: "1.12.1", 11969 options: { 11970 appendTo: "body", 11971 autoOpen: true, 11972 buttons: [], 11973 classes: { 11974 "ui-dialog": "ui-corner-all", 11975 "ui-dialog-titlebar": "ui-corner-all" 11976 }, 11977 closeOnEscape: true, 11978 closeText: "Close", 11979 draggable: true, 11980 hide: null, 11981 height: "auto", 11982 maxHeight: null, 11983 maxWidth: null, 11984 minHeight: 150, 11985 minWidth: 150, 11986 modal: false, 11987 position: { 11988 my: "center", 11989 at: "center", 11990 of: window, 11991 collision: "fit", 11992 11993 // Ensure the titlebar is always visible 11994 using: function( pos ) { 11995 var topOffset = $( this ).css( pos ).offset().top; 11996 if ( topOffset < 0 ) { 11997 $( this ).css( "top", pos.top - topOffset ); 11998 } 11999 } 12000 }, 12001 resizable: true, 12002 show: null, 12003 title: null, 12004 width: 300, 12005 12006 // Callbacks 12007 beforeClose: null, 12008 close: null, 12009 drag: null, 12010 dragStart: null, 12011 dragStop: null, 12012 focus: null, 12013 open: null, 12014 resize: null, 12015 resizeStart: null, 12016 resizeStop: null 12017 }, 12018 12019 sizeRelatedOptions: { 12020 buttons: true, 12021 height: true, 12022 maxHeight: true, 12023 maxWidth: true, 12024 minHeight: true, 12025 minWidth: true, 12026 width: true 12027 }, 12028 12029 resizableRelatedOptions: { 12030 maxHeight: true, 12031 maxWidth: true, 12032 minHeight: true, 12033 minWidth: true 12034 }, 12035 12036 _create: function() { 12037 this.originalCss = { 12038 display: this.element[ 0 ].style.display, 12039 width: this.element[ 0 ].style.width, 12040 minHeight: this.element[ 0 ].style.minHeight, 12041 maxHeight: this.element[ 0 ].style.maxHeight, 12042 height: this.element[ 0 ].style.height 12043 }; 12044 this.originalPosition = { 12045 parent: this.element.parent(), 12046 index: this.element.parent().children().index( this.element ) 12047 }; 12048 this.originalTitle = this.element.attr( "title" ); 12049 if ( this.options.title == null && this.originalTitle != null ) { 12050 this.options.title = this.originalTitle; 12051 } 12052 12053 // Dialogs can't be disabled 12054 if ( this.options.disabled ) { 12055 this.options.disabled = false; 12056 } 12057 12058 this._createWrapper(); 12059 12060 this.element 12061 .show() 12062 .removeAttr( "title" ) 12063 .appendTo( this.uiDialog ); 12064 12065 this._addClass( "ui-dialog-content", "ui-widget-content" ); 12066 12067 this._createTitlebar(); 12068 this._createButtonPane(); 12069 12070 if ( this.options.draggable && $.fn.draggable ) { 12071 this._makeDraggable(); 12072 } 12073 if ( this.options.resizable && $.fn.resizable ) { 12074 this._makeResizable(); 12075 } 12076 12077 this._isOpen = false; 12078 12079 this._trackFocus(); 12080 }, 12081 12082 _init: function() { 12083 if ( this.options.autoOpen ) { 12084 this.open(); 12085 } 12086 }, 12087 12088 _appendTo: function() { 12089 var element = this.options.appendTo; 12090 if ( element && ( element.jquery || element.nodeType ) ) { 12091 return $( element ); 12092 } 12093 return this.document.find( element || "body" ).eq( 0 ); 12094 }, 12095 12096 _destroy: function() { 12097 var next, 12098 originalPosition = this.originalPosition; 12099 12100 this._untrackInstance(); 12101 this._destroyOverlay(); 12102 12103 this.element 12104 .removeUniqueId() 12105 .css( this.originalCss ) 12106 12107 // Without detaching first, the following becomes really slow 12108 .detach(); 12109 12110 this.uiDialog.remove(); 12111 12112 if ( this.originalTitle ) { 12113 this.element.attr( "title", this.originalTitle ); 12114 } 12115 12116 next = originalPosition.parent.children().eq( originalPosition.index ); 12117 12118 // Don't try to place the dialog next to itself (#8613) 12119 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { 12120 next.before( this.element ); 12121 } else { 12122 originalPosition.parent.append( this.element ); 12123 } 12124 }, 12125 12126 widget: function() { 12127 return this.uiDialog; 12128 }, 12129 12130 disable: $.noop, 12131 enable: $.noop, 12132 12133 close: function( event ) { 12134 var that = this; 12135 12136 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { 12137 return; 12138 } 12139 12140 this._isOpen = false; 12141 this._focusedElement = null; 12142 this._destroyOverlay(); 12143 this._untrackInstance(); 12144 12145 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) { 12146 12147 // Hiding a focused element doesn't trigger blur in WebKit 12148 // so in case we have nothing to focus on, explicitly blur the active element 12149 // https://bugs.webkit.org/show_bug.cgi?id=47182 12150 $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) ); 12151 } 12152 12153 this._hide( this.uiDialog, this.options.hide, function() { 12154 that._trigger( "close", event ); 12155 } ); 12156 }, 12157 12158 isOpen: function() { 12159 return this._isOpen; 12160 }, 12161 12162 moveToTop: function() { 12163 this._moveToTop(); 12164 }, 12165 12166 _moveToTop: function( event, silent ) { 12167 var moved = false, 12168 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() { 12169 return +$( this ).css( "z-index" ); 12170 } ).get(), 12171 zIndexMax = Math.max.apply( null, zIndices ); 12172 12173 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { 12174 this.uiDialog.css( "z-index", zIndexMax + 1 ); 12175 moved = true; 12176 } 12177 12178 if ( moved && !silent ) { 12179 this._trigger( "focus", event ); 12180 } 12181 return moved; 12182 }, 12183 12184 open: function() { 12185 var that = this; 12186 if ( this._isOpen ) { 12187 if ( this._moveToTop() ) { 12188 this._focusTabbable(); 12189 } 12190 return; 12191 } 12192 12193 this._isOpen = true; 12194 this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) ); 12195 12196 this._size(); 12197 this._position(); 12198 this._createOverlay(); 12199 this._moveToTop( null, true ); 12200 12201 // Ensure the overlay is moved to the top with the dialog, but only when 12202 // opening. The overlay shouldn't move after the dialog is open so that 12203 // modeless dialogs opened after the modal dialog stack properly. 12204 if ( this.overlay ) { 12205 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); 12206 } 12207 12208 this._show( this.uiDialog, this.options.show, function() { 12209 that._focusTabbable(); 12210 that._trigger( "focus" ); 12211 } ); 12212 12213 // Track the dialog immediately upon openening in case a focus event 12214 // somehow occurs outside of the dialog before an element inside the 12215 // dialog is focused (#10152) 12216 this._makeFocusTarget(); 12217 12218 this._trigger( "open" ); 12219 }, 12220 12221 _focusTabbable: function() { 12222 12223 // Set focus to the first match: 12224 // 1. An element that was focused previously 12225 // 2. First element inside the dialog matching [autofocus] 12226 // 3. Tabbable element inside the content element 12227 // 4. Tabbable element inside the buttonpane 12228 // 5. The close button 12229 // 6. The dialog itself 12230 var hasFocus = this._focusedElement; 12231 if ( !hasFocus ) { 12232 hasFocus = this.element.find( "[autofocus]" ); 12233 } 12234 if ( !hasFocus.length ) { 12235 hasFocus = this.element.find( ":tabbable" ); 12236 } 12237 if ( !hasFocus.length ) { 12238 hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); 12239 } 12240 if ( !hasFocus.length ) { 12241 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); 12242 } 12243 if ( !hasFocus.length ) { 12244 hasFocus = this.uiDialog; 12245 } 12246 hasFocus.eq( 0 ).trigger( "focus" ); 12247 }, 12248 12249 _keepFocus: function( event ) { 12250 function checkFocus() { 12251 var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ), 12252 isActive = this.uiDialog[ 0 ] === activeElement || 12253 $.contains( this.uiDialog[ 0 ], activeElement ); 12254 if ( !isActive ) { 12255 this._focusTabbable(); 12256 } 12257 } 12258 event.preventDefault(); 12259 checkFocus.call( this ); 12260 12261 // support: IE 12262 // IE <= 8 doesn't prevent moving focus even with event.preventDefault() 12263 // so we check again later 12264 this._delay( checkFocus ); 12265 }, 12266 12267 _createWrapper: function() { 12268 this.uiDialog = $( "<div>" ) 12269 .hide() 12270 .attr( { 12271 12272 // Setting tabIndex makes the div focusable 12273 tabIndex: -1, 12274 role: "dialog" 12275 } ) 12276 .appendTo( this._appendTo() ); 12277 12278 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" ); 12279 this._on( this.uiDialog, { 12280 keydown: function( event ) { 12281 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 12282 event.keyCode === $.ui.keyCode.ESCAPE ) { 12283 event.preventDefault(); 12284 this.close( event ); 12285 return; 12286 } 12287 12288 // Prevent tabbing out of dialogs 12289 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { 12290 return; 12291 } 12292 var tabbables = this.uiDialog.find( ":tabbable" ), 12293 first = tabbables.filter( ":first" ), 12294 last = tabbables.filter( ":last" ); 12295 12296 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) && 12297 !event.shiftKey ) { 12298 this._delay( function() { 12299 first.trigger( "focus" ); 12300 } ); 12301 event.preventDefault(); 12302 } else if ( ( event.target === first[ 0 ] || 12303 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) { 12304 this._delay( function() { 12305 last.trigger( "focus" ); 12306 } ); 12307 event.preventDefault(); 12308 } 12309 }, 12310 mousedown: function( event ) { 12311 if ( this._moveToTop( event ) ) { 12312 this._focusTabbable(); 12313 } 12314 } 12315 } ); 12316 12317 // We assume that any existing aria-describedby attribute means 12318 // that the dialog content is marked up properly 12319 // otherwise we brute force the content as the description 12320 if ( !this.element.find( "[aria-describedby]" ).length ) { 12321 this.uiDialog.attr( { 12322 "aria-describedby": this.element.uniqueId().attr( "id" ) 12323 } ); 12324 } 12325 }, 12326 12327 _createTitlebar: function() { 12328 var uiDialogTitle; 12329 12330 this.uiDialogTitlebar = $( "<div>" ); 12331 this._addClass( this.uiDialogTitlebar, 12332 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" ); 12333 this._on( this.uiDialogTitlebar, { 12334 mousedown: function( event ) { 12335 12336 // Don't prevent click on close button (#8838) 12337 // Focusing a dialog that is partially scrolled out of view 12338 // causes the browser to scroll it into view, preventing the click event 12339 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { 12340 12341 // Dialog isn't getting focus when dragging (#8063) 12342 this.uiDialog.trigger( "focus" ); 12343 } 12344 } 12345 } ); 12346 12347 // Support: IE 12348 // Use type="button" to prevent enter keypresses in textboxes from closing the 12349 // dialog in IE (#9312) 12350 this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) 12351 .button( { 12352 label: $( "<a>" ).text( this.options.closeText ).html(), 12353 icon: "ui-icon-closethick", 12354 showLabel: false 12355 } ) 12356 .appendTo( this.uiDialogTitlebar ); 12357 12358 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" ); 12359 this._on( this.uiDialogTitlebarClose, { 12360 click: function( event ) { 12361 event.preventDefault(); 12362 this.close( event ); 12363 } 12364 } ); 12365 12366 uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar ); 12367 this._addClass( uiDialogTitle, "ui-dialog-title" ); 12368 this._title( uiDialogTitle ); 12369 12370 this.uiDialogTitlebar.prependTo( this.uiDialog ); 12371 12372 this.uiDialog.attr( { 12373 "aria-labelledby": uiDialogTitle.attr( "id" ) 12374 } ); 12375 }, 12376 12377 _title: function( title ) { 12378 if ( this.options.title ) { 12379 title.text( this.options.title ); 12380 } else { 12381 title.html( " " ); 12382 } 12383 }, 12384 12385 _createButtonPane: function() { 12386 this.uiDialogButtonPane = $( "<div>" ); 12387 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane", 12388 "ui-widget-content ui-helper-clearfix" ); 12389 12390 this.uiButtonSet = $( "<div>" ) 12391 .appendTo( this.uiDialogButtonPane ); 12392 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" ); 12393 12394 this._createButtons(); 12395 }, 12396 12397 _createButtons: function() { 12398 var that = this, 12399 buttons = this.options.buttons; 12400 12401 // If we already have a button pane, remove it 12402 this.uiDialogButtonPane.remove(); 12403 this.uiButtonSet.empty(); 12404 12405 if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) { 12406 this._removeClass( this.uiDialog, "ui-dialog-buttons" ); 12407 return; 12408 } 12409 12410 $.each( buttons, function( name, props ) { 12411 var click, buttonOptions; 12412 props = $.isFunction( props ) ? 12413 { click: props, text: name } : 12414 props; 12415 12416 // Default to a non-submitting button 12417 props = $.extend( { type: "button" }, props ); 12418 12419 // Change the context for the click callback to be the main element 12420 click = props.click; 12421 buttonOptions = { 12422 icon: props.icon, 12423 iconPosition: props.iconPosition, 12424 showLabel: props.showLabel, 12425 12426 // Deprecated options 12427 icons: props.icons, 12428 text: props.text 12429 }; 12430 12431 delete props.click; 12432 delete props.icon; 12433 delete props.iconPosition; 12434 delete props.showLabel; 12435 12436 // Deprecated options 12437 delete props.icons; 12438 if ( typeof props.text === "boolean" ) { 12439 delete props.text; 12440 } 12441 12442 $( "<button></button>", props ) 12443 .button( buttonOptions ) 12444 .appendTo( that.uiButtonSet ) 12445 .on( "click", function() { 12446 click.apply( that.element[ 0 ], arguments ); 12447 } ); 12448 } ); 12449 this._addClass( this.uiDialog, "ui-dialog-buttons" ); 12450 this.uiDialogButtonPane.appendTo( this.uiDialog ); 12451 }, 12452 12453 _makeDraggable: function() { 12454 var that = this, 12455 options = this.options; 12456 12457 function filteredUi( ui ) { 12458 return { 12459 position: ui.position, 12460 offset: ui.offset 12461 }; 12462 } 12463 12464 this.uiDialog.draggable( { 12465 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", 12466 handle: ".ui-dialog-titlebar", 12467 containment: "document", 12468 start: function( event, ui ) { 12469 that._addClass( $( this ), "ui-dialog-dragging" ); 12470 that._blockFrames(); 12471 that._trigger( "dragStart", event, filteredUi( ui ) ); 12472 }, 12473 drag: function( event, ui ) { 12474 that._trigger( "drag", event, filteredUi( ui ) ); 12475 }, 12476 stop: function( event, ui ) { 12477 var left = ui.offset.left - that.document.scrollLeft(), 12478 top = ui.offset.top - that.document.scrollTop(); 12479 12480 options.position = { 12481 my: "left top", 12482 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12483 "top" + ( top >= 0 ? "+" : "" ) + top, 12484 of: that.window 12485 }; 12486 that._removeClass( $( this ), "ui-dialog-dragging" ); 12487 that._unblockFrames(); 12488 that._trigger( "dragStop", event, filteredUi( ui ) ); 12489 } 12490 } ); 12491 }, 12492 12493 _makeResizable: function() { 12494 var that = this, 12495 options = this.options, 12496 handles = options.resizable, 12497 12498 // .ui-resizable has position: relative defined in the stylesheet 12499 // but dialogs have to use absolute or fixed positioning 12500 position = this.uiDialog.css( "position" ), 12501 resizeHandles = typeof handles === "string" ? 12502 handles : 12503 "n,e,s,w,se,sw,ne,nw"; 12504 12505 function filteredUi( ui ) { 12506 return { 12507 originalPosition: ui.originalPosition, 12508 originalSize: ui.originalSize, 12509 position: ui.position, 12510 size: ui.size 12511 }; 12512 } 12513 12514 this.uiDialog.resizable( { 12515 cancel: ".ui-dialog-content", 12516 containment: "document", 12517 alsoResize: this.element, 12518 maxWidth: options.maxWidth, 12519 maxHeight: options.maxHeight, 12520 minWidth: options.minWidth, 12521 minHeight: this._minHeight(), 12522 handles: resizeHandles, 12523 start: function( event, ui ) { 12524 that._addClass( $( this ), "ui-dialog-resizing" ); 12525 that._blockFrames(); 12526 that._trigger( "resizeStart", event, filteredUi( ui ) ); 12527 }, 12528 resize: function( event, ui ) { 12529 that._trigger( "resize", event, filteredUi( ui ) ); 12530 }, 12531 stop: function( event, ui ) { 12532 var offset = that.uiDialog.offset(), 12533 left = offset.left - that.document.scrollLeft(), 12534 top = offset.top - that.document.scrollTop(); 12535 12536 options.height = that.uiDialog.height(); 12537 options.width = that.uiDialog.width(); 12538 options.position = { 12539 my: "left top", 12540 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12541 "top" + ( top >= 0 ? "+" : "" ) + top, 12542 of: that.window 12543 }; 12544 that._removeClass( $( this ), "ui-dialog-resizing" ); 12545 that._unblockFrames(); 12546 that._trigger( "resizeStop", event, filteredUi( ui ) ); 12547 } 12548 } ) 12549 .css( "position", position ); 12550 }, 12551 12552 _trackFocus: function() { 12553 this._on( this.widget(), { 12554 focusin: function( event ) { 12555 this._makeFocusTarget(); 12556 this._focusedElement = $( event.target ); 12557 } 12558 } ); 12559 }, 12560 12561 _makeFocusTarget: function() { 12562 this._untrackInstance(); 12563 this._trackingInstances().unshift( this ); 12564 }, 12565 12566 _untrackInstance: function() { 12567 var instances = this._trackingInstances(), 12568 exists = $.inArray( this, instances ); 12569 if ( exists !== -1 ) { 12570 instances.splice( exists, 1 ); 12571 } 12572 }, 12573 12574 _trackingInstances: function() { 12575 var instances = this.document.data( "ui-dialog-instances" ); 12576 if ( !instances ) { 12577 instances = []; 12578 this.document.data( "ui-dialog-instances", instances ); 12579 } 12580 return instances; 12581 }, 12582 12583 _minHeight: function() { 12584 var options = this.options; 12585 12586 return options.height === "auto" ? 12587 options.minHeight : 12588 Math.min( options.minHeight, options.height ); 12589 }, 12590 12591 _position: function() { 12592 12593 // Need to show the dialog to get the actual offset in the position plugin 12594 var isVisible = this.uiDialog.is( ":visible" ); 12595 if ( !isVisible ) { 12596 this.uiDialog.show(); 12597 } 12598 this.uiDialog.position( this.options.position ); 12599 if ( !isVisible ) { 12600 this.uiDialog.hide(); 12601 } 12602 }, 12603 12604 _setOptions: function( options ) { 12605 var that = this, 12606 resize = false, 12607 resizableOptions = {}; 12608 12609 $.each( options, function( key, value ) { 12610 that._setOption( key, value ); 12611 12612 if ( key in that.sizeRelatedOptions ) { 12613 resize = true; 12614 } 12615 if ( key in that.resizableRelatedOptions ) { 12616 resizableOptions[ key ] = value; 12617 } 12618 } ); 12619 12620 if ( resize ) { 12621 this._size(); 12622 this._position(); 12623 } 12624 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12625 this.uiDialog.resizable( "option", resizableOptions ); 12626 } 12627 }, 12628 12629 _setOption: function( key, value ) { 12630 var isDraggable, isResizable, 12631 uiDialog = this.uiDialog; 12632 12633 if ( key === "disabled" ) { 12634 return; 12635 } 12636 12637 this._super( key, value ); 12638 12639 if ( key === "appendTo" ) { 12640 this.uiDialog.appendTo( this._appendTo() ); 12641 } 12642 12643 if ( key === "buttons" ) { 12644 this._createButtons(); 12645 } 12646 12647 if ( key === "closeText" ) { 12648 this.uiDialogTitlebarClose.button( { 12649 12650 // Ensure that we always pass a string 12651 label: $( "<a>" ).text( "" + this.options.closeText ).html() 12652 } ); 12653 } 12654 12655 if ( key === "draggable" ) { 12656 isDraggable = uiDialog.is( ":data(ui-draggable)" ); 12657 if ( isDraggable && !value ) { 12658 uiDialog.draggable( "destroy" ); 12659 } 12660 12661 if ( !isDraggable && value ) { 12662 this._makeDraggable(); 12663 } 12664 } 12665 12666 if ( key === "position" ) { 12667 this._position(); 12668 } 12669 12670 if ( key === "resizable" ) { 12671 12672 // currently resizable, becoming non-resizable 12673 isResizable = uiDialog.is( ":data(ui-resizable)" ); 12674 if ( isResizable && !value ) { 12675 uiDialog.resizable( "destroy" ); 12676 } 12677 12678 // Currently resizable, changing handles 12679 if ( isResizable && typeof value === "string" ) { 12680 uiDialog.resizable( "option", "handles", value ); 12681 } 12682 12683 // Currently non-resizable, becoming resizable 12684 if ( !isResizable && value !== false ) { 12685 this._makeResizable(); 12686 } 12687 } 12688 12689 if ( key === "title" ) { 12690 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); 12691 } 12692 }, 12693 12694 _size: function() { 12695 12696 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 12697 // divs will both have width and height set, so we need to reset them 12698 var nonContentHeight, minContentHeight, maxContentHeight, 12699 options = this.options; 12700 12701 // Reset content sizing 12702 this.element.show().css( { 12703 width: "auto", 12704 minHeight: 0, 12705 maxHeight: "none", 12706 height: 0 12707 } ); 12708 12709 if ( options.minWidth > options.width ) { 12710 options.width = options.minWidth; 12711 } 12712 12713 // Reset wrapper sizing 12714 // determine the height of all the non-content elements 12715 nonContentHeight = this.uiDialog.css( { 12716 height: "auto", 12717 width: options.width 12718 } ) 12719 .outerHeight(); 12720 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 12721 maxContentHeight = typeof options.maxHeight === "number" ? 12722 Math.max( 0, options.maxHeight - nonContentHeight ) : 12723 "none"; 12724 12725 if ( options.height === "auto" ) { 12726 this.element.css( { 12727 minHeight: minContentHeight, 12728 maxHeight: maxContentHeight, 12729 height: "auto" 12730 } ); 12731 } else { 12732 this.element.height( Math.max( 0, options.height - nonContentHeight ) ); 12733 } 12734 12735 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12736 this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); 12737 } 12738 }, 12739 12740 _blockFrames: function() { 12741 this.iframeBlocks = this.document.find( "iframe" ).map( function() { 12742 var iframe = $( this ); 12743 12744 return $( "<div>" ) 12745 .css( { 12746 position: "absolute", 12747 width: iframe.outerWidth(), 12748 height: iframe.outerHeight() 12749 } ) 12750 .appendTo( iframe.parent() ) 12751 .offset( iframe.offset() )[ 0 ]; 12752 } ); 12753 }, 12754 12755 _unblockFrames: function() { 12756 if ( this.iframeBlocks ) { 12757 this.iframeBlocks.remove(); 12758 delete this.iframeBlocks; 12759 } 12760 }, 12761 12762 _allowInteraction: function( event ) { 12763 if ( $( event.target ).closest( ".ui-dialog" ).length ) { 12764 return true; 12765 } 12766 12767 // TODO: Remove hack when datepicker implements 12768 // the .ui-front logic (#8989) 12769 return !!$( event.target ).closest( ".ui-datepicker" ).length; 12770 }, 12771 12772 _createOverlay: function() { 12773 if ( !this.options.modal ) { 12774 return; 12775 } 12776 12777 // We use a delay in case the overlay is created from an 12778 // event that we're going to be cancelling (#2804) 12779 var isOpening = true; 12780 this._delay( function() { 12781 isOpening = false; 12782 } ); 12783 12784 if ( !this.document.data( "ui-dialog-overlays" ) ) { 12785 12786 // Prevent use of anchors and inputs 12787 // Using _on() for an event handler shared across many instances is 12788 // safe because the dialogs stack and must be closed in reverse order 12789 this._on( this.document, { 12790 focusin: function( event ) { 12791 if ( isOpening ) { 12792 return; 12793 } 12794 12795 if ( !this._allowInteraction( event ) ) { 12796 event.preventDefault(); 12797 this._trackingInstances()[ 0 ]._focusTabbable(); 12798 } 12799 } 12800 } ); 12801 } 12802 12803 this.overlay = $( "<div>" ) 12804 .appendTo( this._appendTo() ); 12805 12806 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" ); 12807 this._on( this.overlay, { 12808 mousedown: "_keepFocus" 12809 } ); 12810 this.document.data( "ui-dialog-overlays", 12811 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 ); 12812 }, 12813 12814 _destroyOverlay: function() { 12815 if ( !this.options.modal ) { 12816 return; 12817 } 12818 12819 if ( this.overlay ) { 12820 var overlays = this.document.data( "ui-dialog-overlays" ) - 1; 12821 12822 if ( !overlays ) { 12823 this._off( this.document, "focusin" ); 12824 this.document.removeData( "ui-dialog-overlays" ); 12825 } else { 12826 this.document.data( "ui-dialog-overlays", overlays ); 12827 } 12828 12829 this.overlay.remove(); 12830 this.overlay = null; 12831 } 12832 } 12833 } ); 12834 12835 // DEPRECATED 12836 // TODO: switch return back to widget declaration at top of file when this is removed 12837 if ( $.uiBackCompat !== false ) { 12838 12839 // Backcompat for dialogClass option 12840 $.widget( "ui.dialog", $.ui.dialog, { 12841 options: { 12842 dialogClass: "" 12843 }, 12844 _createWrapper: function() { 12845 this._super(); 12846 this.uiDialog.addClass( this.options.dialogClass ); 12847 }, 12848 _setOption: function( key, value ) { 12849 if ( key === "dialogClass" ) { 12850 this.uiDialog 12851 .removeClass( this.options.dialogClass ) 12852 .addClass( value ); 12853 } 12854 this._superApply( arguments ); 12855 } 12856 } ); 12857 } 12858 12859 var widgetsDialog = $.ui.dialog; 12860 12861 12862 /*! 12863 * jQuery UI Droppable 1.12.1 12864 * http://jqueryui.com 12865 * 12866 * Copyright jQuery Foundation and other contributors 12867 * Released under the MIT license. 12868 * http://jquery.org/license 12869 */ 12870 12871 //>>label: Droppable 12872 //>>group: Interactions 12873 //>>description: Enables drop targets for draggable elements. 12874 //>>docs: http://api.jqueryui.com/droppable/ 12875 //>>demos: http://jqueryui.com/droppable/ 12876 12877 12878 12879 $.widget( "ui.droppable", { 12880 version: "1.12.1", 12881 widgetEventPrefix: "drop", 12882 options: { 12883 accept: "*", 12884 addClasses: true, 12885 greedy: false, 12886 scope: "default", 12887 tolerance: "intersect", 12888 12889 // Callbacks 12890 activate: null, 12891 deactivate: null, 12892 drop: null, 12893 out: null, 12894 over: null 12895 }, 12896 _create: function() { 12897 12898 var proportions, 12899 o = this.options, 12900 accept = o.accept; 12901 12902 this.isover = false; 12903 this.isout = true; 12904 12905 this.accept = $.isFunction( accept ) ? accept : function( d ) { 12906 return d.is( accept ); 12907 }; 12908 12909 this.proportions = function( /* valueToWrite */ ) { 12910 if ( arguments.length ) { 12911 12912 // Store the droppable's proportions 12913 proportions = arguments[ 0 ]; 12914 } else { 12915 12916 // Retrieve or derive the droppable's proportions 12917 return proportions ? 12918 proportions : 12919 proportions = { 12920 width: this.element[ 0 ].offsetWidth, 12921 height: this.element[ 0 ].offsetHeight 12922 }; 12923 } 12924 }; 12925 12926 this._addToManager( o.scope ); 12927 12928 o.addClasses && this._addClass( "ui-droppable" ); 12929 12930 }, 12931 12932 _addToManager: function( scope ) { 12933 12934 // Add the reference and positions to the manager 12935 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; 12936 $.ui.ddmanager.droppables[ scope ].push( this ); 12937 }, 12938 12939 _splice: function( drop ) { 12940 var i = 0; 12941 for ( ; i < drop.length; i++ ) { 12942 if ( drop[ i ] === this ) { 12943 drop.splice( i, 1 ); 12944 } 12945 } 12946 }, 12947 12948 _destroy: function() { 12949 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 12950 12951 this._splice( drop ); 12952 }, 12953 12954 _setOption: function( key, value ) { 12955 12956 if ( key === "accept" ) { 12957 this.accept = $.isFunction( value ) ? value : function( d ) { 12958 return d.is( value ); 12959 }; 12960 } else if ( key === "scope" ) { 12961 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 12962 12963 this._splice( drop ); 12964 this._addToManager( value ); 12965 } 12966 12967 this._super( key, value ); 12968 }, 12969 12970 _activate: function( event ) { 12971 var draggable = $.ui.ddmanager.current; 12972 12973 this._addActiveClass(); 12974 if ( draggable ) { 12975 this._trigger( "activate", event, this.ui( draggable ) ); 12976 } 12977 }, 12978 12979 _deactivate: function( event ) { 12980 var draggable = $.ui.ddmanager.current; 12981 12982 this._removeActiveClass(); 12983 if ( draggable ) { 12984 this._trigger( "deactivate", event, this.ui( draggable ) ); 12985 } 12986 }, 12987 12988 _over: function( event ) { 12989 12990 var draggable = $.ui.ddmanager.current; 12991 12992 // Bail if draggable and droppable are same element 12993 if ( !draggable || ( draggable.currentItem || 12994 draggable.element )[ 0 ] === this.element[ 0 ] ) { 12995 return; 12996 } 12997 12998 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 12999 draggable.element ) ) ) { 13000 this._addHoverClass(); 13001 this._trigger( "over", event, this.ui( draggable ) ); 13002 } 13003 13004 }, 13005 13006 _out: function( event ) { 13007 13008 var draggable = $.ui.ddmanager.current; 13009 13010 // Bail if draggable and droppable are same element 13011 if ( !draggable || ( draggable.currentItem || 13012 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13013 return; 13014 } 13015 13016 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 13017 draggable.element ) ) ) { 13018 this._removeHoverClass(); 13019 this._trigger( "out", event, this.ui( draggable ) ); 13020 } 13021 13022 }, 13023 13024 _drop: function( event, custom ) { 13025 13026 var draggable = custom || $.ui.ddmanager.current, 13027 childrenIntersection = false; 13028 13029 // Bail if draggable and droppable are same element 13030 if ( !draggable || ( draggable.currentItem || 13031 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13032 return false; 13033 } 13034 13035 this.element 13036 .find( ":data(ui-droppable)" ) 13037 .not( ".ui-draggable-dragging" ) 13038 .each( function() { 13039 var inst = $( this ).droppable( "instance" ); 13040 if ( 13041 inst.options.greedy && 13042 !inst.options.disabled && 13043 inst.options.scope === draggable.options.scope && 13044 inst.accept.call( 13045 inst.element[ 0 ], ( draggable.currentItem || draggable.element ) 13046 ) && 13047 intersect( 13048 draggable, 13049 $.extend( inst, { offset: inst.element.offset() } ), 13050 inst.options.tolerance, event 13051 ) 13052 ) { 13053 childrenIntersection = true; 13054 return false; } 13055 } ); 13056 if ( childrenIntersection ) { 13057 return false; 13058 } 13059 13060 if ( this.accept.call( this.element[ 0 ], 13061 ( draggable.currentItem || draggable.element ) ) ) { 13062 this._removeActiveClass(); 13063 this._removeHoverClass(); 13064 13065 this._trigger( "drop", event, this.ui( draggable ) ); 13066 return this.element; 13067 } 13068 13069 return false; 13070 13071 }, 13072 13073 ui: function( c ) { 13074 return { 13075 draggable: ( c.currentItem || c.element ), 13076 helper: c.helper, 13077 position: c.position, 13078 offset: c.positionAbs 13079 }; 13080 }, 13081 13082 // Extension points just to make backcompat sane and avoid duplicating logic 13083 // TODO: Remove in 1.13 along with call to it below 13084 _addHoverClass: function() { 13085 this._addClass( "ui-droppable-hover" ); 13086 }, 13087 13088 _removeHoverClass: function() { 13089 this._removeClass( "ui-droppable-hover" ); 13090 }, 13091 13092 _addActiveClass: function() { 13093 this._addClass( "ui-droppable-active" ); 13094 }, 13095 13096 _removeActiveClass: function() { 13097 this._removeClass( "ui-droppable-active" ); 13098 } 13099 } ); 13100 13101 var intersect = $.ui.intersect = ( function() { 13102 function isOverAxis( x, reference, size ) { 13103 return ( x >= reference ) && ( x < ( reference + size ) ); 13104 } 13105 13106 return function( draggable, droppable, toleranceMode, event ) { 13107 13108 if ( !droppable.offset ) { 13109 return false; 13110 } 13111 13112 var x1 = ( draggable.positionAbs || 13113 draggable.position.absolute ).left + draggable.margins.left, 13114 y1 = ( draggable.positionAbs || 13115 draggable.position.absolute ).top + draggable.margins.top, 13116 x2 = x1 + draggable.helperProportions.width, 13117 y2 = y1 + draggable.helperProportions.height, 13118 l = droppable.offset.left, 13119 t = droppable.offset.top, 13120 r = l + droppable.proportions().width, 13121 b = t + droppable.proportions().height; 13122 13123 switch ( toleranceMode ) { 13124 case "fit": 13125 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); 13126 case "intersect": 13127 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half 13128 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half 13129 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half 13130 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half 13131 case "pointer": 13132 return isOverAxis( event.pageY, t, droppable.proportions().height ) && 13133 isOverAxis( event.pageX, l, droppable.proportions().width ); 13134 case "touch": 13135 return ( 13136 ( y1 >= t && y1 <= b ) || // Top edge touching 13137 ( y2 >= t && y2 <= b ) || // Bottom edge touching 13138 ( y1 < t && y2 > b ) // Surrounded vertically 13139 ) && ( 13140 ( x1 >= l && x1 <= r ) || // Left edge touching 13141 ( x2 >= l && x2 <= r ) || // Right edge touching 13142 ( x1 < l && x2 > r ) // Surrounded horizontally 13143 ); 13144 default: 13145 return false; 13146 } 13147 }; 13148 } )(); 13149 13150 /* 13151 This manager tracks offsets of draggables and droppables 13152 */ 13153 $.ui.ddmanager = { 13154 current: null, 13155 droppables: { "default": [] }, 13156 prepareOffsets: function( t, event ) { 13157 13158 var i, j, 13159 m = $.ui.ddmanager.droppables[ t.options.scope ] || [], 13160 type = event ? event.type : null, // workaround for #2317 13161 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); 13162 13163 droppablesLoop: for ( i = 0; i < m.length; i++ ) { 13164 13165 // No disabled and non-accepted 13166 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], 13167 ( t.currentItem || t.element ) ) ) ) { 13168 continue; 13169 } 13170 13171 // Filter out elements in the current dragged item 13172 for ( j = 0; j < list.length; j++ ) { 13173 if ( list[ j ] === m[ i ].element[ 0 ] ) { 13174 m[ i ].proportions().height = 0; 13175 continue droppablesLoop; 13176 } 13177 } 13178 13179 m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; 13180 if ( !m[ i ].visible ) { 13181 continue; 13182 } 13183 13184 // Activate the droppable if used directly from draggables 13185 if ( type === "mousedown" ) { 13186 m[ i ]._activate.call( m[ i ], event ); 13187 } 13188 13189 m[ i ].offset = m[ i ].element.offset(); 13190 m[ i ].proportions( { 13191 width: m[ i ].element[ 0 ].offsetWidth, 13192 height: m[ i ].element[ 0 ].offsetHeight 13193 } ); 13194 13195 } 13196 13197 }, 13198 drop: function( draggable, event ) { 13199 13200 var dropped = false; 13201 13202 // Create a copy of the droppables in case the list changes during the drop (#9116) 13203 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { 13204 13205 if ( !this.options ) { 13206 return; 13207 } 13208 if ( !this.options.disabled && this.visible && 13209 intersect( draggable, this, this.options.tolerance, event ) ) { 13210 dropped = this._drop.call( this, event ) || dropped; 13211 } 13212 13213 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], 13214 ( draggable.currentItem || draggable.element ) ) ) { 13215 this.isout = true; 13216 this.isover = false; 13217 this._deactivate.call( this, event ); 13218 } 13219 13220 } ); 13221 return dropped; 13222 13223 }, 13224 dragStart: function( draggable, event ) { 13225 13226 // Listen for scrolling so that if the dragging causes scrolling the position of the 13227 // droppables can be recalculated (see #5003) 13228 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() { 13229 if ( !draggable.options.refreshPositions ) { 13230 $.ui.ddmanager.prepareOffsets( draggable, event ); 13231 } 13232 } ); 13233 }, 13234 drag: function( draggable, event ) { 13235 13236 // If you have a highly dynamic page, you might try this option. It renders positions 13237 // every time you move the mouse. 13238 if ( draggable.options.refreshPositions ) { 13239 $.ui.ddmanager.prepareOffsets( draggable, event ); 13240 } 13241 13242 // Run through all droppables and check their positions based on specific tolerance options 13243 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { 13244 13245 if ( this.options.disabled || this.greedyChild || !this.visible ) { 13246 return; 13247 } 13248 13249 var parentInstance, scope, parent, 13250 intersects = intersect( draggable, this, this.options.tolerance, event ), 13251 c = !intersects && this.isover ? 13252 "isout" : 13253 ( intersects && !this.isover ? "isover" : null ); 13254 if ( !c ) { 13255 return; 13256 } 13257 13258 if ( this.options.greedy ) { 13259 13260 // find droppable parents with same scope 13261 scope = this.options.scope; 13262 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() { 13263 return $( this ).droppable( "instance" ).options.scope === scope; 13264 } ); 13265 13266 if ( parent.length ) { 13267 parentInstance = $( parent[ 0 ] ).droppable( "instance" ); 13268 parentInstance.greedyChild = ( c === "isover" ); 13269 } 13270 } 13271 13272 // We just moved into a greedy child 13273 if ( parentInstance && c === "isover" ) { 13274 parentInstance.isover = false; 13275 parentInstance.isout = true; 13276 parentInstance._out.call( parentInstance, event ); 13277 } 13278 13279 this[ c ] = true; 13280 this[ c === "isout" ? "isover" : "isout" ] = false; 13281 this[ c === "isover" ? "_over" : "_out" ].call( this, event ); 13282 13283 // We just moved out of a greedy child 13284 if ( parentInstance && c === "isout" ) { 13285 parentInstance.isout = false; 13286 parentInstance.isover = true; 13287 parentInstance._over.call( parentInstance, event ); 13288 } 13289 } ); 13290 13291 }, 13292 dragStop: function( draggable, event ) { 13293 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" ); 13294 13295 // Call prepareOffsets one final time since IE does not fire return scroll events when 13296 // overflow was caused by drag (see #5003) 13297 if ( !draggable.options.refreshPositions ) { 13298 $.ui.ddmanager.prepareOffsets( draggable, event ); 13299 } 13300 } 13301 }; 13302 13303 // DEPRECATED 13304 // TODO: switch return back to widget declaration at top of file when this is removed 13305 if ( $.uiBackCompat !== false ) { 13306 13307 // Backcompat for activeClass and hoverClass options 13308 $.widget( "ui.droppable", $.ui.droppable, { 13309 options: { 13310 hoverClass: false, 13311 activeClass: false 13312 }, 13313 _addActiveClass: function() { 13314 this._super(); 13315 if ( this.options.activeClass ) { 13316 this.element.addClass( this.options.activeClass ); 13317 } 13318 }, 13319 _removeActiveClass: function() { 13320 this._super(); 13321 if ( this.options.activeClass ) { 13322 this.element.removeClass( this.options.activeClass ); 13323 } 13324 }, 13325 _addHoverClass: function() { 13326 this._super(); 13327 if ( this.options.hoverClass ) { 13328 this.element.addClass( this.options.hoverClass ); 13329 } 13330 }, 13331 _removeHoverClass: function() { 13332 this._super(); 13333 if ( this.options.hoverClass ) { 13334 this.element.removeClass( this.options.hoverClass ); 13335 } 13336 } 13337 } ); 13338 } 13339 13340 var widgetsDroppable = $.ui.droppable; 13341 13342 13343 /*! 13344 * jQuery UI Progressbar 1.12.1 13345 * http://jqueryui.com 13346 * 13347 * Copyright jQuery Foundation and other contributors 13348 * Released under the MIT license. 13349 * http://jquery.org/license 13350 */ 13351 13352 //>>label: Progressbar 13353 //>>group: Widgets 13354 // jscs:disable maximumLineLength 13355 //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators. 13356 // jscs:enable maximumLineLength 13357 //>>docs: http://api.jqueryui.com/progressbar/ 13358 //>>demos: http://jqueryui.com/progressbar/ 13359 //>>css.structure: ../../themes/base/core.css 13360 //>>css.structure: ../../themes/base/progressbar.css 13361 //>>css.theme: ../../themes/base/theme.css 13362 13363 13364 13365 var widgetsProgressbar = $.widget( "ui.progressbar", { 13366 version: "1.12.1", 13367 options: { 13368 classes: { 13369 "ui-progressbar": "ui-corner-all", 13370 "ui-progressbar-value": "ui-corner-left", 13371 "ui-progressbar-complete": "ui-corner-right" 13372 }, 13373 max: 100, 13374 value: 0, 13375 13376 change: null, 13377 complete: null 13378 }, 13379 13380 min: 0, 13381 13382 _create: function() { 13383 13384 // Constrain initial value 13385 this.oldValue = this.options.value = this._constrainedValue(); 13386 13387 this.element.attr( { 13388 13389 // Only set static values; aria-valuenow and aria-valuemax are 13390 // set inside _refreshValue() 13391 role: "progressbar", 13392 "aria-valuemin": this.min 13393 } ); 13394 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" ); 13395 13396 this.valueDiv = $( "<div>" ).appendTo( this.element ); 13397 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" ); 13398 this._refreshValue(); 13399 }, 13400 13401 _destroy: function() { 13402 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" ); 13403 13404 this.valueDiv.remove(); 13405 }, 13406 13407 value: function( newValue ) { 13408 if ( newValue === undefined ) { 13409 return this.options.value; 13410 } 13411 13412 this.options.value = this._constrainedValue( newValue ); 13413 this._refreshValue(); 13414 }, 13415 13416 _constrainedValue: function( newValue ) { 13417 if ( newValue === undefined ) { 13418 newValue = this.options.value; 13419 } 13420 13421 this.indeterminate = newValue === false; 13422 13423 // Sanitize value 13424 if ( typeof newValue !== "number" ) { 13425 newValue = 0; 13426 } 13427 13428 return this.indeterminate ? false : 13429 Math.min( this.options.max, Math.max( this.min, newValue ) ); 13430 }, 13431 13432 _setOptions: function( options ) { 13433 13434 // Ensure "value" option is set after other values (like max) 13435 var value = options.value; 13436 delete options.value; 13437 13438 this._super( options ); 13439 13440 this.options.value = this._constrainedValue( value ); 13441 this._refreshValue(); 13442 }, 13443 13444 _setOption: function( key, value ) { 13445 if ( key === "max" ) { 13446 13447 // Don't allow a max less than min 13448 value = Math.max( this.min, value ); 13449 } 13450 this._super( key, value ); 13451 }, 13452 13453 _setOptionDisabled: function( value ) { 13454 this._super( value ); 13455 13456 this.element.attr( "aria-disabled", value ); 13457 this._toggleClass( null, "ui-state-disabled", !!value ); 13458 }, 13459 13460 _percentage: function() { 13461 return this.indeterminate ? 13462 100 : 13463 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); 13464 }, 13465 13466 _refreshValue: function() { 13467 var value = this.options.value, 13468 percentage = this._percentage(); 13469 13470 this.valueDiv 13471 .toggle( this.indeterminate || value > this.min ) 13472 .width( percentage.toFixed( 0 ) + "%" ); 13473 13474 this 13475 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null, 13476 value === this.options.max ) 13477 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate ); 13478 13479 if ( this.indeterminate ) { 13480 this.element.removeAttr( "aria-valuenow" ); 13481 if ( !this.overlayDiv ) { 13482 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv ); 13483 this._addClass( this.overlayDiv, "ui-progressbar-overlay" ); 13484 } 13485 } else { 13486 this.element.attr( { 13487 "aria-valuemax": this.options.max, 13488 "aria-valuenow": value 13489 } ); 13490 if ( this.overlayDiv ) { 13491 this.overlayDiv.remove(); 13492 this.overlayDiv = null; 13493 } 13494 } 13495 13496 if ( this.oldValue !== value ) { 13497 this.oldValue = value; 13498 this._trigger( "change" ); 13499 } 13500 if ( value === this.options.max ) { 13501 this._trigger( "complete" ); 13502 } 13503 } 13504 } ); 13505 13506 13507 /*! 13508 * jQuery UI Selectable 1.12.1 13509 * http://jqueryui.com 13510 * 13511 * Copyright jQuery Foundation and other contributors 13512 * Released under the MIT license. 13513 * http://jquery.org/license 13514 */ 13515 13516 //>>label: Selectable 13517 //>>group: Interactions 13518 //>>description: Allows groups of elements to be selected with the mouse. 13519 //>>docs: http://api.jqueryui.com/selectable/ 13520 //>>demos: http://jqueryui.com/selectable/ 13521 //>>css.structure: ../../themes/base/selectable.css 13522 13523 13524 13525 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, { 13526 version: "1.12.1", 13527 options: { 13528 appendTo: "body", 13529 autoRefresh: true, 13530 distance: 0, 13531 filter: "*", 13532 tolerance: "touch", 13533 13534 // Callbacks 13535 selected: null, 13536 selecting: null, 13537 start: null, 13538 stop: null, 13539 unselected: null, 13540 unselecting: null 13541 }, 13542 _create: function() { 13543 var that = this; 13544 13545 this._addClass( "ui-selectable" ); 13546 13547 this.dragged = false; 13548 13549 // Cache selectee children based on filter 13550 this.refresh = function() { 13551 that.elementPos = $( that.element[ 0 ] ).offset(); 13552 that.selectees = $( that.options.filter, that.element[ 0 ] ); 13553 that._addClass( that.selectees, "ui-selectee" ); 13554 that.selectees.each( function() { 13555 var $this = $( this ), 13556 selecteeOffset = $this.offset(), 13557 pos = { 13558 left: selecteeOffset.left - that.elementPos.left, 13559 top: selecteeOffset.top - that.elementPos.top 13560 }; 13561 $.data( this, "selectable-item", { 13562 element: this, 13563 $element: $this, 13564 left: pos.left, 13565 top: pos.top, 13566 right: pos.left + $this.outerWidth(), 13567 bottom: pos.top + $this.outerHeight(), 13568 startselected: false, 13569 selected: $this.hasClass( "ui-selected" ), 13570 selecting: $this.hasClass( "ui-selecting" ), 13571 unselecting: $this.hasClass( "ui-unselecting" ) 13572 } ); 13573 } ); 13574 }; 13575 this.refresh(); 13576 13577 this._mouseInit(); 13578 13579 this.helper = $( "<div>" ); 13580 this._addClass( this.helper, "ui-selectable-helper" ); 13581 }, 13582 13583 _destroy: function() { 13584 this.selectees.removeData( "selectable-item" ); 13585 this._mouseDestroy(); 13586 }, 13587 13588 _mouseStart: function( event ) { 13589 var that = this, 13590 options = this.options; 13591 13592 this.opos = [ event.pageX, event.pageY ]; 13593 this.elementPos = $( this.element[ 0 ] ).offset(); 13594 13595 if ( this.options.disabled ) { 13596 return; 13597 } 13598 13599 this.selectees = $( options.filter, this.element[ 0 ] ); 13600 13601 this._trigger( "start", event ); 13602 13603 $( options.appendTo ).append( this.helper ); 13604 13605 // position helper (lasso) 13606 this.helper.css( { 13607 "left": event.pageX, 13608 "top": event.pageY, 13609 "width": 0, 13610 "height": 0 13611 } ); 13612 13613 if ( options.autoRefresh ) { 13614 this.refresh(); 13615 } 13616 13617 this.selectees.filter( ".ui-selected" ).each( function() { 13618 var selectee = $.data( this, "selectable-item" ); 13619 selectee.startselected = true; 13620 if ( !event.metaKey && !event.ctrlKey ) { 13621 that._removeClass( selectee.$element, "ui-selected" ); 13622 selectee.selected = false; 13623 that._addClass( selectee.$element, "ui-unselecting" ); 13624 selectee.unselecting = true; 13625 13626 // selectable UNSELECTING callback 13627 that._trigger( "unselecting", event, { 13628 unselecting: selectee.element 13629 } ); 13630 } 13631 } ); 13632 13633 $( event.target ).parents().addBack().each( function() { 13634 var doSelect, 13635 selectee = $.data( this, "selectable-item" ); 13636 if ( selectee ) { 13637 doSelect = ( !event.metaKey && !event.ctrlKey ) || 13638 !selectee.$element.hasClass( "ui-selected" ); 13639 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" ) 13640 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" ); 13641 selectee.unselecting = !doSelect; 13642 selectee.selecting = doSelect; 13643 selectee.selected = doSelect; 13644 13645 // selectable (UN)SELECTING callback 13646 if ( doSelect ) { 13647 that._trigger( "selecting", event, { 13648 selecting: selectee.element 13649 } ); 13650 } else { 13651 that._trigger( "unselecting", event, { 13652 unselecting: selectee.element 13653 } ); 13654 } 13655 return false; 13656 } 13657 } ); 13658 13659 }, 13660 13661 _mouseDrag: function( event ) { 13662 13663 this.dragged = true; 13664 13665 if ( this.options.disabled ) { 13666 return; 13667 } 13668 13669 var tmp, 13670 that = this, 13671 options = this.options, 13672 x1 = this.opos[ 0 ], 13673 y1 = this.opos[ 1 ], 13674 x2 = event.pageX, 13675 y2 = event.pageY; 13676 13677 if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; } 13678 if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; } 13679 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } ); 13680 13681 this.selectees.each( function() { 13682 var selectee = $.data( this, "selectable-item" ), 13683 hit = false, 13684 offset = {}; 13685 13686 //prevent helper from being selected if appendTo: selectable 13687 if ( !selectee || selectee.element === that.element[ 0 ] ) { 13688 return; 13689 } 13690 13691 offset.left = selectee.left + that.elementPos.left; 13692 offset.right = selectee.right + that.elementPos.left; 13693 offset.top = selectee.top + that.elementPos.top; 13694 offset.bottom = selectee.bottom + that.elementPos.top; 13695 13696 if ( options.tolerance === "touch" ) { 13697 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 || 13698 offset.bottom < y1 ) ); 13699 } else if ( options.tolerance === "fit" ) { 13700 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 && 13701 offset.bottom < y2 ); 13702 } 13703 13704 if ( hit ) { 13705 13706 // SELECT 13707 if ( selectee.selected ) { 13708 that._removeClass( selectee.$element, "ui-selected" ); 13709 selectee.selected = false; 13710 } 13711 if ( selectee.unselecting ) { 13712 that._removeClass( selectee.$element, "ui-unselecting" ); 13713 selectee.unselecting = false; 13714 } 13715 if ( !selectee.selecting ) { 13716 that._addClass( selectee.$element, "ui-selecting" ); 13717 selectee.selecting = true; 13718 13719 // selectable SELECTING callback 13720 that._trigger( "selecting", event, { 13721 selecting: selectee.element 13722 } ); 13723 } 13724 } else { 13725 13726 // UNSELECT 13727 if ( selectee.selecting ) { 13728 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) { 13729 that._removeClass( selectee.$element, "ui-selecting" ); 13730 selectee.selecting = false; 13731 that._addClass( selectee.$element, "ui-selected" ); 13732 selectee.selected = true; 13733 } else { 13734 that._removeClass( selectee.$element, "ui-selecting" ); 13735 selectee.selecting = false; 13736 if ( selectee.startselected ) { 13737 that._addClass( selectee.$element, "ui-unselecting" ); 13738 selectee.unselecting = true; 13739 } 13740 13741 // selectable UNSELECTING callback 13742 that._trigger( "unselecting", event, { 13743 unselecting: selectee.element 13744 } ); 13745 } 13746 } 13747 if ( selectee.selected ) { 13748 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) { 13749 that._removeClass( selectee.$element, "ui-selected" ); 13750 selectee.selected = false; 13751 13752 that._addClass( selectee.$element, "ui-unselecting" ); 13753 selectee.unselecting = true; 13754 13755 // selectable UNSELECTING callback 13756 that._trigger( "unselecting", event, { 13757 unselecting: selectee.element 13758 } ); 13759 } 13760 } 13761 } 13762 } ); 13763 13764 return false; 13765 }, 13766 13767 _mouseStop: function( event ) { 13768 var that = this; 13769 13770 this.dragged = false; 13771 13772 $( ".ui-unselecting", this.element[ 0 ] ).each( function() { 13773 var selectee = $.data( this, "selectable-item" ); 13774 that._removeClass( selectee.$element, "ui-unselecting" ); 13775 selectee.unselecting = false; 13776 selectee.startselected = false; 13777 that._trigger( "unselected", event, { 13778 unselected: selectee.element 13779 } ); 13780 } ); 13781 $( ".ui-selecting", this.element[ 0 ] ).each( function() { 13782 var selectee = $.data( this, "selectable-item" ); 13783 that._removeClass( selectee.$element, "ui-selecting" ) 13784 ._addClass( selectee.$element, "ui-selected" ); 13785 selectee.selecting = false; 13786 selectee.selected = true; 13787 selectee.startselected = true; 13788 that._trigger( "selected", event, { 13789 selected: selectee.element 13790 } ); 13791 } ); 13792 this._trigger( "stop", event ); 13793 13794 this.helper.remove(); 13795 13796 return false; 13797 } 13798 13799 } ); 13800 13801 13802 /*! 13803 * jQuery UI Selectmenu 1.12.1 13804 * http://jqueryui.com 13805 * 13806 * Copyright jQuery Foundation and other contributors 13807 * Released under the MIT license. 13808 * http://jquery.org/license 13809 */ 13810 13811 //>>label: Selectmenu 13812 //>>group: Widgets 13813 // jscs:disable maximumLineLength 13814 //>>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. 13815 // jscs:enable maximumLineLength 13816 //>>docs: http://api.jqueryui.com/selectmenu/ 13817 //>>demos: http://jqueryui.com/selectmenu/ 13818 //>>css.structure: ../../themes/base/core.css 13819 //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css 13820 //>>css.theme: ../../themes/base/theme.css 13821 13822 13823 13824 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, { 13825 version: "1.12.1", 13826 defaultElement: "<select>", 13827 options: { 13828 appendTo: null, 13829 classes: { 13830 "ui-selectmenu-button-open": "ui-corner-top", 13831 "ui-selectmenu-button-closed": "ui-corner-all" 13832 }, 13833 disabled: null, 13834 icons: { 13835 button: "ui-icon-triangle-1-s" 13836 }, 13837 position: { 13838 my: "left top", 13839 at: "left bottom", 13840 collision: "none" 13841 }, 13842 width: false, 13843 13844 // Callbacks 13845 change: null, 13846 close: null, 13847 focus: null, 13848 open: null, 13849 select: null 13850 }, 13851 13852 _create: function() { 13853 var selectmenuId = this.element.uniqueId().attr( "id" ); 13854 this.ids = { 13855 element: selectmenuId, 13856 button: selectmenuId + "-button", 13857 menu: selectmenuId + "-menu" 13858 }; 13859 13860 this._drawButton(); 13861 this._drawMenu(); 13862 this._bindFormResetHandler(); 13863 13864 this._rendered = false; 13865 this.menuItems = $(); 13866 }, 13867 13868 _drawButton: function() { 13869 var icon, 13870 that = this, 13871 item = this._parseOption( 13872 this.element.find( "option:selected" ), 13873 this.element[ 0 ].selectedIndex 13874 ); 13875 13876 // Associate existing label with the new button 13877 this.labels = this.element.labels().attr( "for", this.ids.button ); 13878 this._on( this.labels, { 13879 click: function( event ) { 13880 this.button.focus(); 13881 event.preventDefault(); 13882 } 13883 } ); 13884 13885 // Hide original select element 13886 this.element.hide(); 13887 13888 // Create button 13889 this.button = $( "<span>", { 13890 tabindex: this.options.disabled ? -1 : 0, 13891 id: this.ids.button, 13892 role: "combobox", 13893 "aria-expanded": "false", 13894 "aria-autocomplete": "list", 13895 "aria-owns": this.ids.menu, 13896 "aria-haspopup": "true", 13897 title: this.element.attr( "title" ) 13898 } ) 13899 .insertAfter( this.element ); 13900 13901 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed", 13902 "ui-button ui-widget" ); 13903 13904 icon = $( "<span>" ).appendTo( this.button ); 13905 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button ); 13906 this.buttonItem = this._renderButtonItem( item ) 13907 .appendTo( this.button ); 13908 13909 if ( this.options.width !== false ) { 13910 this._resizeButton(); 13911 } 13912 13913 this._on( this.button, this._buttonEvents ); 13914 this.button.one( "focusin", function() { 13915 13916 // Delay rendering the menu items until the button receives focus. 13917 // The menu may have already been rendered via a programmatic open. 13918 if ( !that._rendered ) { 13919 that._refreshMenu(); 13920 } 13921 } ); 13922 }, 13923 13924 _drawMenu: function() { 13925 var that = this; 13926 13927 // Create menu 13928 this.menu = $( "<ul>", { 13929 "aria-hidden": "true", 13930 "aria-labelledby": this.ids.button, 13931 id: this.ids.menu 13932 } ); 13933 13934 // Wrap menu 13935 this.menuWrap = $( "<div>" ).append( this.menu ); 13936 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" ); 13937 this.menuWrap.appendTo( this._appendTo() ); 13938 13939 // Initialize menu widget 13940 this.menuInstance = this.menu 13941 .menu( { 13942 classes: { 13943 "ui-menu": "ui-corner-bottom" 13944 }, 13945 role: "listbox", 13946 select: function( event, ui ) { 13947 event.preventDefault(); 13948 13949 // Support: IE8 13950 // If the item was selected via a click, the text selection 13951 // will be destroyed in IE 13952 that._setSelection(); 13953 13954 that._select( ui.item.data( "ui-selectmenu-item" ), event ); 13955 }, 13956 focus: function( event, ui ) { 13957 var item = ui.item.data( "ui-selectmenu-item" ); 13958 13959 // Prevent inital focus from firing and check if its a newly focused item 13960 if ( that.focusIndex != null && item.index !== that.focusIndex ) { 13961 that._trigger( "focus", event, { item: item } ); 13962 if ( !that.isOpen ) { 13963 that._select( item, event ); 13964 } 13965 } 13966 that.focusIndex = item.index; 13967 13968 that.button.attr( "aria-activedescendant", 13969 that.menuItems.eq( item.index ).attr( "id" ) ); 13970 } 13971 } ) 13972 .menu( "instance" ); 13973 13974 // Don't close the menu on mouseleave 13975 this.menuInstance._off( this.menu, "mouseleave" ); 13976 13977 // Cancel the menu's collapseAll on document click 13978 this.menuInstance._closeOnDocumentClick = function() { 13979 return false; 13980 }; 13981 13982 // Selects often contain empty items, but never contain dividers 13983 this.menuInstance._isDivider = function() { 13984 return false; 13985 }; 13986 }, 13987 13988 refresh: function() { 13989 this._refreshMenu(); 13990 this.buttonItem.replaceWith( 13991 this.buttonItem = this._renderButtonItem( 13992 13993 // Fall back to an empty object in case there are no options 13994 this._getSelectedItem().data( "ui-selectmenu-item" ) || {} 13995 ) 13996 ); 13997 if ( this.options.width === null ) { 13998 this._resizeButton(); 13999 } 14000 }, 14001 14002 _refreshMenu: function() { 14003 var item, 14004 options = this.element.find( "option" ); 14005 14006 this.menu.empty(); 14007 14008 this._parseOptions( options ); 14009 this._renderMenu( this.menu, this.items ); 14010 14011 this.menuInstance.refresh(); 14012 this.menuItems = this.menu.find( "li" ) 14013 .not( ".ui-selectmenu-optgroup" ) 14014 .find( ".ui-menu-item-wrapper" ); 14015 14016 this._rendered = true; 14017 14018 if ( !options.length ) { 14019 return; 14020 } 14021 14022 item = this._getSelectedItem(); 14023 14024 // Update the menu to have the correct item focused 14025 this.menuInstance.focus( null, item ); 14026 this._setAria( item.data( "ui-selectmenu-item" ) ); 14027 14028 // Set disabled state 14029 this._setOption( "disabled", this.element.prop( "disabled" ) ); 14030 }, 14031 14032 open: function( event ) { 14033 if ( this.options.disabled ) { 14034 return; 14035 } 14036 14037 // If this is the first time the menu is being opened, render the items 14038 if ( !this._rendered ) { 14039 this._refreshMenu(); 14040 } else { 14041 14042 // Menu clears focus on close, reset focus to selected item 14043 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" ); 14044 this.menuInstance.focus( null, this._getSelectedItem() ); 14045 } 14046 14047 // If there are no options, don't open the menu 14048 if ( !this.menuItems.length ) { 14049 return; 14050 } 14051 14052 this.isOpen = true; 14053 this._toggleAttr(); 14054 this._resizeMenu(); 14055 this._position(); 14056 14057 this._on( this.document, this._documentClick ); 14058 14059 this._trigger( "open", event ); 14060 }, 14061 14062 _position: function() { 14063 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); 14064 }, 14065 14066 close: function( event ) { 14067 if ( !this.isOpen ) { 14068 return; 14069 } 14070 14071 this.isOpen = false; 14072 this._toggleAttr(); 14073 14074 this.range = null; 14075 this._off( this.document ); 14076 14077 this._trigger( "close", event ); 14078 }, 14079 14080 widget: function() { 14081 return this.button; 14082 }, 14083 14084 menuWidget: function() { 14085 return this.menu; 14086 }, 14087 14088 _renderButtonItem: function( item ) { 14089 var buttonItem = $( "<span>" ); 14090 14091 this._setText( buttonItem, item.label ); 14092 this._addClass( buttonItem, "ui-selectmenu-text" ); 14093 14094 return buttonItem; 14095 }, 14096 14097 _renderMenu: function( ul, items ) { 14098 var that = this, 14099 currentOptgroup = ""; 14100 14101 $.each( items, function( index, item ) { 14102 var li; 14103 14104 if ( item.optgroup !== currentOptgroup ) { 14105 li = $( "<li>", { 14106 text: item.optgroup 14107 } ); 14108 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" + 14109 ( item.element.parent( "optgroup" ).prop( "disabled" ) ? 14110 " ui-state-disabled" : 14111 "" ) ); 14112 14113 li.appendTo( ul ); 14114 14115 currentOptgroup = item.optgroup; 14116 } 14117 14118 that._renderItemData( ul, item ); 14119 } ); 14120 }, 14121 14122 _renderItemData: function( ul, item ) { 14123 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); 14124 }, 14125 14126 _renderItem: function( ul, item ) { 14127 var li = $( "<li>" ), 14128 wrapper = $( "<div>", { 14129 title: item.element.attr( "title" ) 14130 } ); 14131 14132 if ( item.disabled ) { 14133 this._addClass( li, null, "ui-state-disabled" ); 14134 } 14135 this._setText( wrapper, item.label ); 14136 14137 return li.append( wrapper ).appendTo( ul ); 14138 }, 14139 14140 _setText: function( element, value ) { 14141 if ( value ) { 14142 element.text( value ); 14143 } else { 14144 element.html( " " ); 14145 } 14146 }, 14147 14148 _move: function( direction, event ) { 14149 var item, next, 14150 filter = ".ui-menu-item"; 14151 14152 if ( this.isOpen ) { 14153 item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14154 } else { 14155 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14156 filter += ":not(.ui-state-disabled)"; 14157 } 14158 14159 if ( direction === "first" || direction === "last" ) { 14160 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); 14161 } else { 14162 next = item[ direction + "All" ]( filter ).eq( 0 ); 14163 } 14164 14165 if ( next.length ) { 14166 this.menuInstance.focus( event, next ); 14167 } 14168 }, 14169 14170 _getSelectedItem: function() { 14171 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14172 }, 14173 14174 _toggle: function( event ) { 14175 this[ this.isOpen ? "close" : "open" ]( event ); 14176 }, 14177 14178 _setSelection: function() { 14179 var selection; 14180 14181 if ( !this.range ) { 14182 return; 14183 } 14184 14185 if ( window.getSelection ) { 14186 selection = window.getSelection(); 14187 selection.removeAllRanges(); 14188 selection.addRange( this.range ); 14189 14190 // Support: IE8 14191 } else { 14192 this.range.select(); 14193 } 14194 14195 // Support: IE 14196 // Setting the text selection kills the button focus in IE, but 14197 // restoring the focus doesn't kill the selection. 14198 this.button.focus(); 14199 }, 14200 14201 _documentClick: { 14202 mousedown: function( event ) { 14203 if ( !this.isOpen ) { 14204 return; 14205 } 14206 14207 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + 14208 $.ui.escapeSelector( this.ids.button ) ).length ) { 14209 this.close( event ); 14210 } 14211 } 14212 }, 14213 14214 _buttonEvents: { 14215 14216 // Prevent text selection from being reset when interacting with the selectmenu (#10144) 14217 mousedown: function() { 14218 var selection; 14219 14220 if ( window.getSelection ) { 14221 selection = window.getSelection(); 14222 if ( selection.rangeCount ) { 14223 this.range = selection.getRangeAt( 0 ); 14224 } 14225 14226 // Support: IE8 14227 } else { 14228 this.range = document.selection.createRange(); 14229 } 14230 }, 14231 14232 click: function( event ) { 14233 this._setSelection(); 14234 this._toggle( event ); 14235 }, 14236 14237 keydown: function( event ) { 14238 var preventDefault = true; 14239 switch ( event.keyCode ) { 14240 case $.ui.keyCode.TAB: 14241 case $.ui.keyCode.ESCAPE: 14242 this.close( event ); 14243 preventDefault = false; 14244 break; 14245 case $.ui.keyCode.ENTER: 14246 if ( this.isOpen ) { 14247 this._selectFocusedItem( event ); 14248 } 14249 break; 14250 case $.ui.keyCode.UP: 14251 if ( event.altKey ) { 14252 this._toggle( event ); 14253 } else { 14254 this._move( "prev", event ); 14255 } 14256 break; 14257 case $.ui.keyCode.DOWN: 14258 if ( event.altKey ) { 14259 this._toggle( event ); 14260 } else { 14261 this._move( "next", event ); 14262 } 14263 break; 14264 case $.ui.keyCode.SPACE: 14265 if ( this.isOpen ) { 14266 this._selectFocusedItem( event ); 14267 } else { 14268 this._toggle( event ); 14269 } 14270 break; 14271 case $.ui.keyCode.LEFT: 14272 this._move( "prev", event ); 14273 break; 14274 case $.ui.keyCode.RIGHT: 14275 this._move( "next", event ); 14276 break; 14277 case $.ui.keyCode.HOME: 14278 case $.ui.keyCode.PAGE_UP: 14279 this._move( "first", event ); 14280 break; 14281 case $.ui.keyCode.END: 14282 case $.ui.keyCode.PAGE_DOWN: 14283 this._move( "last", event ); 14284 break; 14285 default: 14286 this.menu.trigger( event ); 14287 preventDefault = false; 14288 } 14289 14290 if ( preventDefault ) { 14291 event.preventDefault(); 14292 } 14293 } 14294 }, 14295 14296 _selectFocusedItem: function( event ) { 14297 var item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14298 if ( !item.hasClass( "ui-state-disabled" ) ) { 14299 this._select( item.data( "ui-selectmenu-item" ), event ); 14300 } 14301 }, 14302 14303 _select: function( item, event ) { 14304 var oldIndex = this.element[ 0 ].selectedIndex; 14305 14306 // Change native select element 14307 this.element[ 0 ].selectedIndex = item.index; 14308 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) ); 14309 this._setAria( item ); 14310 this._trigger( "select", event, { item: item } ); 14311 14312 if ( item.index !== oldIndex ) { 14313 this._trigger( "change", event, { item: item } ); 14314 } 14315 14316 this.close( event ); 14317 }, 14318 14319 _setAria: function( item ) { 14320 var id = this.menuItems.eq( item.index ).attr( "id" ); 14321 14322 this.button.attr( { 14323 "aria-labelledby": id, 14324 "aria-activedescendant": id 14325 } ); 14326 this.menu.attr( "aria-activedescendant", id ); 14327 }, 14328 14329 _setOption: function( key, value ) { 14330 if ( key === "icons" ) { 14331 var icon = this.button.find( "span.ui-icon" ); 14332 this._removeClass( icon, null, this.options.icons.button ) 14333 ._addClass( icon, null, value.button ); 14334 } 14335 14336 this._super( key, value ); 14337 14338 if ( key === "appendTo" ) { 14339 this.menuWrap.appendTo( this._appendTo() ); 14340 } 14341 14342 if ( key === "width" ) { 14343 this._resizeButton(); 14344 } 14345 }, 14346 14347 _setOptionDisabled: function( value ) { 14348 this._super( value ); 14349 14350 this.menuInstance.option( "disabled", value ); 14351 this.button.attr( "aria-disabled", value ); 14352 this._toggleClass( this.button, null, "ui-state-disabled", value ); 14353 14354 this.element.prop( "disabled", value ); 14355 if ( value ) { 14356 this.button.attr( "tabindex", -1 ); 14357 this.close(); 14358 } else { 14359 this.button.attr( "tabindex", 0 ); 14360 } 14361 }, 14362 14363 _appendTo: function() { 14364 var element = this.options.appendTo; 14365 14366 if ( element ) { 14367 element = element.jquery || element.nodeType ? 14368 $( element ) : 14369 this.document.find( element ).eq( 0 ); 14370 } 14371 14372 if ( !element || !element[ 0 ] ) { 14373 element = this.element.closest( ".ui-front, dialog" ); 14374 } 14375 14376 if ( !element.length ) { 14377 element = this.document[ 0 ].body; 14378 } 14379 14380 return element; 14381 }, 14382 14383 _toggleAttr: function() { 14384 this.button.attr( "aria-expanded", this.isOpen ); 14385 14386 // We can't use two _toggleClass() calls here, because we need to make sure 14387 // we always remove classes first and add them second, otherwise if both classes have the 14388 // same theme class, it will be removed after we add it. 14389 this._removeClass( this.button, "ui-selectmenu-button-" + 14390 ( this.isOpen ? "closed" : "open" ) ) 14391 ._addClass( this.button, "ui-selectmenu-button-" + 14392 ( this.isOpen ? "open" : "closed" ) ) 14393 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen ); 14394 14395 this.menu.attr( "aria-hidden", !this.isOpen ); 14396 }, 14397 14398 _resizeButton: function() { 14399 var width = this.options.width; 14400 14401 // For `width: false`, just remove inline style and stop 14402 if ( width === false ) { 14403 this.button.css( "width", "" ); 14404 return; 14405 } 14406 14407 // For `width: null`, match the width of the original element 14408 if ( width === null ) { 14409 width = this.element.show().outerWidth(); 14410 this.element.hide(); 14411 } 14412 14413 this.button.outerWidth( width ); 14414 }, 14415 14416 _resizeMenu: function() { 14417 this.menu.outerWidth( Math.max( 14418 this.button.outerWidth(), 14419 14420 // Support: IE10 14421 // IE10 wraps long text (possibly a rounding bug) 14422 // so we add 1px to avoid the wrapping 14423 this.menu.width( "" ).outerWidth() + 1 14424 ) ); 14425 }, 14426 14427 _getCreateOptions: function() { 14428 var options = this._super(); 14429 14430 options.disabled = this.element.prop( "disabled" ); 14431 14432 return options; 14433 }, 14434 14435 _parseOptions: function( options ) { 14436 var that = this, 14437 data = []; 14438 options.each( function( index, item ) { 14439 data.push( that._parseOption( $( item ), index ) ); 14440 } ); 14441 this.items = data; 14442 }, 14443 14444 _parseOption: function( option, index ) { 14445 var optgroup = option.parent( "optgroup" ); 14446 14447 return { 14448 element: option, 14449 index: index, 14450 value: option.val(), 14451 label: option.text(), 14452 optgroup: optgroup.attr( "label" ) || "", 14453 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) 14454 }; 14455 }, 14456 14457 _destroy: function() { 14458 this._unbindFormResetHandler(); 14459 this.menuWrap.remove(); 14460 this.button.remove(); 14461 this.element.show(); 14462 this.element.removeUniqueId(); 14463 this.labels.attr( "for", this.ids.element ); 14464 } 14465 } ] ); 14466 14467 14468 /*! 14469 * jQuery UI Slider 1.12.1 14470 * http://jqueryui.com 14471 * 14472 * Copyright jQuery Foundation and other contributors 14473 * Released under the MIT license. 14474 * http://jquery.org/license 14475 */ 14476 14477 //>>label: Slider 14478 //>>group: Widgets 14479 //>>description: Displays a flexible slider with ranges and accessibility via keyboard. 14480 //>>docs: http://api.jqueryui.com/slider/ 14481 //>>demos: http://jqueryui.com/slider/ 14482 //>>css.structure: ../../themes/base/core.css 14483 //>>css.structure: ../../themes/base/slider.css 14484 //>>css.theme: ../../themes/base/theme.css 14485 14486 14487 14488 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, { 14489 version: "1.12.1", 14490 widgetEventPrefix: "slide", 14491 14492 options: { 14493 animate: false, 14494 classes: { 14495 "ui-slider": "ui-corner-all", 14496 "ui-slider-handle": "ui-corner-all", 14497 14498 // Note: ui-widget-header isn't the most fittingly semantic framework class for this 14499 // element, but worked best visually with a variety of themes 14500 "ui-slider-range": "ui-corner-all ui-widget-header" 14501 }, 14502 distance: 0, 14503 max: 100, 14504 min: 0, 14505 orientation: "horizontal", 14506 range: false, 14507 step: 1, 14508 value: 0, 14509 values: null, 14510 14511 // Callbacks 14512 change: null, 14513 slide: null, 14514 start: null, 14515 stop: null 14516 }, 14517 14518 // Number of pages in a slider 14519 // (how many times can you page up/down to go through the whole range) 14520 numPages: 5, 14521 14522 _create: function() { 14523 this._keySliding = false; 14524 this._mouseSliding = false; 14525 this._animateOff = true; 14526 this._handleIndex = null; 14527 this._detectOrientation(); 14528 this._mouseInit(); 14529 this._calculateNewMax(); 14530 14531 this._addClass( "ui-slider ui-slider-" + this.orientation, 14532 "ui-widget ui-widget-content" ); 14533 14534 this._refresh(); 14535 14536 this._animateOff = false; 14537 }, 14538 14539 _refresh: function() { 14540 this._createRange(); 14541 this._createHandles(); 14542 this._setupEvents(); 14543 this._refreshValue(); 14544 }, 14545 14546 _createHandles: function() { 14547 var i, handleCount, 14548 options = this.options, 14549 existingHandles = this.element.find( ".ui-slider-handle" ), 14550 handle = "<span tabindex='0'></span>", 14551 handles = []; 14552 14553 handleCount = ( options.values && options.values.length ) || 1; 14554 14555 if ( existingHandles.length > handleCount ) { 14556 existingHandles.slice( handleCount ).remove(); 14557 existingHandles = existingHandles.slice( 0, handleCount ); 14558 } 14559 14560 for ( i = existingHandles.length; i < handleCount; i++ ) { 14561 handles.push( handle ); 14562 } 14563 14564 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 14565 14566 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" ); 14567 14568 this.handle = this.handles.eq( 0 ); 14569 14570 this.handles.each( function( i ) { 14571 $( this ) 14572 .data( "ui-slider-handle-index", i ) 14573 .attr( "tabIndex", 0 ); 14574 } ); 14575 }, 14576 14577 _createRange: function() { 14578 var options = this.options; 14579 14580 if ( options.range ) { 14581 if ( options.range === true ) { 14582 if ( !options.values ) { 14583 options.values = [ this._valueMin(), this._valueMin() ]; 14584 } else if ( options.values.length && options.values.length !== 2 ) { 14585 options.values = [ options.values[ 0 ], options.values[ 0 ] ]; 14586 } else if ( $.isArray( options.values ) ) { 14587 options.values = options.values.slice( 0 ); 14588 } 14589 } 14590 14591 if ( !this.range || !this.range.length ) { 14592 this.range = $( "<div>" ) 14593 .appendTo( this.element ); 14594 14595 this._addClass( this.range, "ui-slider-range" ); 14596 } else { 14597 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" ); 14598 14599 // Handle range switching from true to min/max 14600 this.range.css( { 14601 "left": "", 14602 "bottom": "" 14603 } ); 14604 } 14605 if ( options.range === "min" || options.range === "max" ) { 14606 this._addClass( this.range, "ui-slider-range-" + options.range ); 14607 } 14608 } else { 14609 if ( this.range ) { 14610 this.range.remove(); 14611 } 14612 this.range = null; 14613 } 14614 }, 14615 14616 _setupEvents: function() { 14617 this._off( this.handles ); 14618 this._on( this.handles, this._handleEvents ); 14619 this._hoverable( this.handles ); 14620 this._focusable( this.handles ); 14621 }, 14622 14623 _destroy: function() { 14624 this.handles.remove(); 14625 if ( this.range ) { 14626 this.range.remove(); 14627 } 14628 14629 this._mouseDestroy(); 14630 }, 14631 14632 _mouseCapture: function( event ) { 14633 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 14634 that = this, 14635 o = this.options; 14636 14637 if ( o.disabled ) { 14638 return false; 14639 } 14640 14641 this.elementSize = { 14642 width: this.element.outerWidth(), 14643 height: this.element.outerHeight() 14644 }; 14645 this.elementOffset = this.element.offset(); 14646 14647 position = { x: event.pageX, y: event.pageY }; 14648 normValue = this._normValueFromMouse( position ); 14649 distance = this._valueMax() - this._valueMin() + 1; 14650 this.handles.each( function( i ) { 14651 var thisDistance = Math.abs( normValue - that.values( i ) ); 14652 if ( ( distance > thisDistance ) || 14653 ( distance === thisDistance && 14654 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) { 14655 distance = thisDistance; 14656 closestHandle = $( this ); 14657 index = i; 14658 } 14659 } ); 14660 14661 allowed = this._start( event, index ); 14662 if ( allowed === false ) { 14663 return false; 14664 } 14665 this._mouseSliding = true; 14666 14667 this._handleIndex = index; 14668 14669 this._addClass( closestHandle, null, "ui-state-active" ); 14670 closestHandle.trigger( "focus" ); 14671 14672 offset = closestHandle.offset(); 14673 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 14674 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 14675 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 14676 top: event.pageY - offset.top - 14677 ( closestHandle.height() / 2 ) - 14678 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) - 14679 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) + 14680 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 ) 14681 }; 14682 14683 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 14684 this._slide( event, index, normValue ); 14685 } 14686 this._animateOff = true; 14687 return true; 14688 }, 14689 14690 _mouseStart: function() { 14691 return true; 14692 }, 14693 14694 _mouseDrag: function( event ) { 14695 var position = { x: event.pageX, y: event.pageY }, 14696 normValue = this._normValueFromMouse( position ); 14697 14698 this._slide( event, this._handleIndex, normValue ); 14699 14700 return false; 14701 }, 14702 14703 _mouseStop: function( event ) { 14704 this._removeClass( this.handles, null, "ui-state-active" ); 14705 this._mouseSliding = false; 14706 14707 this._stop( event, this._handleIndex ); 14708 this._change( event, this._handleIndex ); 14709 14710 this._handleIndex = null; 14711 this._clickOffset = null; 14712 this._animateOff = false; 14713 14714 return false; 14715 }, 14716 14717 _detectOrientation: function() { 14718 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 14719 }, 14720 14721 _normValueFromMouse: function( position ) { 14722 var pixelTotal, 14723 pixelMouse, 14724 percentMouse, 14725 valueTotal, 14726 valueMouse; 14727 14728 if ( this.orientation === "horizontal" ) { 14729 pixelTotal = this.elementSize.width; 14730 pixelMouse = position.x - this.elementOffset.left - 14731 ( this._clickOffset ? this._clickOffset.left : 0 ); 14732 } else { 14733 pixelTotal = this.elementSize.height; 14734 pixelMouse = position.y - this.elementOffset.top - 14735 ( this._clickOffset ? this._clickOffset.top : 0 ); 14736 } 14737 14738 percentMouse = ( pixelMouse / pixelTotal ); 14739 if ( percentMouse > 1 ) { 14740 percentMouse = 1; 14741 } 14742 if ( percentMouse < 0 ) { 14743 percentMouse = 0; 14744 } 14745 if ( this.orientation === "vertical" ) { 14746 percentMouse = 1 - percentMouse; 14747 } 14748 14749 valueTotal = this._valueMax() - this._valueMin(); 14750 valueMouse = this._valueMin() + percentMouse * valueTotal; 14751 14752 return this._trimAlignValue( valueMouse ); 14753 }, 14754 14755 _uiHash: function( index, value, values ) { 14756 var uiHash = { 14757 handle: this.handles[ index ], 14758 handleIndex: index, 14759 value: value !== undefined ? value : this.value() 14760 }; 14761 14762 if ( this._hasMultipleValues() ) { 14763 uiHash.value = value !== undefined ? value : this.values( index ); 14764 uiHash.values = values || this.values(); 14765 } 14766 14767 return uiHash; 14768 }, 14769 14770 _hasMultipleValues: function() { 14771 return this.options.values && this.options.values.length; 14772 }, 14773 14774 _start: function( event, index ) { 14775 return this._trigger( "start", event, this._uiHash( index ) ); 14776 }, 14777 14778 _slide: function( event, index, newVal ) { 14779 var allowed, otherVal, 14780 currentValue = this.value(), 14781 newValues = this.values(); 14782 14783 if ( this._hasMultipleValues() ) { 14784 otherVal = this.values( index ? 0 : 1 ); 14785 currentValue = this.values( index ); 14786 14787 if ( this.options.values.length === 2 && this.options.range === true ) { 14788 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal ); 14789 } 14790 14791 newValues[ index ] = newVal; 14792 } 14793 14794 if ( newVal === currentValue ) { 14795 return; 14796 } 14797 14798 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) ); 14799 14800 // A slide can be canceled by returning false from the slide callback 14801 if ( allowed === false ) { 14802 return; 14803 } 14804 14805 if ( this._hasMultipleValues() ) { 14806 this.values( index, newVal ); 14807 } else { 14808 this.value( newVal ); 14809 } 14810 }, 14811 14812 _stop: function( event, index ) { 14813 this._trigger( "stop", event, this._uiHash( index ) ); 14814 }, 14815 14816 _change: function( event, index ) { 14817 if ( !this._keySliding && !this._mouseSliding ) { 14818 14819 //store the last changed value index for reference when handles overlap 14820 this._lastChangedValue = index; 14821 this._trigger( "change", event, this._uiHash( index ) ); 14822 } 14823 }, 14824 14825 value: function( newValue ) { 14826 if ( arguments.length ) { 14827 this.options.value = this._trimAlignValue( newValue ); 14828 this._refreshValue(); 14829 this._change( null, 0 ); 14830 return; 14831 } 14832 14833 return this._value(); 14834 }, 14835 14836 values: function( index, newValue ) { 14837 var vals, 14838 newValues, 14839 i; 14840 14841 if ( arguments.length > 1 ) { 14842 this.options.values[ index ] = this._trimAlignValue( newValue ); 14843 this._refreshValue(); 14844 this._change( null, index ); 14845 return; 14846 } 14847 14848 if ( arguments.length ) { 14849 if ( $.isArray( arguments[ 0 ] ) ) { 14850 vals = this.options.values; 14851 newValues = arguments[ 0 ]; 14852 for ( i = 0; i < vals.length; i += 1 ) { 14853 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 14854 this._change( null, i ); 14855 } 14856 this._refreshValue(); 14857 } else { 14858 if ( this._hasMultipleValues() ) { 14859 return this._values( index ); 14860 } else { 14861 return this.value(); 14862 } 14863 } 14864 } else { 14865 return this._values(); 14866 } 14867 }, 14868 14869 _setOption: function( key, value ) { 14870 var i, 14871 valsLength = 0; 14872 14873 if ( key === "range" && this.options.range === true ) { 14874 if ( value === "min" ) { 14875 this.options.value = this._values( 0 ); 14876 this.options.values = null; 14877 } else if ( value === "max" ) { 14878 this.options.value = this._values( this.options.values.length - 1 ); 14879 this.options.values = null; 14880 } 14881 } 14882 14883 if ( $.isArray( this.options.values ) ) { 14884 valsLength = this.options.values.length; 14885 } 14886 14887 this._super( key, value ); 14888 14889 switch ( key ) { 14890 case "orientation": 14891 this._detectOrientation(); 14892 this._removeClass( "ui-slider-horizontal ui-slider-vertical" ) 14893 ._addClass( "ui-slider-" + this.orientation ); 14894 this._refreshValue(); 14895 if ( this.options.range ) { 14896 this._refreshRange( value ); 14897 } 14898 14899 // Reset positioning from previous orientation 14900 this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); 14901 break; 14902 case "value": 14903 this._animateOff = true; 14904 this._refreshValue(); 14905 this._change( null, 0 ); 14906 this._animateOff = false; 14907 break; 14908 case "values": 14909 this._animateOff = true; 14910 this._refreshValue(); 14911 14912 // Start from the last handle to prevent unreachable handles (#9046) 14913 for ( i = valsLength - 1; i >= 0; i-- ) { 14914 this._change( null, i ); 14915 } 14916 this._animateOff = false; 14917 break; 14918 case "step": 14919 case "min": 14920 case "max": 14921 this._animateOff = true; 14922 this._calculateNewMax(); 14923 this._refreshValue(); 14924 this._animateOff = false; 14925 break; 14926 case "range": 14927 this._animateOff = true; 14928 this._refresh(); 14929 this._animateOff = false; 14930 break; 14931 } 14932 }, 14933 14934 _setOptionDisabled: function( value ) { 14935 this._super( value ); 14936 14937 this._toggleClass( null, "ui-state-disabled", !!value ); 14938 }, 14939 14940 //internal value getter 14941 // _value() returns value trimmed by min and max, aligned by step 14942 _value: function() { 14943 var val = this.options.value; 14944 val = this._trimAlignValue( val ); 14945 14946 return val; 14947 }, 14948 14949 //internal values getter 14950 // _values() returns array of values trimmed by min and max, aligned by step 14951 // _values( index ) returns single value trimmed by min and max, aligned by step 14952 _values: function( index ) { 14953 var val, 14954 vals, 14955 i; 14956 14957 if ( arguments.length ) { 14958 val = this.options.values[ index ]; 14959 val = this._trimAlignValue( val ); 14960 14961 return val; 14962 } else if ( this._hasMultipleValues() ) { 14963 14964 // .slice() creates a copy of the array 14965 // this copy gets trimmed by min and max and then returned 14966 vals = this.options.values.slice(); 14967 for ( i = 0; i < vals.length; i += 1 ) { 14968 vals[ i ] = this._trimAlignValue( vals[ i ] ); 14969 } 14970 14971 return vals; 14972 } else { 14973 return []; 14974 } 14975 }, 14976 14977 // Returns the step-aligned value that val is closest to, between (inclusive) min and max 14978 _trimAlignValue: function( val ) { 14979 if ( val <= this._valueMin() ) { 14980 return this._valueMin(); 14981 } 14982 if ( val >= this._valueMax() ) { 14983 return this._valueMax(); 14984 } 14985 var step = ( this.options.step > 0 ) ? this.options.step : 1, 14986 valModStep = ( val - this._valueMin() ) % step, 14987 alignValue = val - valModStep; 14988 14989 if ( Math.abs( valModStep ) * 2 >= step ) { 14990 alignValue += ( valModStep > 0 ) ? step : ( -step ); 14991 } 14992 14993 // Since JavaScript has problems with large floats, round 14994 // the final value to 5 digits after the decimal point (see #4124) 14995 return parseFloat( alignValue.toFixed( 5 ) ); 14996 }, 14997 14998 _calculateNewMax: function() { 14999 var max = this.options.max, 15000 min = this._valueMin(), 15001 step = this.options.step, 15002 aboveMin = Math.round( ( max - min ) / step ) * step; 15003 max = aboveMin + min; 15004 if ( max > this.options.max ) { 15005 15006 //If max is not divisible by step, rounding off may increase its value 15007 max -= step; 15008 } 15009 this.max = parseFloat( max.toFixed( this._precision() ) ); 15010 }, 15011 15012 _precision: function() { 15013 var precision = this._precisionOf( this.options.step ); 15014 if ( this.options.min !== null ) { 15015 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 15016 } 15017 return precision; 15018 }, 15019 15020 _precisionOf: function( num ) { 15021 var str = num.toString(), 15022 decimal = str.indexOf( "." ); 15023 return decimal === -1 ? 0 : str.length - decimal - 1; 15024 }, 15025 15026 _valueMin: function() { 15027 return this.options.min; 15028 }, 15029 15030 _valueMax: function() { 15031 return this.max; 15032 }, 15033 15034 _refreshRange: function( orientation ) { 15035 if ( orientation === "vertical" ) { 15036 this.range.css( { "width": "", "left": "" } ); 15037 } 15038 if ( orientation === "horizontal" ) { 15039 this.range.css( { "height": "", "bottom": "" } ); 15040 } 15041 }, 15042 15043 _refreshValue: function() { 15044 var lastValPercent, valPercent, value, valueMin, valueMax, 15045 oRange = this.options.range, 15046 o = this.options, 15047 that = this, 15048 animate = ( !this._animateOff ) ? o.animate : false, 15049 _set = {}; 15050 15051 if ( this._hasMultipleValues() ) { 15052 this.handles.each( function( i ) { 15053 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() - 15054 that._valueMin() ) * 100; 15055 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15056 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15057 if ( that.options.range === true ) { 15058 if ( that.orientation === "horizontal" ) { 15059 if ( i === 0 ) { 15060 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15061 left: valPercent + "%" 15062 }, o.animate ); 15063 } 15064 if ( i === 1 ) { 15065 that.range[ animate ? "animate" : "css" ]( { 15066 width: ( valPercent - lastValPercent ) + "%" 15067 }, { 15068 queue: false, 15069 duration: o.animate 15070 } ); 15071 } 15072 } else { 15073 if ( i === 0 ) { 15074 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15075 bottom: ( valPercent ) + "%" 15076 }, o.animate ); 15077 } 15078 if ( i === 1 ) { 15079 that.range[ animate ? "animate" : "css" ]( { 15080 height: ( valPercent - lastValPercent ) + "%" 15081 }, { 15082 queue: false, 15083 duration: o.animate 15084 } ); 15085 } 15086 } 15087 } 15088 lastValPercent = valPercent; 15089 } ); 15090 } else { 15091 value = this.value(); 15092 valueMin = this._valueMin(); 15093 valueMax = this._valueMax(); 15094 valPercent = ( valueMax !== valueMin ) ? 15095 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 15096 0; 15097 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15098 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15099 15100 if ( oRange === "min" && this.orientation === "horizontal" ) { 15101 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15102 width: valPercent + "%" 15103 }, o.animate ); 15104 } 15105 if ( oRange === "max" && this.orientation === "horizontal" ) { 15106 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15107 width: ( 100 - valPercent ) + "%" 15108 }, o.animate ); 15109 } 15110 if ( oRange === "min" && this.orientation === "vertical" ) { 15111 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15112 height: valPercent + "%" 15113 }, o.animate ); 15114 } 15115 if ( oRange === "max" && this.orientation === "vertical" ) { 15116 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15117 height: ( 100 - valPercent ) + "%" 15118 }, o.animate ); 15119 } 15120 } 15121 }, 15122 15123 _handleEvents: { 15124 keydown: function( event ) { 15125 var allowed, curVal, newVal, step, 15126 index = $( event.target ).data( "ui-slider-handle-index" ); 15127 15128 switch ( event.keyCode ) { 15129 case $.ui.keyCode.HOME: 15130 case $.ui.keyCode.END: 15131 case $.ui.keyCode.PAGE_UP: 15132 case $.ui.keyCode.PAGE_DOWN: 15133 case $.ui.keyCode.UP: 15134 case $.ui.keyCode.RIGHT: 15135 case $.ui.keyCode.DOWN: 15136 case $.ui.keyCode.LEFT: 15137 event.preventDefault(); 15138 if ( !this._keySliding ) { 15139 this._keySliding = true; 15140 this._addClass( $( event.target ), null, "ui-state-active" ); 15141 allowed = this._start( event, index ); 15142 if ( allowed === false ) { 15143 return; 15144 } 15145 } 15146 break; 15147 } 15148 15149 step = this.options.step; 15150 if ( this._hasMultipleValues() ) { 15151 curVal = newVal = this.values( index ); 15152 } else { 15153 curVal = newVal = this.value(); 15154 } 15155 15156 switch ( event.keyCode ) { 15157 case $.ui.keyCode.HOME: 15158 newVal = this._valueMin(); 15159 break; 15160 case $.ui.keyCode.END: 15161 newVal = this._valueMax(); 15162 break; 15163 case $.ui.keyCode.PAGE_UP: 15164 newVal = this._trimAlignValue( 15165 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) 15166 ); 15167 break; 15168 case $.ui.keyCode.PAGE_DOWN: 15169 newVal = this._trimAlignValue( 15170 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); 15171 break; 15172 case $.ui.keyCode.UP: 15173 case $.ui.keyCode.RIGHT: 15174 if ( curVal === this._valueMax() ) { 15175 return; 15176 } 15177 newVal = this._trimAlignValue( curVal + step ); 15178 break; 15179 case $.ui.keyCode.DOWN: 15180 case $.ui.keyCode.LEFT: 15181 if ( curVal === this._valueMin() ) { 15182 return; 15183 } 15184 newVal = this._trimAlignValue( curVal - step ); 15185 break; 15186 } 15187 15188 this._slide( event, index, newVal ); 15189 }, 15190 keyup: function( event ) { 15191 var index = $( event.target ).data( "ui-slider-handle-index" ); 15192 15193 if ( this._keySliding ) { 15194 this._keySliding = false; 15195 this._stop( event, index ); 15196 this._change( event, index ); 15197 this._removeClass( $( event.target ), null, "ui-state-active" ); 15198 } 15199 } 15200 } 15201 } ); 15202 15203 15204 /*! 15205 * jQuery UI Sortable 1.12.1 15206 * http://jqueryui.com 15207 * 15208 * Copyright jQuery Foundation and other contributors 15209 * Released under the MIT license. 15210 * http://jquery.org/license 15211 */ 15212 15213 //>>label: Sortable 15214 //>>group: Interactions 15215 //>>description: Enables items in a list to be sorted using the mouse. 15216 //>>docs: http://api.jqueryui.com/sortable/ 15217 //>>demos: http://jqueryui.com/sortable/ 15218 //>>css.structure: ../../themes/base/sortable.css 15219 15220 15221 15222 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, { 15223 version: "1.12.1", 15224 widgetEventPrefix: "sort", 15225 ready: false, 15226 options: { 15227 appendTo: "parent", 15228 axis: false, 15229 connectWith: false, 15230 containment: false, 15231 cursor: "auto", 15232 cursorAt: false, 15233 dropOnEmpty: true, 15234 forcePlaceholderSize: false, 15235 forceHelperSize: false, 15236 grid: false, 15237 handle: false, 15238 helper: "original", 15239 items: "> *", 15240 opacity: false, 15241 placeholder: false, 15242 revert: false, 15243 scroll: true, 15244 scrollSensitivity: 20, 15245 scrollSpeed: 20, 15246 scope: "default", 15247 tolerance: "intersect", 15248 zIndex: 1000, 15249 15250 // Callbacks 15251 activate: null, 15252 beforeStop: null, 15253 change: null, 15254 deactivate: null, 15255 out: null, 15256 over: null, 15257 receive: null, 15258 remove: null, 15259 sort: null, 15260 start: null, 15261 stop: null, 15262 update: null 15263 }, 15264 15265 _isOverAxis: function( x, reference, size ) { 15266 return ( x >= reference ) && ( x < ( reference + size ) ); 15267 }, 15268 15269 _isFloating: function( item ) { 15270 return ( /left|right/ ).test( item.css( "float" ) ) || 15271 ( /inline|table-cell/ ).test( item.css( "display" ) ); 15272 }, 15273 15274 _create: function() { 15275 this.containerCache = {}; 15276 this._addClass( "ui-sortable" ); 15277 15278 //Get the items 15279 this.refresh(); 15280 15281 //Let's determine the parent's offset 15282 this.offset = this.element.offset(); 15283 15284 //Initialize mouse events for interaction 15285 this._mouseInit(); 15286 15287 this._setHandleClassName(); 15288 15289 //We're ready to go 15290 this.ready = true; 15291 15292 }, 15293 15294 _setOption: function( key, value ) { 15295 this._super( key, value ); 15296 15297 if ( key === "handle" ) { 15298 this._setHandleClassName(); 15299 } 15300 }, 15301 15302 _setHandleClassName: function() { 15303 var that = this; 15304 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" ); 15305 $.each( this.items, function() { 15306 that._addClass( 15307 this.instance.options.handle ? 15308 this.item.find( this.instance.options.handle ) : 15309 this.item, 15310 "ui-sortable-handle" 15311 ); 15312 } ); 15313 }, 15314 15315 _destroy: function() { 15316 this._mouseDestroy(); 15317 15318 for ( var i = this.items.length - 1; i >= 0; i-- ) { 15319 this.items[ i ].item.removeData( this.widgetName + "-item" ); 15320 } 15321 15322 return this; 15323 }, 15324 15325 _mouseCapture: function( event, overrideHandle ) { 15326 var currentItem = null, 15327 validHandle = false, 15328 that = this; 15329 15330 if ( this.reverting ) { 15331 return false; 15332 } 15333 15334 if ( this.options.disabled || this.options.type === "static" ) { 15335 return false; 15336 } 15337 15338 //We have to refresh the items data once first 15339 this._refreshItems( event ); 15340 15341 //Find out if the clicked node (or one of its parents) is a actual item in this.items 15342 $( event.target ).parents().each( function() { 15343 if ( $.data( this, that.widgetName + "-item" ) === that ) { 15344 currentItem = $( this ); 15345 return false; 15346 } 15347 } ); 15348 if ( $.data( event.target, that.widgetName + "-item" ) === that ) { 15349 currentItem = $( event.target ); 15350 } 15351 15352 if ( !currentItem ) { 15353 return false; 15354 } 15355 if ( this.options.handle && !overrideHandle ) { 15356 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() { 15357 if ( this === event.target ) { 15358 validHandle = true; 15359 } 15360 } ); 15361 if ( !validHandle ) { 15362 return false; 15363 } 15364 } 15365 15366 this.currentItem = currentItem; 15367 this._removeCurrentsFromItems(); 15368 return true; 15369 15370 }, 15371 15372 _mouseStart: function( event, overrideHandle, noActivation ) { 15373 15374 var i, body, 15375 o = this.options; 15376 15377 this.currentContainer = this; 15378 15379 //We only need to call refreshPositions, because the refreshItems call has been moved to 15380 // mouseCapture 15381 this.refreshPositions(); 15382 15383 //Create and append the visible helper 15384 this.helper = this._createHelper( event ); 15385 15386 //Cache the helper size 15387 this._cacheHelperProportions(); 15388 15389 /* 15390 * - Position generation - 15391 * This block generates everything position related - it's the core of draggables. 15392 */ 15393 15394 //Cache the margins of the original element 15395 this._cacheMargins(); 15396 15397 //Get the next scrolling parent 15398 this.scrollParent = this.helper.scrollParent(); 15399 15400 //The element's absolute position on the page minus margins 15401 this.offset = this.currentItem.offset(); 15402 this.offset = { 15403 top: this.offset.top - this.margins.top, 15404 left: this.offset.left - this.margins.left 15405 }; 15406 15407 $.extend( this.offset, { 15408 click: { //Where the click happened, relative to the element 15409 left: event.pageX - this.offset.left, 15410 top: event.pageY - this.offset.top 15411 }, 15412 parent: this._getParentOffset(), 15413 15414 // This is a relative to absolute position minus the actual position calculation - 15415 // only used for relative positioned helper 15416 relative: this._getRelativeOffset() 15417 } ); 15418 15419 // Only after we got the offset, we can change the helper's position to absolute 15420 // TODO: Still need to figure out a way to make relative sorting possible 15421 this.helper.css( "position", "absolute" ); 15422 this.cssPosition = this.helper.css( "position" ); 15423 15424 //Generate the original position 15425 this.originalPosition = this._generatePosition( event ); 15426 this.originalPageX = event.pageX; 15427 this.originalPageY = event.pageY; 15428 15429 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 15430 ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) ); 15431 15432 //Cache the former DOM position 15433 this.domPosition = { 15434 prev: this.currentItem.prev()[ 0 ], 15435 parent: this.currentItem.parent()[ 0 ] 15436 }; 15437 15438 // If the helper is not the original, hide the original so it's not playing any role during 15439 // the drag, won't cause anything bad this way 15440 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 15441 this.currentItem.hide(); 15442 } 15443 15444 //Create the placeholder 15445 this._createPlaceholder(); 15446 15447 //Set a containment if given in the options 15448 if ( o.containment ) { 15449 this._setContainment(); 15450 } 15451 15452 if ( o.cursor && o.cursor !== "auto" ) { // cursor option 15453 body = this.document.find( "body" ); 15454 15455 // Support: IE 15456 this.storedCursor = body.css( "cursor" ); 15457 body.css( "cursor", o.cursor ); 15458 15459 this.storedStylesheet = 15460 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body ); 15461 } 15462 15463 if ( o.opacity ) { // opacity option 15464 if ( this.helper.css( "opacity" ) ) { 15465 this._storedOpacity = this.helper.css( "opacity" ); 15466 } 15467 this.helper.css( "opacity", o.opacity ); 15468 } 15469 15470 if ( o.zIndex ) { // zIndex option 15471 if ( this.helper.css( "zIndex" ) ) { 15472 this._storedZIndex = this.helper.css( "zIndex" ); 15473 } 15474 this.helper.css( "zIndex", o.zIndex ); 15475 } 15476 15477 //Prepare scrolling 15478 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15479 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15480 this.overflowOffset = this.scrollParent.offset(); 15481 } 15482 15483 //Call callbacks 15484 this._trigger( "start", event, this._uiHash() ); 15485 15486 //Recache the helper size 15487 if ( !this._preserveHelperProportions ) { 15488 this._cacheHelperProportions(); 15489 } 15490 15491 //Post "activate" events to possible containers 15492 if ( !noActivation ) { 15493 for ( i = this.containers.length - 1; i >= 0; i-- ) { 15494 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 15495 } 15496 } 15497 15498 //Prepare possible droppables 15499 if ( $.ui.ddmanager ) { 15500 $.ui.ddmanager.current = this; 15501 } 15502 15503 if ( $.ui.ddmanager && !o.dropBehaviour ) { 15504 $.ui.ddmanager.prepareOffsets( this, event ); 15505 } 15506 15507 this.dragging = true; 15508 15509 this._addClass( this.helper, "ui-sortable-helper" ); 15510 15511 // Execute the drag once - this causes the helper not to be visiblebefore getting its 15512 // correct position 15513 this._mouseDrag( event ); 15514 return true; 15515 15516 }, 15517 15518 _mouseDrag: function( event ) { 15519 var i, item, itemElement, intersection, 15520 o = this.options, 15521 scrolled = false; 15522 15523 //Compute the helpers position 15524 this.position = this._generatePosition( event ); 15525 this.positionAbs = this._convertPositionTo( "absolute" ); 15526 15527 if ( !this.lastPositionAbs ) { 15528 this.lastPositionAbs = this.positionAbs; 15529 } 15530 15531 //Do scrolling 15532 if ( this.options.scroll ) { 15533 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15534 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15535 15536 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) - 15537 event.pageY < o.scrollSensitivity ) { 15538 this.scrollParent[ 0 ].scrollTop = 15539 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed; 15540 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) { 15541 this.scrollParent[ 0 ].scrollTop = 15542 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed; 15543 } 15544 15545 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) - 15546 event.pageX < o.scrollSensitivity ) { 15547 this.scrollParent[ 0 ].scrollLeft = scrolled = 15548 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed; 15549 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) { 15550 this.scrollParent[ 0 ].scrollLeft = scrolled = 15551 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed; 15552 } 15553 15554 } else { 15555 15556 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) { 15557 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed ); 15558 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) < 15559 o.scrollSensitivity ) { 15560 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed ); 15561 } 15562 15563 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) { 15564 scrolled = this.document.scrollLeft( 15565 this.document.scrollLeft() - o.scrollSpeed 15566 ); 15567 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) < 15568 o.scrollSensitivity ) { 15569 scrolled = this.document.scrollLeft( 15570 this.document.scrollLeft() + o.scrollSpeed 15571 ); 15572 } 15573 15574 } 15575 15576 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 15577 $.ui.ddmanager.prepareOffsets( this, event ); 15578 } 15579 } 15580 15581 //Regenerate the absolute position used for position checks 15582 this.positionAbs = this._convertPositionTo( "absolute" ); 15583 15584 //Set the helper position 15585 if ( !this.options.axis || this.options.axis !== "y" ) { 15586 this.helper[ 0 ].style.left = this.position.left + "px"; 15587 } 15588 if ( !this.options.axis || this.options.axis !== "x" ) { 15589 this.helper[ 0 ].style.top = this.position.top + "px"; 15590 } 15591 15592 //Rearrange 15593 for ( i = this.items.length - 1; i >= 0; i-- ) { 15594 15595 //Cache variables and intersection, continue if no intersection 15596 item = this.items[ i ]; 15597 itemElement = item.item[ 0 ]; 15598 intersection = this._intersectsWithPointer( item ); 15599 if ( !intersection ) { 15600 continue; 15601 } 15602 15603 // Only put the placeholder inside the current Container, skip all 15604 // items from other containers. This works because when moving 15605 // an item from one container to another the 15606 // currentContainer is switched before the placeholder is moved. 15607 // 15608 // Without this, moving items in "sub-sortables" can cause 15609 // the placeholder to jitter between the outer and inner container. 15610 if ( item.instance !== this.currentContainer ) { 15611 continue; 15612 } 15613 15614 // Cannot intersect with itself 15615 // no useless actions that have been done before 15616 // no action if the item moved is the parent of the item checked 15617 if ( itemElement !== this.currentItem[ 0 ] && 15618 this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement && 15619 !$.contains( this.placeholder[ 0 ], itemElement ) && 15620 ( this.options.type === "semi-dynamic" ? 15621 !$.contains( this.element[ 0 ], itemElement ) : 15622 true 15623 ) 15624 ) { 15625 15626 this.direction = intersection === 1 ? "down" : "up"; 15627 15628 if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) { 15629 this._rearrange( event, item ); 15630 } else { 15631 break; 15632 } 15633 15634 this._trigger( "change", event, this._uiHash() ); 15635 break; 15636 } 15637 } 15638 15639 //Post events to containers 15640 this._contactContainers( event ); 15641 15642 //Interconnect with droppables 15643 if ( $.ui.ddmanager ) { 15644 $.ui.ddmanager.drag( this, event ); 15645 } 15646 15647 //Call callbacks 15648 this._trigger( "sort", event, this._uiHash() ); 15649 15650 this.lastPositionAbs = this.positionAbs; 15651 return false; 15652 15653 }, 15654 15655 _mouseStop: function( event, noPropagation ) { 15656 15657 if ( !event ) { 15658 return; 15659 } 15660 15661 //If we are using droppables, inform the manager about the drop 15662 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 15663 $.ui.ddmanager.drop( this, event ); 15664 } 15665 15666 if ( this.options.revert ) { 15667 var that = this, 15668 cur = this.placeholder.offset(), 15669 axis = this.options.axis, 15670 animation = {}; 15671 15672 if ( !axis || axis === "x" ) { 15673 animation.left = cur.left - this.offset.parent.left - this.margins.left + 15674 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15675 0 : 15676 this.offsetParent[ 0 ].scrollLeft 15677 ); 15678 } 15679 if ( !axis || axis === "y" ) { 15680 animation.top = cur.top - this.offset.parent.top - this.margins.top + 15681 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15682 0 : 15683 this.offsetParent[ 0 ].scrollTop 15684 ); 15685 } 15686 this.reverting = true; 15687 $( this.helper ).animate( 15688 animation, 15689 parseInt( this.options.revert, 10 ) || 500, 15690 function() { 15691 that._clear( event ); 15692 } 15693 ); 15694 } else { 15695 this._clear( event, noPropagation ); 15696 } 15697 15698 return false; 15699 15700 }, 15701 15702 cancel: function() { 15703 15704 if ( this.dragging ) { 15705 15706 this._mouseUp( new $.Event( "mouseup", { target: null } ) ); 15707 15708 if ( this.options.helper === "original" ) { 15709 this.currentItem.css( this._storedCSS ); 15710 this._removeClass( this.currentItem, "ui-sortable-helper" ); 15711 } else { 15712 this.currentItem.show(); 15713 } 15714 15715 //Post deactivating events to containers 15716 for ( var i = this.containers.length - 1; i >= 0; i-- ) { 15717 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) ); 15718 if ( this.containers[ i ].containerCache.over ) { 15719 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) ); 15720 this.containers[ i ].containerCache.over = 0; 15721 } 15722 } 15723 15724 } 15725 15726 if ( this.placeholder ) { 15727 15728 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 15729 // it unbinds ALL events from the original node! 15730 if ( this.placeholder[ 0 ].parentNode ) { 15731 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 15732 } 15733 if ( this.options.helper !== "original" && this.helper && 15734 this.helper[ 0 ].parentNode ) { 15735 this.helper.remove(); 15736 } 15737 15738 $.extend( this, { 15739 helper: null, 15740 dragging: false, 15741 reverting: false, 15742 _noFinalSort: null 15743 } ); 15744 15745 if ( this.domPosition.prev ) { 15746 $( this.domPosition.prev ).after( this.currentItem ); 15747 } else { 15748 $( this.domPosition.parent ).prepend( this.currentItem ); 15749 } 15750 } 15751 15752 return this; 15753 15754 }, 15755 15756 serialize: function( o ) { 15757 15758 var items = this._getItemsAsjQuery( o && o.connected ), 15759 str = []; 15760 o = o || {}; 15761 15762 $( items ).each( function() { 15763 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" ) 15764 .match( o.expression || ( /(.+)[\-=_](.+)/ ) ); 15765 if ( res ) { 15766 str.push( 15767 ( o.key || res[ 1 ] + "[]" ) + 15768 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) ); 15769 } 15770 } ); 15771 15772 if ( !str.length && o.key ) { 15773 str.push( o.key + "=" ); 15774 } 15775 15776 return str.join( "&" ); 15777 15778 }, 15779 15780 toArray: function( o ) { 15781 15782 var items = this._getItemsAsjQuery( o && o.connected ), 15783 ret = []; 15784 15785 o = o || {}; 15786 15787 items.each( function() { 15788 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" ); 15789 } ); 15790 return ret; 15791 15792 }, 15793 15794 /* Be careful with the following core functions */ 15795 _intersectsWith: function( item ) { 15796 15797 var x1 = this.positionAbs.left, 15798 x2 = x1 + this.helperProportions.width, 15799 y1 = this.positionAbs.top, 15800 y2 = y1 + this.helperProportions.height, 15801 l = item.left, 15802 r = l + item.width, 15803 t = item.top, 15804 b = t + item.height, 15805 dyClick = this.offset.click.top, 15806 dxClick = this.offset.click.left, 15807 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && 15808 ( y1 + dyClick ) < b ), 15809 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && 15810 ( x1 + dxClick ) < r ), 15811 isOverElement = isOverElementHeight && isOverElementWidth; 15812 15813 if ( this.options.tolerance === "pointer" || 15814 this.options.forcePointerForContainers || 15815 ( this.options.tolerance !== "pointer" && 15816 this.helperProportions[ this.floating ? "width" : "height" ] > 15817 item[ this.floating ? "width" : "height" ] ) 15818 ) { 15819 return isOverElement; 15820 } else { 15821 15822 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half 15823 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half 15824 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half 15825 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half 15826 15827 } 15828 }, 15829 15830 _intersectsWithPointer: function( item ) { 15831 var verticalDirection, horizontalDirection, 15832 isOverElementHeight = ( this.options.axis === "x" ) || 15833 this._isOverAxis( 15834 this.positionAbs.top + this.offset.click.top, item.top, item.height ), 15835 isOverElementWidth = ( this.options.axis === "y" ) || 15836 this._isOverAxis( 15837 this.positionAbs.left + this.offset.click.left, item.left, item.width ), 15838 isOverElement = isOverElementHeight && isOverElementWidth; 15839 15840 if ( !isOverElement ) { 15841 return false; 15842 } 15843 15844 verticalDirection = this._getDragVerticalDirection(); 15845 horizontalDirection = this._getDragHorizontalDirection(); 15846 15847 return this.floating ? 15848 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) 15849 : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) ); 15850 15851 }, 15852 15853 _intersectsWithSides: function( item ) { 15854 15855 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top + 15856 this.offset.click.top, item.top + ( item.height / 2 ), item.height ), 15857 isOverRightHalf = this._isOverAxis( this.positionAbs.left + 15858 this.offset.click.left, item.left + ( item.width / 2 ), item.width ), 15859 verticalDirection = this._getDragVerticalDirection(), 15860 horizontalDirection = this._getDragHorizontalDirection(); 15861 15862 if ( this.floating && horizontalDirection ) { 15863 return ( ( horizontalDirection === "right" && isOverRightHalf ) || 15864 ( horizontalDirection === "left" && !isOverRightHalf ) ); 15865 } else { 15866 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) || 15867 ( verticalDirection === "up" && !isOverBottomHalf ) ); 15868 } 15869 15870 }, 15871 15872 _getDragVerticalDirection: function() { 15873 var delta = this.positionAbs.top - this.lastPositionAbs.top; 15874 return delta !== 0 && ( delta > 0 ? "down" : "up" ); 15875 }, 15876 15877 _getDragHorizontalDirection: function() { 15878 var delta = this.positionAbs.left - this.lastPositionAbs.left; 15879 return delta !== 0 && ( delta > 0 ? "right" : "left" ); 15880 }, 15881 15882 refresh: function( event ) { 15883 this._refreshItems( event ); 15884 this._setHandleClassName(); 15885 this.refreshPositions(); 15886 return this; 15887 }, 15888 15889 _connectWith: function() { 15890 var options = this.options; 15891 return options.connectWith.constructor === String ? 15892 [ options.connectWith ] : 15893 options.connectWith; 15894 }, 15895 15896 _getItemsAsjQuery: function( connected ) { 15897 15898 var i, j, cur, inst, 15899 items = [], 15900 queries = [], 15901 connectWith = this._connectWith(); 15902 15903 if ( connectWith && connected ) { 15904 for ( i = connectWith.length - 1; i >= 0; i-- ) { 15905 cur = $( connectWith[ i ], this.document[ 0 ] ); 15906 for ( j = cur.length - 1; j >= 0; j-- ) { 15907 inst = $.data( cur[ j ], this.widgetFullName ); 15908 if ( inst && inst !== this && !inst.options.disabled ) { 15909 queries.push( [ $.isFunction( inst.options.items ) ? 15910 inst.options.items.call( inst.element ) : 15911 $( inst.options.items, inst.element ) 15912 .not( ".ui-sortable-helper" ) 15913 .not( ".ui-sortable-placeholder" ), inst ] ); 15914 } 15915 } 15916 } 15917 } 15918 15919 queries.push( [ $.isFunction( this.options.items ) ? 15920 this.options.items 15921 .call( this.element, null, { options: this.options, item: this.currentItem } ) : 15922 $( this.options.items, this.element ) 15923 .not( ".ui-sortable-helper" ) 15924 .not( ".ui-sortable-placeholder" ), this ] ); 15925 15926 function addItems() { 15927 items.push( this ); 15928 } 15929 for ( i = queries.length - 1; i >= 0; i-- ) { 15930 queries[ i ][ 0 ].each( addItems ); 15931 } 15932 15933 return $( items ); 15934 15935 }, 15936 15937 _removeCurrentsFromItems: function() { 15938 15939 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" ); 15940 15941 this.items = $.grep( this.items, function( item ) { 15942 for ( var j = 0; j < list.length; j++ ) { 15943 if ( list[ j ] === item.item[ 0 ] ) { 15944 return false; 15945 } 15946 } 15947 return true; 15948 } ); 15949 15950 }, 15951 15952 _refreshItems: function( event ) { 15953 15954 this.items = []; 15955 this.containers = [ this ]; 15956 15957 var i, j, cur, inst, targetData, _queries, item, queriesLength, 15958 items = this.items, 15959 queries = [ [ $.isFunction( this.options.items ) ? 15960 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) : 15961 $( this.options.items, this.element ), this ] ], 15962 connectWith = this._connectWith(); 15963 15964 //Shouldn't be run the first time through due to massive slow-down 15965 if ( connectWith && this.ready ) { 15966 for ( i = connectWith.length - 1; i >= 0; i-- ) { 15967 cur = $( connectWith[ i ], this.document[ 0 ] ); 15968 for ( j = cur.length - 1; j >= 0; j-- ) { 15969 inst = $.data( cur[ j ], this.widgetFullName ); 15970 if ( inst && inst !== this && !inst.options.disabled ) { 15971 queries.push( [ $.isFunction( inst.options.items ) ? 15972 inst.options.items 15973 .call( inst.element[ 0 ], event, { item: this.currentItem } ) : 15974 $( inst.options.items, inst.element ), inst ] ); 15975 this.containers.push( inst ); 15976 } 15977 } 15978 } 15979 } 15980 15981 for ( i = queries.length - 1; i >= 0; i-- ) { 15982 targetData = queries[ i ][ 1 ]; 15983 _queries = queries[ i ][ 0 ]; 15984 15985 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) { 15986 item = $( _queries[ j ] ); 15987 15988 // Data for target checking (mouse manager) 15989 item.data( this.widgetName + "-item", targetData ); 15990 15991 items.push( { 15992 item: item, 15993 instance: targetData, 15994 width: 0, height: 0, 15995 left: 0, top: 0 15996 } ); 15997 } 15998 } 15999 16000 }, 16001 16002 refreshPositions: function( fast ) { 16003 16004 // Determine whether items are being displayed horizontally 16005 this.floating = this.items.length ? 16006 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : 16007 false; 16008 16009 //This has to be redone because due to the item being moved out/into the offsetParent, 16010 // the offsetParent's position will change 16011 if ( this.offsetParent && this.helper ) { 16012 this.offset.parent = this._getParentOffset(); 16013 } 16014 16015 var i, item, t, p; 16016 16017 for ( i = this.items.length - 1; i >= 0; i-- ) { 16018 item = this.items[ i ]; 16019 16020 //We ignore calculating positions of all connected containers when we're not over them 16021 if ( item.instance !== this.currentContainer && this.currentContainer && 16022 item.item[ 0 ] !== this.currentItem[ 0 ] ) { 16023 continue; 16024 } 16025 16026 t = this.options.toleranceElement ? 16027 $( this.options.toleranceElement, item.item ) : 16028 item.item; 16029 16030 if ( !fast ) { 16031 item.width = t.outerWidth(); 16032 item.height = t.outerHeight(); 16033 } 16034 16035 p = t.offset(); 16036 item.left = p.left; 16037 item.top = p.top; 16038 } 16039 16040 if ( this.options.custom && this.options.custom.refreshContainers ) { 16041 this.options.custom.refreshContainers.call( this ); 16042 } else { 16043 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16044 p = this.containers[ i ].element.offset(); 16045 this.containers[ i ].containerCache.left = p.left; 16046 this.containers[ i ].containerCache.top = p.top; 16047 this.containers[ i ].containerCache.width = 16048 this.containers[ i ].element.outerWidth(); 16049 this.containers[ i ].containerCache.height = 16050 this.containers[ i ].element.outerHeight(); 16051 } 16052 } 16053 16054 return this; 16055 }, 16056 16057 _createPlaceholder: function( that ) { 16058 that = that || this; 16059 var className, 16060 o = that.options; 16061 16062 if ( !o.placeholder || o.placeholder.constructor === String ) { 16063 className = o.placeholder; 16064 o.placeholder = { 16065 element: function() { 16066 16067 var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(), 16068 element = $( "<" + nodeName + ">", that.document[ 0 ] ); 16069 16070 that._addClass( element, "ui-sortable-placeholder", 16071 className || that.currentItem[ 0 ].className ) 16072 ._removeClass( element, "ui-sortable-helper" ); 16073 16074 if ( nodeName === "tbody" ) { 16075 that._createTrPlaceholder( 16076 that.currentItem.find( "tr" ).eq( 0 ), 16077 $( "<tr>", that.document[ 0 ] ).appendTo( element ) 16078 ); 16079 } else if ( nodeName === "tr" ) { 16080 that._createTrPlaceholder( that.currentItem, element ); 16081 } else if ( nodeName === "img" ) { 16082 element.attr( "src", that.currentItem.attr( "src" ) ); 16083 } 16084 16085 if ( !className ) { 16086 element.css( "visibility", "hidden" ); 16087 } 16088 16089 return element; 16090 }, 16091 update: function( container, p ) { 16092 16093 // 1. If a className is set as 'placeholder option, we don't force sizes - 16094 // the class is responsible for that 16095 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a 16096 // class name is specified 16097 if ( className && !o.forcePlaceholderSize ) { 16098 return; 16099 } 16100 16101 //If the element doesn't have a actual height by itself (without styles coming 16102 // from a stylesheet), it receives the inline height from the dragged item 16103 if ( !p.height() ) { 16104 p.height( 16105 that.currentItem.innerHeight() - 16106 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) - 16107 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) ); 16108 } 16109 if ( !p.width() ) { 16110 p.width( 16111 that.currentItem.innerWidth() - 16112 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) - 16113 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) ); 16114 } 16115 } 16116 }; 16117 } 16118 16119 //Create the placeholder 16120 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) ); 16121 16122 //Append it after the actual current item 16123 that.currentItem.after( that.placeholder ); 16124 16125 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 16126 o.placeholder.update( that, that.placeholder ); 16127 16128 }, 16129 16130 _createTrPlaceholder: function( sourceTr, targetTr ) { 16131 var that = this; 16132 16133 sourceTr.children().each( function() { 16134 $( "<td> </td>", that.document[ 0 ] ) 16135 .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 16136 .appendTo( targetTr ); 16137 } ); 16138 }, 16139 16140 _contactContainers: function( event ) { 16141 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, 16142 floating, axis, 16143 innermostContainer = null, 16144 innermostIndex = null; 16145 16146 // Get innermost container that intersects with item 16147 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16148 16149 // Never consider a container that's located within the item itself 16150 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) { 16151 continue; 16152 } 16153 16154 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) { 16155 16156 // If we've already found a container and it's more "inner" than this, then continue 16157 if ( innermostContainer && 16158 $.contains( 16159 this.containers[ i ].element[ 0 ], 16160 innermostContainer.element[ 0 ] ) ) { 16161 continue; 16162 } 16163 16164 innermostContainer = this.containers[ i ]; 16165 innermostIndex = i; 16166 16167 } else { 16168 16169 // container doesn't intersect. trigger "out" event if necessary 16170 if ( this.containers[ i ].containerCache.over ) { 16171 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) ); 16172 this.containers[ i ].containerCache.over = 0; 16173 } 16174 } 16175 16176 } 16177 16178 // If no intersecting containers found, return 16179 if ( !innermostContainer ) { 16180 return; 16181 } 16182 16183 // Move the item into the container if it's not there already 16184 if ( this.containers.length === 1 ) { 16185 if ( !this.containers[ innermostIndex ].containerCache.over ) { 16186 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16187 this.containers[ innermostIndex ].containerCache.over = 1; 16188 } 16189 } else { 16190 16191 // When entering a new container, we will find the item with the least distance and 16192 // append our item near it 16193 dist = 10000; 16194 itemWithLeastDistance = null; 16195 floating = innermostContainer.floating || this._isFloating( this.currentItem ); 16196 posProperty = floating ? "left" : "top"; 16197 sizeProperty = floating ? "width" : "height"; 16198 axis = floating ? "pageX" : "pageY"; 16199 16200 for ( j = this.items.length - 1; j >= 0; j-- ) { 16201 if ( !$.contains( 16202 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] ) 16203 ) { 16204 continue; 16205 } 16206 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) { 16207 continue; 16208 } 16209 16210 cur = this.items[ j ].item.offset()[ posProperty ]; 16211 nearBottom = false; 16212 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 16213 nearBottom = true; 16214 } 16215 16216 if ( Math.abs( event[ axis ] - cur ) < dist ) { 16217 dist = Math.abs( event[ axis ] - cur ); 16218 itemWithLeastDistance = this.items[ j ]; 16219 this.direction = nearBottom ? "up" : "down"; 16220 } 16221 } 16222 16223 //Check if dropOnEmpty is enabled 16224 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) { 16225 return; 16226 } 16227 16228 if ( this.currentContainer === this.containers[ innermostIndex ] ) { 16229 if ( !this.currentContainer.containerCache.over ) { 16230 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); 16231 this.currentContainer.containerCache.over = 1; 16232 } 16233 return; 16234 } 16235 16236 itemWithLeastDistance ? 16237 this._rearrange( event, itemWithLeastDistance, null, true ) : 16238 this._rearrange( event, null, this.containers[ innermostIndex ].element, true ); 16239 this._trigger( "change", event, this._uiHash() ); 16240 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) ); 16241 this.currentContainer = this.containers[ innermostIndex ]; 16242 16243 //Update the placeholder 16244 this.options.placeholder.update( this.currentContainer, this.placeholder ); 16245 16246 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16247 this.containers[ innermostIndex ].containerCache.over = 1; 16248 } 16249 16250 }, 16251 16252 _createHelper: function( event ) { 16253 16254 var o = this.options, 16255 helper = $.isFunction( o.helper ) ? 16256 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) : 16257 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem ); 16258 16259 //Add the helper to the DOM if that didn't happen already 16260 if ( !helper.parents( "body" ).length ) { 16261 $( o.appendTo !== "parent" ? 16262 o.appendTo : 16263 this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] ); 16264 } 16265 16266 if ( helper[ 0 ] === this.currentItem[ 0 ] ) { 16267 this._storedCSS = { 16268 width: this.currentItem[ 0 ].style.width, 16269 height: this.currentItem[ 0 ].style.height, 16270 position: this.currentItem.css( "position" ), 16271 top: this.currentItem.css( "top" ), 16272 left: this.currentItem.css( "left" ) 16273 }; 16274 } 16275 16276 if ( !helper[ 0 ].style.width || o.forceHelperSize ) { 16277 helper.width( this.currentItem.width() ); 16278 } 16279 if ( !helper[ 0 ].style.height || o.forceHelperSize ) { 16280 helper.height( this.currentItem.height() ); 16281 } 16282 16283 return helper; 16284 16285 }, 16286 16287 _adjustOffsetFromHelper: function( obj ) { 16288 if ( typeof obj === "string" ) { 16289 obj = obj.split( " " ); 16290 } 16291 if ( $.isArray( obj ) ) { 16292 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 16293 } 16294 if ( "left" in obj ) { 16295 this.offset.click.left = obj.left + this.margins.left; 16296 } 16297 if ( "right" in obj ) { 16298 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 16299 } 16300 if ( "top" in obj ) { 16301 this.offset.click.top = obj.top + this.margins.top; 16302 } 16303 if ( "bottom" in obj ) { 16304 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 16305 } 16306 }, 16307 16308 _getParentOffset: function() { 16309 16310 //Get the offsetParent and cache its position 16311 this.offsetParent = this.helper.offsetParent(); 16312 var po = this.offsetParent.offset(); 16313 16314 // This is a special case where we need to modify a offset calculated on start, since the 16315 // following happened: 16316 // 1. The position of the helper is absolute, so it's position is calculated based on the 16317 // next positioned parent 16318 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 16319 // the document, which means that the scroll is included in the initial calculation of the 16320 // offset of the parent, and never recalculated upon drag 16321 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] && 16322 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 16323 po.left += this.scrollParent.scrollLeft(); 16324 po.top += this.scrollParent.scrollTop(); 16325 } 16326 16327 // This needs to be actually done for all browsers, since pageX/pageY includes this 16328 // information with an ugly IE fix 16329 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body || 16330 ( this.offsetParent[ 0 ].tagName && 16331 this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) { 16332 po = { top: 0, left: 0 }; 16333 } 16334 16335 return { 16336 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 16337 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 16338 }; 16339 16340 }, 16341 16342 _getRelativeOffset: function() { 16343 16344 if ( this.cssPosition === "relative" ) { 16345 var p = this.currentItem.position(); 16346 return { 16347 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 16348 this.scrollParent.scrollTop(), 16349 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 16350 this.scrollParent.scrollLeft() 16351 }; 16352 } else { 16353 return { top: 0, left: 0 }; 16354 } 16355 16356 }, 16357 16358 _cacheMargins: function() { 16359 this.margins = { 16360 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ), 16361 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 ) 16362 }; 16363 }, 16364 16365 _cacheHelperProportions: function() { 16366 this.helperProportions = { 16367 width: this.helper.outerWidth(), 16368 height: this.helper.outerHeight() 16369 }; 16370 }, 16371 16372 _setContainment: function() { 16373 16374 var ce, co, over, 16375 o = this.options; 16376 if ( o.containment === "parent" ) { 16377 o.containment = this.helper[ 0 ].parentNode; 16378 } 16379 if ( o.containment === "document" || o.containment === "window" ) { 16380 this.containment = [ 16381 0 - this.offset.relative.left - this.offset.parent.left, 16382 0 - this.offset.relative.top - this.offset.parent.top, 16383 o.containment === "document" ? 16384 this.document.width() : 16385 this.window.width() - this.helperProportions.width - this.margins.left, 16386 ( o.containment === "document" ? 16387 ( this.document.height() || document.body.parentNode.scrollHeight ) : 16388 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight 16389 ) - this.helperProportions.height - this.margins.top 16390 ]; 16391 } 16392 16393 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) { 16394 ce = $( o.containment )[ 0 ]; 16395 co = $( o.containment ).offset(); 16396 over = ( $( ce ).css( "overflow" ) !== "hidden" ); 16397 16398 this.containment = [ 16399 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) + 16400 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left, 16401 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) + 16402 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top, 16403 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 16404 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) - 16405 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) - 16406 this.helperProportions.width - this.margins.left, 16407 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 16408 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) - 16409 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) - 16410 this.helperProportions.height - this.margins.top 16411 ]; 16412 } 16413 16414 }, 16415 16416 _convertPositionTo: function( d, pos ) { 16417 16418 if ( !pos ) { 16419 pos = this.position; 16420 } 16421 var mod = d === "absolute" ? 1 : -1, 16422 scroll = this.cssPosition === "absolute" && 16423 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16424 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16425 this.offsetParent : 16426 this.scrollParent, 16427 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16428 16429 return { 16430 top: ( 16431 16432 // The absolute mouse position 16433 pos.top + 16434 16435 // Only for relative positioned nodes: Relative offset from element to offset parent 16436 this.offset.relative.top * mod + 16437 16438 // The offsetParent's offset without borders (offset + border) 16439 this.offset.parent.top * mod - 16440 ( ( this.cssPosition === "fixed" ? 16441 -this.scrollParent.scrollTop() : 16442 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod ) 16443 ), 16444 left: ( 16445 16446 // The absolute mouse position 16447 pos.left + 16448 16449 // Only for relative positioned nodes: Relative offset from element to offset parent 16450 this.offset.relative.left * mod + 16451 16452 // The offsetParent's offset without borders (offset + border) 16453 this.offset.parent.left * mod - 16454 ( ( this.cssPosition === "fixed" ? 16455 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : 16456 scroll.scrollLeft() ) * mod ) 16457 ) 16458 }; 16459 16460 }, 16461 16462 _generatePosition: function( event ) { 16463 16464 var top, left, 16465 o = this.options, 16466 pageX = event.pageX, 16467 pageY = event.pageY, 16468 scroll = this.cssPosition === "absolute" && 16469 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16470 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16471 this.offsetParent : 16472 this.scrollParent, 16473 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16474 16475 // This is another very weird special case that only happens for relative elements: 16476 // 1. If the css position is relative 16477 // 2. and the scroll parent is the document or similar to the offset parent 16478 // we have to refresh the relative offset during the scroll so there are no jumps 16479 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16480 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) { 16481 this.offset.relative = this._getRelativeOffset(); 16482 } 16483 16484 /* 16485 * - Position constraining - 16486 * Constrain the position to a mix of grid, containment. 16487 */ 16488 16489 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options 16490 16491 if ( this.containment ) { 16492 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) { 16493 pageX = this.containment[ 0 ] + this.offset.click.left; 16494 } 16495 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) { 16496 pageY = this.containment[ 1 ] + this.offset.click.top; 16497 } 16498 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) { 16499 pageX = this.containment[ 2 ] + this.offset.click.left; 16500 } 16501 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) { 16502 pageY = this.containment[ 3 ] + this.offset.click.top; 16503 } 16504 } 16505 16506 if ( o.grid ) { 16507 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) / 16508 o.grid[ 1 ] ) * o.grid[ 1 ]; 16509 pageY = this.containment ? 16510 ( ( top - this.offset.click.top >= this.containment[ 1 ] && 16511 top - this.offset.click.top <= this.containment[ 3 ] ) ? 16512 top : 16513 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ? 16514 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : 16515 top; 16516 16517 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) / 16518 o.grid[ 0 ] ) * o.grid[ 0 ]; 16519 pageX = this.containment ? 16520 ( ( left - this.offset.click.left >= this.containment[ 0 ] && 16521 left - this.offset.click.left <= this.containment[ 2 ] ) ? 16522 left : 16523 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ? 16524 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : 16525 left; 16526 } 16527 16528 } 16529 16530 return { 16531 top: ( 16532 16533 // The absolute mouse position 16534 pageY - 16535 16536 // Click offset (relative to the element) 16537 this.offset.click.top - 16538 16539 // Only for relative positioned nodes: Relative offset from element to offset parent 16540 this.offset.relative.top - 16541 16542 // The offsetParent's offset without borders (offset + border) 16543 this.offset.parent.top + 16544 ( ( this.cssPosition === "fixed" ? 16545 -this.scrollParent.scrollTop() : 16546 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) ) 16547 ), 16548 left: ( 16549 16550 // The absolute mouse position 16551 pageX - 16552 16553 // Click offset (relative to the element) 16554 this.offset.click.left - 16555 16556 // Only for relative positioned nodes: Relative offset from element to offset parent 16557 this.offset.relative.left - 16558 16559 // The offsetParent's offset without borders (offset + border) 16560 this.offset.parent.left + 16561 ( ( this.cssPosition === "fixed" ? 16562 -this.scrollParent.scrollLeft() : 16563 scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) 16564 ) 16565 }; 16566 16567 }, 16568 16569 _rearrange: function( event, i, a, hardRefresh ) { 16570 16571 a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) : 16572 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ], 16573 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) ); 16574 16575 //Various things done here to improve the performance: 16576 // 1. we create a setTimeout, that calls refreshPositions 16577 // 2. on the instance, we have a counter variable, that get's higher after every append 16578 // 3. on the local scope, we copy the counter variable, and check in the timeout, 16579 // if it's still the same 16580 // 4. this lets only the last addition to the timeout stack through 16581 this.counter = this.counter ? ++this.counter : 1; 16582 var counter = this.counter; 16583 16584 this._delay( function() { 16585 if ( counter === this.counter ) { 16586 16587 //Precompute after each DOM insertion, NOT on mousemove 16588 this.refreshPositions( !hardRefresh ); 16589 } 16590 } ); 16591 16592 }, 16593 16594 _clear: function( event, noPropagation ) { 16595 16596 this.reverting = false; 16597 16598 // We delay all events that have to be triggered to after the point where the placeholder 16599 // has been removed and everything else normalized again 16600 var i, 16601 delayedTriggers = []; 16602 16603 // We first have to update the dom position of the actual currentItem 16604 // Note: don't do it if the current item is already removed (by a user), or it gets 16605 // reappended (see #4088) 16606 if ( !this._noFinalSort && this.currentItem.parent().length ) { 16607 this.placeholder.before( this.currentItem ); 16608 } 16609 this._noFinalSort = null; 16610 16611 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) { 16612 for ( i in this._storedCSS ) { 16613 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) { 16614 this._storedCSS[ i ] = ""; 16615 } 16616 } 16617 this.currentItem.css( this._storedCSS ); 16618 this._removeClass( this.currentItem, "ui-sortable-helper" ); 16619 } else { 16620 this.currentItem.show(); 16621 } 16622 16623 if ( this.fromOutside && !noPropagation ) { 16624 delayedTriggers.push( function( event ) { 16625 this._trigger( "receive", event, this._uiHash( this.fromOutside ) ); 16626 } ); 16627 } 16628 if ( ( this.fromOutside || 16629 this.domPosition.prev !== 16630 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] || 16631 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) { 16632 16633 // Trigger update callback if the DOM position has changed 16634 delayedTriggers.push( function( event ) { 16635 this._trigger( "update", event, this._uiHash() ); 16636 } ); 16637 } 16638 16639 // Check if the items Container has Changed and trigger appropriate 16640 // events. 16641 if ( this !== this.currentContainer ) { 16642 if ( !noPropagation ) { 16643 delayedTriggers.push( function( event ) { 16644 this._trigger( "remove", event, this._uiHash() ); 16645 } ); 16646 delayedTriggers.push( ( function( c ) { 16647 return function( event ) { 16648 c._trigger( "receive", event, this._uiHash( this ) ); 16649 }; 16650 } ).call( this, this.currentContainer ) ); 16651 delayedTriggers.push( ( function( c ) { 16652 return function( event ) { 16653 c._trigger( "update", event, this._uiHash( this ) ); 16654 }; 16655 } ).call( this, this.currentContainer ) ); 16656 } 16657 } 16658 16659 //Post events to containers 16660 function delayEvent( type, instance, container ) { 16661 return function( event ) { 16662 container._trigger( type, event, instance._uiHash( instance ) ); 16663 }; 16664 } 16665 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16666 if ( !noPropagation ) { 16667 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 16668 } 16669 if ( this.containers[ i ].containerCache.over ) { 16670 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 16671 this.containers[ i ].containerCache.over = 0; 16672 } 16673 } 16674 16675 //Do what was originally in plugins 16676 if ( this.storedCursor ) { 16677 this.document.find( "body" ).css( "cursor", this.storedCursor ); 16678 this.storedStylesheet.remove(); 16679 } 16680 if ( this._storedOpacity ) { 16681 this.helper.css( "opacity", this._storedOpacity ); 16682 } 16683 if ( this._storedZIndex ) { 16684 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex ); 16685 } 16686 16687 this.dragging = false; 16688 16689 if ( !noPropagation ) { 16690 this._trigger( "beforeStop", event, this._uiHash() ); 16691 } 16692 16693 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 16694 // it unbinds ALL events from the original node! 16695 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 16696 16697 if ( !this.cancelHelperRemoval ) { 16698 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 16699 this.helper.remove(); 16700 } 16701 this.helper = null; 16702 } 16703 16704 if ( !noPropagation ) { 16705 for ( i = 0; i < delayedTriggers.length; i++ ) { 16706 16707 // Trigger all delayed events 16708 delayedTriggers[ i ].call( this, event ); 16709 } 16710 this._trigger( "stop", event, this._uiHash() ); 16711 } 16712 16713 this.fromOutside = false; 16714 return !this.cancelHelperRemoval; 16715 16716 }, 16717 16718 _trigger: function() { 16719 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) { 16720 this.cancel(); 16721 } 16722 }, 16723 16724 _uiHash: function( _inst ) { 16725 var inst = _inst || this; 16726 return { 16727 helper: inst.helper, 16728 placeholder: inst.placeholder || $( [] ), 16729 position: inst.position, 16730 originalPosition: inst.originalPosition, 16731 offset: inst.positionAbs, 16732 item: inst.currentItem, 16733 sender: _inst ? _inst.element : null 16734 }; 16735 } 16736 16737 } ); 16738 16739 16740 /*! 16741 * jQuery UI Spinner 1.12.1 16742 * http://jqueryui.com 16743 * 16744 * Copyright jQuery Foundation and other contributors 16745 * Released under the MIT license. 16746 * http://jquery.org/license 16747 */ 16748 16749 //>>label: Spinner 16750 //>>group: Widgets 16751 //>>description: Displays buttons to easily input numbers via the keyboard or mouse. 16752 //>>docs: http://api.jqueryui.com/spinner/ 16753 //>>demos: http://jqueryui.com/spinner/ 16754 //>>css.structure: ../../themes/base/core.css 16755 //>>css.structure: ../../themes/base/spinner.css 16756 //>>css.theme: ../../themes/base/theme.css 16757 16758 16759 16760 function spinnerModifer( fn ) { 16761 return function() { 16762 var previous = this.element.val(); 16763 fn.apply( this, arguments ); 16764 this._refresh(); 16765 if ( previous !== this.element.val() ) { 16766 this._trigger( "change" ); 16767 } 16768 }; 16769 } 16770 16771 $.widget( "ui.spinner", { 16772 version: "1.12.1", 16773 defaultElement: "<input>", 16774 widgetEventPrefix: "spin", 16775 options: { 16776 classes: { 16777 "ui-spinner": "ui-corner-all", 16778 "ui-spinner-down": "ui-corner-br", 16779 "ui-spinner-up": "ui-corner-tr" 16780 }, 16781 culture: null, 16782 icons: { 16783 down: "ui-icon-triangle-1-s", 16784 up: "ui-icon-triangle-1-n" 16785 }, 16786 incremental: true, 16787 max: null, 16788 min: null, 16789 numberFormat: null, 16790 page: 10, 16791 step: 1, 16792 16793 change: null, 16794 spin: null, 16795 start: null, 16796 stop: null 16797 }, 16798 16799 _create: function() { 16800 16801 // handle string values that need to be parsed 16802 this._setOption( "max", this.options.max ); 16803 this._setOption( "min", this.options.min ); 16804 this._setOption( "step", this.options.step ); 16805 16806 // Only format if there is a value, prevents the field from being marked 16807 // as invalid in Firefox, see #9573. 16808 if ( this.value() !== "" ) { 16809 16810 // Format the value, but don't constrain. 16811 this._value( this.element.val(), true ); 16812 } 16813 16814 this._draw(); 16815 this._on( this._events ); 16816 this._refresh(); 16817 16818 // Turning off autocomplete prevents the browser from remembering the 16819 // value when navigating through history, so we re-enable autocomplete 16820 // if the page is unloaded before the widget is destroyed. #7790 16821 this._on( this.window, { 16822 beforeunload: function() { 16823 this.element.removeAttr( "autocomplete" ); 16824 } 16825 } ); 16826 }, 16827 16828 _getCreateOptions: function() { 16829 var options = this._super(); 16830 var element = this.element; 16831 16832 $.each( [ "min", "max", "step" ], function( i, option ) { 16833 var value = element.attr( option ); 16834 if ( value != null && value.length ) { 16835 options[ option ] = value; 16836 } 16837 } ); 16838 16839 return options; 16840 }, 16841 16842 _events: { 16843 keydown: function( event ) { 16844 if ( this._start( event ) && this._keydown( event ) ) { 16845 event.preventDefault(); 16846 } 16847 }, 16848 keyup: "_stop", 16849 focus: function() { 16850 this.previous = this.element.val(); 16851 }, 16852 blur: function( event ) { 16853 if ( this.cancelBlur ) { 16854 delete this.cancelBlur; 16855 return; 16856 } 16857 16858 this._stop(); 16859 this._refresh(); 16860 if ( this.previous !== this.element.val() ) { 16861 this._trigger( "change", event ); 16862 } 16863 }, 16864 mousewheel: function( event, delta ) { 16865 if ( !delta ) { 16866 return; 16867 } 16868 if ( !this.spinning && !this._start( event ) ) { 16869 return false; 16870 } 16871 16872 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); 16873 clearTimeout( this.mousewheelTimer ); 16874 this.mousewheelTimer = this._delay( function() { 16875 if ( this.spinning ) { 16876 this._stop( event ); 16877 } 16878 }, 100 ); 16879 event.preventDefault(); 16880 }, 16881 "mousedown .ui-spinner-button": function( event ) { 16882 var previous; 16883 16884 // We never want the buttons to have focus; whenever the user is 16885 // interacting with the spinner, the focus should be on the input. 16886 // If the input is focused then this.previous is properly set from 16887 // when the input first received focus. If the input is not focused 16888 // then we need to set this.previous based on the value before spinning. 16889 previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ? 16890 this.previous : this.element.val(); 16891 function checkFocus() { 16892 var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ); 16893 if ( !isActive ) { 16894 this.element.trigger( "focus" ); 16895 this.previous = previous; 16896 16897 // support: IE 16898 // IE sets focus asynchronously, so we need to check if focus 16899 // moved off of the input because the user clicked on the button. 16900 this._delay( function() { 16901 this.previous = previous; 16902 } ); 16903 } 16904 } 16905 16906 // Ensure focus is on (or stays on) the text field 16907 event.preventDefault(); 16908 checkFocus.call( this ); 16909 16910 // Support: IE 16911 // IE doesn't prevent moving focus even with event.preventDefault() 16912 // so we set a flag to know when we should ignore the blur event 16913 // and check (again) if focus moved off of the input. 16914 this.cancelBlur = true; 16915 this._delay( function() { 16916 delete this.cancelBlur; 16917 checkFocus.call( this ); 16918 } ); 16919 16920 if ( this._start( event ) === false ) { 16921 return; 16922 } 16923 16924 this._repeat( null, $( event.currentTarget ) 16925 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 16926 }, 16927 "mouseup .ui-spinner-button": "_stop", 16928 "mouseenter .ui-spinner-button": function( event ) { 16929 16930 // button will add ui-state-active if mouse was down while mouseleave and kept down 16931 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 16932 return; 16933 } 16934 16935 if ( this._start( event ) === false ) { 16936 return false; 16937 } 16938 this._repeat( null, $( event.currentTarget ) 16939 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 16940 }, 16941 16942 // TODO: do we really want to consider this a stop? 16943 // shouldn't we just stop the repeater and wait until mouseup before 16944 // we trigger the stop event? 16945 "mouseleave .ui-spinner-button": "_stop" 16946 }, 16947 16948 // Support mobile enhanced option and make backcompat more sane 16949 _enhance: function() { 16950 this.uiSpinner = this.element 16951 .attr( "autocomplete", "off" ) 16952 .wrap( "<span>" ) 16953 .parent() 16954 16955 // Add buttons 16956 .append( 16957 "<a></a><a></a>" 16958 ); 16959 }, 16960 16961 _draw: function() { 16962 this._enhance(); 16963 16964 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); 16965 this._addClass( "ui-spinner-input" ); 16966 16967 this.element.attr( "role", "spinbutton" ); 16968 16969 // Button bindings 16970 this.buttons = this.uiSpinner.children( "a" ) 16971 .attr( "tabIndex", -1 ) 16972 .attr( "aria-hidden", true ) 16973 .button( { 16974 classes: { 16975 "ui-button": "" 16976 } 16977 } ); 16978 16979 // TODO: Right now button does not support classes this is already updated in button PR 16980 this._removeClass( this.buttons, "ui-corner-all" ); 16981 16982 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); 16983 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); 16984 this.buttons.first().button( { 16985 "icon": this.options.icons.up, 16986 "showLabel": false 16987 } ); 16988 this.buttons.last().button( { 16989 "icon": this.options.icons.down, 16990 "showLabel": false 16991 } ); 16992 16993 // IE 6 doesn't understand height: 50% for the buttons 16994 // unless the wrapper has an explicit height 16995 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && 16996 this.uiSpinner.height() > 0 ) { 16997 this.uiSpinner.height( this.uiSpinner.height() ); 16998 } 16999 }, 17000 17001 _keydown: function( event ) { 17002 var options = this.options, 17003 keyCode = $.ui.keyCode; 17004 17005 switch ( event.keyCode ) { 17006 case keyCode.UP: 17007 this._repeat( null, 1, event ); 17008 return true; 17009 case keyCode.DOWN: 17010 this._repeat( null, -1, event ); 17011 return true; 17012 case keyCode.PAGE_UP: 17013 this._repeat( null, options.page, event ); 17014 return true; 17015 case keyCode.PAGE_DOWN: 17016 this._repeat( null, -options.page, event ); 17017 return true; 17018 } 17019 17020 return false; 17021 }, 17022 17023 _start: function( event ) { 17024 if ( !this.spinning && this._trigger( "start", event ) === false ) { 17025 return false; 17026 } 17027 17028 if ( !this.counter ) { 17029 this.counter = 1; 17030 } 17031 this.spinning = true; 17032 return true; 17033 }, 17034 17035 _repeat: function( i, steps, event ) { 17036 i = i || 500; 17037 17038 clearTimeout( this.timer ); 17039 this.timer = this._delay( function() { 17040 this._repeat( 40, steps, event ); 17041 }, i ); 17042 17043 this._spin( steps * this.options.step, event ); 17044 }, 17045 17046 _spin: function( step, event ) { 17047 var value = this.value() || 0; 17048 17049 if ( !this.counter ) { 17050 this.counter = 1; 17051 } 17052 17053 value = this._adjustValue( value + step * this._increment( this.counter ) ); 17054 17055 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { 17056 this._value( value ); 17057 this.counter++; 17058 } 17059 }, 17060 17061 _increment: function( i ) { 17062 var incremental = this.options.incremental; 17063 17064 if ( incremental ) { 17065 return $.isFunction( incremental ) ? 17066 incremental( i ) : 17067 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 17068 } 17069 17070 return 1; 17071 }, 17072 17073 _precision: function() { 17074 var precision = this._precisionOf( this.options.step ); 17075 if ( this.options.min !== null ) { 17076 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 17077 } 17078 return precision; 17079 }, 17080 17081 _precisionOf: function( num ) { 17082 var str = num.toString(), 17083 decimal = str.indexOf( "." ); 17084 return decimal === -1 ? 0 : str.length - decimal - 1; 17085 }, 17086 17087 _adjustValue: function( value ) { 17088 var base, aboveMin, 17089 options = this.options; 17090 17091 // Make sure we're at a valid step 17092 // - find out where we are relative to the base (min or 0) 17093 base = options.min !== null ? options.min : 0; 17094 aboveMin = value - base; 17095 17096 // - round to the nearest step 17097 aboveMin = Math.round( aboveMin / options.step ) * options.step; 17098 17099 // - rounding is based on 0, so adjust back to our base 17100 value = base + aboveMin; 17101 17102 // Fix precision from bad JS floating point math 17103 value = parseFloat( value.toFixed( this._precision() ) ); 17104 17105 // Clamp the value 17106 if ( options.max !== null && value > options.max ) { 17107 return options.max; 17108 } 17109 if ( options.min !== null && value < options.min ) { 17110 return options.min; 17111 } 17112 17113 return value; 17114 }, 17115 17116 _stop: function( event ) { 17117 if ( !this.spinning ) { 17118 return; 17119 } 17120 17121 clearTimeout( this.timer ); 17122 clearTimeout( this.mousewheelTimer ); 17123 this.counter = 0; 17124 this.spinning = false; 17125 this._trigger( "stop", event ); 17126 }, 17127 17128 _setOption: function( key, value ) { 17129 var prevValue, first, last; 17130 17131 if ( key === "culture" || key === "numberFormat" ) { 17132 prevValue = this._parse( this.element.val() ); 17133 this.options[ key ] = value; 17134 this.element.val( this._format( prevValue ) ); 17135 return; 17136 } 17137 17138 if ( key === "max" || key === "min" || key === "step" ) { 17139 if ( typeof value === "string" ) { 17140 value = this._parse( value ); 17141 } 17142 } 17143 if ( key === "icons" ) { 17144 first = this.buttons.first().find( ".ui-icon" ); 17145 this._removeClass( first, null, this.options.icons.up ); 17146 this._addClass( first, null, value.up ); 17147 last = this.buttons.last().find( ".ui-icon" ); 17148 this._removeClass( last, null, this.options.icons.down ); 17149 this._addClass( last, null, value.down ); 17150 } 17151 17152 this._super( key, value ); 17153 }, 17154 17155 _setOptionDisabled: function( value ) { 17156 this._super( value ); 17157 17158 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); 17159 this.element.prop( "disabled", !!value ); 17160 this.buttons.button( value ? "disable" : "enable" ); 17161 }, 17162 17163 _setOptions: spinnerModifer( function( options ) { 17164 this._super( options ); 17165 } ), 17166 17167 _parse: function( val ) { 17168 if ( typeof val === "string" && val !== "" ) { 17169 val = window.Globalize && this.options.numberFormat ? 17170 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 17171 } 17172 return val === "" || isNaN( val ) ? null : val; 17173 }, 17174 17175 _format: function( value ) { 17176 if ( value === "" ) { 17177 return ""; 17178 } 17179 return window.Globalize && this.options.numberFormat ? 17180 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 17181 value; 17182 }, 17183 17184 _refresh: function() { 17185 this.element.attr( { 17186 "aria-valuemin": this.options.min, 17187 "aria-valuemax": this.options.max, 17188 17189 // TODO: what should we do with values that can't be parsed? 17190 "aria-valuenow": this._parse( this.element.val() ) 17191 } ); 17192 }, 17193 17194 isValid: function() { 17195 var value = this.value(); 17196 17197 // Null is invalid 17198 if ( value === null ) { 17199 return false; 17200 } 17201 17202 // If value gets adjusted, it's invalid 17203 return value === this._adjustValue( value ); 17204 }, 17205 17206 // Update the value without triggering change 17207 _value: function( value, allowAny ) { 17208 var parsed; 17209 if ( value !== "" ) { 17210 parsed = this._parse( value ); 17211 if ( parsed !== null ) { 17212 if ( !allowAny ) { 17213 parsed = this._adjustValue( parsed ); 17214 } 17215 value = this._format( parsed ); 17216 } 17217 } 17218 this.element.val( value ); 17219 this._refresh(); 17220 }, 17221 17222 _destroy: function() { 17223 this.element 17224 .prop( "disabled", false ) 17225 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); 17226 17227 this.uiSpinner.replaceWith( this.element ); 17228 }, 17229 17230 stepUp: spinnerModifer( function( steps ) { 17231 this._stepUp( steps ); 17232 } ), 17233 _stepUp: function( steps ) { 17234 if ( this._start() ) { 17235 this._spin( ( steps || 1 ) * this.options.step ); 17236 this._stop(); 17237 } 17238 }, 17239 17240 stepDown: spinnerModifer( function( steps ) { 17241 this._stepDown( steps ); 17242 } ), 17243 _stepDown: function( steps ) { 17244 if ( this._start() ) { 17245 this._spin( ( steps || 1 ) * -this.options.step ); 17246 this._stop(); 17247 } 17248 }, 17249 17250 pageUp: spinnerModifer( function( pages ) { 17251 this._stepUp( ( pages || 1 ) * this.options.page ); 17252 } ), 17253 17254 pageDown: spinnerModifer( function( pages ) { 17255 this._stepDown( ( pages || 1 ) * this.options.page ); 17256 } ), 17257 17258 value: function( newVal ) { 17259 if ( !arguments.length ) { 17260 return this._parse( this.element.val() ); 17261 } 17262 spinnerModifer( this._value ).call( this, newVal ); 17263 }, 17264 17265 widget: function() { 17266 return this.uiSpinner; 17267 } 17268 } ); 17269 17270 // DEPRECATED 17271 // TODO: switch return back to widget declaration at top of file when this is removed 17272 if ( $.uiBackCompat !== false ) { 17273 17274 // Backcompat for spinner html extension points 17275 $.widget( "ui.spinner", $.ui.spinner, { 17276 _enhance: function() { 17277 this.uiSpinner = this.element 17278 .attr( "autocomplete", "off" ) 17279 .wrap( this._uiSpinnerHtml() ) 17280 .parent() 17281 17282 // Add buttons 17283 .append( this._buttonHtml() ); 17284 }, 17285 _uiSpinnerHtml: function() { 17286 return "<span>"; 17287 }, 17288 17289 _buttonHtml: function() { 17290 return "<a></a><a></a>"; 17291 } 17292 } ); 17293 } 17294 17295 var widgetsSpinner = $.ui.spinner; 17296 17297 17298 /*! 17299 * jQuery UI Tabs 1.12.1 17300 * http://jqueryui.com 17301 * 17302 * Copyright jQuery Foundation and other contributors 17303 * Released under the MIT license. 17304 * http://jquery.org/license 17305 */ 17306 17307 //>>label: Tabs 17308 //>>group: Widgets 17309 //>>description: Transforms a set of container elements into a tab structure. 17310 //>>docs: http://api.jqueryui.com/tabs/ 17311 //>>demos: http://jqueryui.com/tabs/ 17312 //>>css.structure: ../../themes/base/core.css 17313 //>>css.structure: ../../themes/base/tabs.css 17314 //>>css.theme: ../../themes/base/theme.css 17315 17316 17317 17318 $.widget( "ui.tabs", { 17319 version: "1.12.1", 17320 delay: 300, 17321 options: { 17322 active: null, 17323 classes: { 17324 "ui-tabs": "ui-corner-all", 17325 "ui-tabs-nav": "ui-corner-all", 17326 "ui-tabs-panel": "ui-corner-bottom", 17327 "ui-tabs-tab": "ui-corner-top" 17328 }, 17329 collapsible: false, 17330 event: "click", 17331 heightStyle: "content", 17332 hide: null, 17333 show: null, 17334 17335 // Callbacks 17336 activate: null, 17337 beforeActivate: null, 17338 beforeLoad: null, 17339 load: null 17340 }, 17341 17342 _isLocal: ( function() { 17343 var rhash = /#.*$/; 17344 17345 return function( anchor ) { 17346 var anchorUrl, locationUrl; 17347 17348 anchorUrl = anchor.href.replace( rhash, "" ); 17349 locationUrl = location.href.replace( rhash, "" ); 17350 17351 // Decoding may throw an error if the URL isn't UTF-8 (#9518) 17352 try { 17353 anchorUrl = decodeURIComponent( anchorUrl ); 17354 } catch ( error ) {} 17355 try { 17356 locationUrl = decodeURIComponent( locationUrl ); 17357 } catch ( error ) {} 17358 17359 return anchor.hash.length > 1 && anchorUrl === locationUrl; 17360 }; 17361 } )(), 17362 17363 _create: function() { 17364 var that = this, 17365 options = this.options; 17366 17367 this.running = false; 17368 17369 this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); 17370 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); 17371 17372 this._processTabs(); 17373 options.active = this._initialActive(); 17374 17375 // Take disabling tabs via class attribute from HTML 17376 // into account and update option properly. 17377 if ( $.isArray( options.disabled ) ) { 17378 options.disabled = $.unique( options.disabled.concat( 17379 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { 17380 return that.tabs.index( li ); 17381 } ) 17382 ) ).sort(); 17383 } 17384 17385 // Check for length avoids error when initializing empty list 17386 if ( this.options.active !== false && this.anchors.length ) { 17387 this.active = this._findActive( options.active ); 17388 } else { 17389 this.active = $(); 17390 } 17391 17392 this._refresh(); 17393 17394 if ( this.active.length ) { 17395 this.load( options.active ); 17396 } 17397 }, 17398 17399 _initialActive: function() { 17400 var active = this.options.active, 17401 collapsible = this.options.collapsible, 17402 locationHash = location.hash.substring( 1 ); 17403 17404 if ( active === null ) { 17405 17406 // check the fragment identifier in the URL 17407 if ( locationHash ) { 17408 this.tabs.each( function( i, tab ) { 17409 if ( $( tab ).attr( "aria-controls" ) === locationHash ) { 17410 active = i; 17411 return false; 17412 } 17413 } ); 17414 } 17415 17416 // Check for a tab marked active via a class 17417 if ( active === null ) { 17418 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); 17419 } 17420 17421 // No active tab, set to false 17422 if ( active === null || active === -1 ) { 17423 active = this.tabs.length ? 0 : false; 17424 } 17425 } 17426 17427 // Handle numbers: negative, out of range 17428 if ( active !== false ) { 17429 active = this.tabs.index( this.tabs.eq( active ) ); 17430 if ( active === -1 ) { 17431 active = collapsible ? false : 0; 17432 } 17433 } 17434 17435 // Don't allow collapsible: false and active: false 17436 if ( !collapsible && active === false && this.anchors.length ) { 17437 active = 0; 17438 } 17439 17440 return active; 17441 }, 17442 17443 _getCreateEventData: function() { 17444 return { 17445 tab: this.active, 17446 panel: !this.active.length ? $() : this._getPanelForTab( this.active ) 17447 }; 17448 }, 17449 17450 _tabKeydown: function( event ) { 17451 var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ), 17452 selectedIndex = this.tabs.index( focusedTab ), 17453 goingForward = true; 17454 17455 if ( this._handlePageNav( event ) ) { 17456 return; 17457 } 17458 17459 switch ( event.keyCode ) { 17460 case $.ui.keyCode.RIGHT: 17461 case $.ui.keyCode.DOWN: 17462 selectedIndex++; 17463 break; 17464 case $.ui.keyCode.UP: 17465 case $.ui.keyCode.LEFT: 17466 goingForward = false; 17467 selectedIndex--; 17468 break; 17469 case $.ui.keyCode.END: 17470 selectedIndex = this.anchors.length - 1; 17471 break; 17472 case $.ui.keyCode.HOME: 17473 selectedIndex = 0; 17474 break; 17475 case $.ui.keyCode.SPACE: 17476 17477 // Activate only, no collapsing 17478 event.preventDefault(); 17479 clearTimeout( this.activating ); 17480 this._activate( selectedIndex ); 17481 return; 17482 case $.ui.keyCode.ENTER: 17483 17484 // Toggle (cancel delayed activation, allow collapsing) 17485 event.preventDefault(); 17486 clearTimeout( this.activating ); 17487 17488 // Determine if we should collapse or activate 17489 this._activate( selectedIndex === this.options.active ? false : selectedIndex ); 17490 return; 17491 default: 17492 return; 17493 } 17494 17495 // Focus the appropriate tab, based on which key was pressed 17496 event.preventDefault(); 17497 clearTimeout( this.activating ); 17498 selectedIndex = this._focusNextTab( selectedIndex, goingForward ); 17499 17500 // Navigating with control/command key will prevent automatic activation 17501 if ( !event.ctrlKey && !event.metaKey ) { 17502 17503 // Update aria-selected immediately so that AT think the tab is already selected. 17504 // Otherwise AT may confuse the user by stating that they need to activate the tab, 17505 // but the tab will already be activated by the time the announcement finishes. 17506 focusedTab.attr( "aria-selected", "false" ); 17507 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); 17508 17509 this.activating = this._delay( function() { 17510 this.option( "active", selectedIndex ); 17511 }, this.delay ); 17512 } 17513 }, 17514 17515 _panelKeydown: function( event ) { 17516 if ( this._handlePageNav( event ) ) { 17517 return; 17518 } 17519 17520 // Ctrl+up moves focus to the current tab 17521 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { 17522 event.preventDefault(); 17523 this.active.trigger( "focus" ); 17524 } 17525 }, 17526 17527 // Alt+page up/down moves focus to the previous/next tab (and activates) 17528 _handlePageNav: function( event ) { 17529 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { 17530 this._activate( this._focusNextTab( this.options.active - 1, false ) ); 17531 return true; 17532 } 17533 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { 17534 this._activate( this._focusNextTab( this.options.active + 1, true ) ); 17535 return true; 17536 } 17537 }, 17538 17539 _findNextTab: function( index, goingForward ) { 17540 var lastTabIndex = this.tabs.length - 1; 17541 17542 function constrain() { 17543 if ( index > lastTabIndex ) { 17544 index = 0; 17545 } 17546 if ( index < 0 ) { 17547 index = lastTabIndex; 17548 } 17549 return index; 17550 } 17551 17552 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { 17553 index = goingForward ? index + 1 : index - 1; 17554 } 17555 17556 return index; 17557 }, 17558 17559 _focusNextTab: function( index, goingForward ) { 17560 index = this._findNextTab( index, goingForward ); 17561 this.tabs.eq( index ).trigger( "focus" ); 17562 return index; 17563 }, 17564 17565 _setOption: function( key, value ) { 17566 if ( key === "active" ) { 17567 17568 // _activate() will handle invalid values and update this.options 17569 this._activate( value ); 17570 return; 17571 } 17572 17573 this._super( key, value ); 17574 17575 if ( key === "collapsible" ) { 17576 this._toggleClass( "ui-tabs-collapsible", null, value ); 17577 17578 // Setting collapsible: false while collapsed; open first panel 17579 if ( !value && this.options.active === false ) { 17580 this._activate( 0 ); 17581 } 17582 } 17583 17584 if ( key === "event" ) { 17585 this._setupEvents( value ); 17586 } 17587 17588 if ( key === "heightStyle" ) { 17589 this._setupHeightStyle( value ); 17590 } 17591 }, 17592 17593 _sanitizeSelector: function( hash ) { 17594 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; 17595 }, 17596 17597 refresh: function() { 17598 var options = this.options, 17599 lis = this.tablist.children( ":has(a[href])" ); 17600 17601 // Get disabled tabs from class attribute from HTML 17602 // this will get converted to a boolean if needed in _refresh() 17603 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { 17604 return lis.index( tab ); 17605 } ); 17606 17607 this._processTabs(); 17608 17609 // Was collapsed or no tabs 17610 if ( options.active === false || !this.anchors.length ) { 17611 options.active = false; 17612 this.active = $(); 17613 17614 // was active, but active tab is gone 17615 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { 17616 17617 // all remaining tabs are disabled 17618 if ( this.tabs.length === options.disabled.length ) { 17619 options.active = false; 17620 this.active = $(); 17621 17622 // activate previous tab 17623 } else { 17624 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); 17625 } 17626 17627 // was active, active tab still exists 17628 } else { 17629 17630 // make sure active index is correct 17631 options.active = this.tabs.index( this.active ); 17632 } 17633 17634 this._refresh(); 17635 }, 17636 17637 _refresh: function() { 17638 this._setOptionDisabled( this.options.disabled ); 17639 this._setupEvents( this.options.event ); 17640 this._setupHeightStyle( this.options.heightStyle ); 17641 17642 this.tabs.not( this.active ).attr( { 17643 "aria-selected": "false", 17644 "aria-expanded": "false", 17645 tabIndex: -1 17646 } ); 17647 this.panels.not( this._getPanelForTab( this.active ) ) 17648 .hide() 17649 .attr( { 17650 "aria-hidden": "true" 17651 } ); 17652 17653 // Make sure one tab is in the tab order 17654 if ( !this.active.length ) { 17655 this.tabs.eq( 0 ).attr( "tabIndex", 0 ); 17656 } else { 17657 this.active 17658 .attr( { 17659 "aria-selected": "true", 17660 "aria-expanded": "true", 17661 tabIndex: 0 17662 } ); 17663 this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); 17664 this._getPanelForTab( this.active ) 17665 .show() 17666 .attr( { 17667 "aria-hidden": "false" 17668 } ); 17669 } 17670 }, 17671 17672 _processTabs: function() { 17673 var that = this, 17674 prevTabs = this.tabs, 17675 prevAnchors = this.anchors, 17676 prevPanels = this.panels; 17677 17678 this.tablist = this._getList().attr( "role", "tablist" ); 17679 this._addClass( this.tablist, "ui-tabs-nav", 17680 "ui-helper-reset ui-helper-clearfix ui-widget-header" ); 17681 17682 // Prevent users from focusing disabled tabs via click 17683 this.tablist 17684 .on( "mousedown" + this.eventNamespace, "> li", function( event ) { 17685 if ( $( this ).is( ".ui-state-disabled" ) ) { 17686 event.preventDefault(); 17687 } 17688 } ) 17689 17690 // Support: IE <9 17691 // Preventing the default action in mousedown doesn't prevent IE 17692 // from focusing the element, so if the anchor gets focused, blur. 17693 // We don't have to worry about focusing the previously focused 17694 // element since clicking on a non-focusable element should focus 17695 // the body anyway. 17696 .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() { 17697 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { 17698 this.blur(); 17699 } 17700 } ); 17701 17702 this.tabs = this.tablist.find( "> li:has(a[href])" ) 17703 .attr( { 17704 role: "tab", 17705 tabIndex: -1 17706 } ); 17707 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); 17708 17709 this.anchors = this.tabs.map( function() { 17710 return $( "a", this )[ 0 ]; 17711 } ) 17712 .attr( { 17713 role: "presentation", 17714 tabIndex: -1 17715 } ); 17716 this._addClass( this.anchors, "ui-tabs-anchor" ); 17717 17718 this.panels = $(); 17719 17720 this.anchors.each( function( i, anchor ) { 17721 var selector, panel, panelId, 17722 anchorId = $( anchor ).uniqueId().attr( "id" ), 17723 tab = $( anchor ).closest( "li" ), 17724 originalAriaControls = tab.attr( "aria-controls" ); 17725 17726 // Inline tab 17727 if ( that._isLocal( anchor ) ) { 17728 selector = anchor.hash; 17729 panelId = selector.substring( 1 ); 17730 panel = that.element.find( that._sanitizeSelector( selector ) ); 17731 17732 // remote tab 17733 } else { 17734 17735 // If the tab doesn't already have aria-controls, 17736 // generate an id by using a throw-away element 17737 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; 17738 selector = "#" + panelId; 17739 panel = that.element.find( selector ); 17740 if ( !panel.length ) { 17741 panel = that._createPanel( panelId ); 17742 panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); 17743 } 17744 panel.attr( "aria-live", "polite" ); 17745 } 17746 17747 if ( panel.length ) { 17748 that.panels = that.panels.add( panel ); 17749 } 17750 if ( originalAriaControls ) { 17751 tab.data( "ui-tabs-aria-controls", originalAriaControls ); 17752 } 17753 tab.attr( { 17754 "aria-controls": panelId, 17755 "aria-labelledby": anchorId 17756 } ); 17757 panel.attr( "aria-labelledby", anchorId ); 17758 } ); 17759 17760 this.panels.attr( "role", "tabpanel" ); 17761 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); 17762 17763 // Avoid memory leaks (#10056) 17764 if ( prevTabs ) { 17765 this._off( prevTabs.not( this.tabs ) ); 17766 this._off( prevAnchors.not( this.anchors ) ); 17767 this._off( prevPanels.not( this.panels ) ); 17768 } 17769 }, 17770 17771 // Allow overriding how to find the list for rare usage scenarios (#7715) 17772 _getList: function() { 17773 return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); 17774 }, 17775 17776 _createPanel: function( id ) { 17777 return $( "<div>" ) 17778 .attr( "id", id ) 17779 .data( "ui-tabs-destroy", true ); 17780 }, 17781 17782 _setOptionDisabled: function( disabled ) { 17783 var currentItem, li, i; 17784 17785 if ( $.isArray( disabled ) ) { 17786 if ( !disabled.length ) { 17787 disabled = false; 17788 } else if ( disabled.length === this.anchors.length ) { 17789 disabled = true; 17790 } 17791 } 17792 17793 // Disable tabs 17794 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { 17795 currentItem = $( li ); 17796 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { 17797 currentItem.attr( "aria-disabled", "true" ); 17798 this._addClass( currentItem, null, "ui-state-disabled" ); 17799 } else { 17800 currentItem.removeAttr( "aria-disabled" ); 17801 this._removeClass( currentItem, null, "ui-state-disabled" ); 17802 } 17803 } 17804 17805 this.options.disabled = disabled; 17806 17807 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, 17808 disabled === true ); 17809 }, 17810 17811 _setupEvents: function( event ) { 17812 var events = {}; 17813 if ( event ) { 17814 $.each( event.split( " " ), function( index, eventName ) { 17815 events[ eventName ] = "_eventHandler"; 17816 } ); 17817 } 17818 17819 this._off( this.anchors.add( this.tabs ).add( this.panels ) ); 17820 17821 // Always prevent the default action, even when disabled 17822 this._on( true, this.anchors, { 17823 click: function( event ) { 17824 event.preventDefault(); 17825 } 17826 } ); 17827 this._on( this.anchors, events ); 17828 this._on( this.tabs, { keydown: "_tabKeydown" } ); 17829 this._on( this.panels, { keydown: "_panelKeydown" } ); 17830 17831 this._focusable( this.tabs ); 17832 this._hoverable( this.tabs ); 17833 }, 17834 17835 _setupHeightStyle: function( heightStyle ) { 17836 var maxHeight, 17837 parent = this.element.parent(); 17838 17839 if ( heightStyle === "fill" ) { 17840 maxHeight = parent.height(); 17841 maxHeight -= this.element.outerHeight() - this.element.height(); 17842 17843 this.element.siblings( ":visible" ).each( function() { 17844 var elem = $( this ), 17845 position = elem.css( "position" ); 17846 17847 if ( position === "absolute" || position === "fixed" ) { 17848 return; 17849 } 17850 maxHeight -= elem.outerHeight( true ); 17851 } ); 17852 17853 this.element.children().not( this.panels ).each( function() { 17854 maxHeight -= $( this ).outerHeight( true ); 17855 } ); 17856 17857 this.panels.each( function() { 17858 $( this ).height( Math.max( 0, maxHeight - 17859 $( this ).innerHeight() + $( this ).height() ) ); 17860 } ) 17861 .css( "overflow", "auto" ); 17862 } else if ( heightStyle === "auto" ) { 17863 maxHeight = 0; 17864 this.panels.each( function() { 17865 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 17866 } ).height( maxHeight ); 17867 } 17868 }, 17869 17870 _eventHandler: function( event ) { 17871 var options = this.options, 17872 active = this.active, 17873 anchor = $( event.currentTarget ), 17874 tab = anchor.closest( "li" ), 17875 clickedIsActive = tab[ 0 ] === active[ 0 ], 17876 collapsing = clickedIsActive && options.collapsible, 17877 toShow = collapsing ? $() : this._getPanelForTab( tab ), 17878 toHide = !active.length ? $() : this._getPanelForTab( active ), 17879 eventData = { 17880 oldTab: active, 17881 oldPanel: toHide, 17882 newTab: collapsing ? $() : tab, 17883 newPanel: toShow 17884 }; 17885 17886 event.preventDefault(); 17887 17888 if ( tab.hasClass( "ui-state-disabled" ) || 17889 17890 // tab is already loading 17891 tab.hasClass( "ui-tabs-loading" ) || 17892 17893 // can't switch durning an animation 17894 this.running || 17895 17896 // click on active header, but not collapsible 17897 ( clickedIsActive && !options.collapsible ) || 17898 17899 // allow canceling activation 17900 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 17901 return; 17902 } 17903 17904 options.active = collapsing ? false : this.tabs.index( tab ); 17905 17906 this.active = clickedIsActive ? $() : tab; 17907 if ( this.xhr ) { 17908 this.xhr.abort(); 17909 } 17910 17911 if ( !toHide.length && !toShow.length ) { 17912 $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); 17913 } 17914 17915 if ( toShow.length ) { 17916 this.load( this.tabs.index( tab ), event ); 17917 } 17918 this._toggle( event, eventData ); 17919 }, 17920 17921 // Handles show/hide for selecting tabs 17922 _toggle: function( event, eventData ) { 17923 var that = this, 17924 toShow = eventData.newPanel, 17925 toHide = eventData.oldPanel; 17926 17927 this.running = true; 17928 17929 function complete() { 17930 that.running = false; 17931 that._trigger( "activate", event, eventData ); 17932 } 17933 17934 function show() { 17935 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); 17936 17937 if ( toShow.length && that.options.show ) { 17938 that._show( toShow, that.options.show, complete ); 17939 } else { 17940 toShow.show(); 17941 complete(); 17942 } 17943 } 17944 17945 // Start out by hiding, then showing, then completing 17946 if ( toHide.length && this.options.hide ) { 17947 this._hide( toHide, this.options.hide, function() { 17948 that._removeClass( eventData.oldTab.closest( "li" ), 17949 "ui-tabs-active", "ui-state-active" ); 17950 show(); 17951 } ); 17952 } else { 17953 this._removeClass( eventData.oldTab.closest( "li" ), 17954 "ui-tabs-active", "ui-state-active" ); 17955 toHide.hide(); 17956 show(); 17957 } 17958 17959 toHide.attr( "aria-hidden", "true" ); 17960 eventData.oldTab.attr( { 17961 "aria-selected": "false", 17962 "aria-expanded": "false" 17963 } ); 17964 17965 // If we're switching tabs, remove the old tab from the tab order. 17966 // If we're opening from collapsed state, remove the previous tab from the tab order. 17967 // If we're collapsing, then keep the collapsing tab in the tab order. 17968 if ( toShow.length && toHide.length ) { 17969 eventData.oldTab.attr( "tabIndex", -1 ); 17970 } else if ( toShow.length ) { 17971 this.tabs.filter( function() { 17972 return $( this ).attr( "tabIndex" ) === 0; 17973 } ) 17974 .attr( "tabIndex", -1 ); 17975 } 17976 17977 toShow.attr( "aria-hidden", "false" ); 17978 eventData.newTab.attr( { 17979 "aria-selected": "true", 17980 "aria-expanded": "true", 17981 tabIndex: 0 17982 } ); 17983 }, 17984 17985 _activate: function( index ) { 17986 var anchor, 17987 active = this._findActive( index ); 17988 17989 // Trying to activate the already active panel 17990 if ( active[ 0 ] === this.active[ 0 ] ) { 17991 return; 17992 } 17993 17994 // Trying to collapse, simulate a click on the current active header 17995 if ( !active.length ) { 17996 active = this.active; 17997 } 17998 17999 anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; 18000 this._eventHandler( { 18001 target: anchor, 18002 currentTarget: anchor, 18003 preventDefault: $.noop 18004 } ); 18005 }, 18006 18007 _findActive: function( index ) { 18008 return index === false ? $() : this.tabs.eq( index ); 18009 }, 18010 18011 _getIndex: function( index ) { 18012 18013 // meta-function to give users option to provide a href string instead of a numerical index. 18014 if ( typeof index === "string" ) { 18015 index = this.anchors.index( this.anchors.filter( "[href$='" + 18016 $.ui.escapeSelector( index ) + "']" ) ); 18017 } 18018 18019 return index; 18020 }, 18021 18022 _destroy: function() { 18023 if ( this.xhr ) { 18024 this.xhr.abort(); 18025 } 18026 18027 this.tablist 18028 .removeAttr( "role" ) 18029 .off( this.eventNamespace ); 18030 18031 this.anchors 18032 .removeAttr( "role tabIndex" ) 18033 .removeUniqueId(); 18034 18035 this.tabs.add( this.panels ).each( function() { 18036 if ( $.data( this, "ui-tabs-destroy" ) ) { 18037 $( this ).remove(); 18038 } else { 18039 $( this ).removeAttr( "role tabIndex " + 18040 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); 18041 } 18042 } ); 18043 18044 this.tabs.each( function() { 18045 var li = $( this ), 18046 prev = li.data( "ui-tabs-aria-controls" ); 18047 if ( prev ) { 18048 li 18049 .attr( "aria-controls", prev ) 18050 .removeData( "ui-tabs-aria-controls" ); 18051 } else { 18052 li.removeAttr( "aria-controls" ); 18053 } 18054 } ); 18055 18056 this.panels.show(); 18057 18058 if ( this.options.heightStyle !== "content" ) { 18059 this.panels.css( "height", "" ); 18060 } 18061 }, 18062 18063 enable: function( index ) { 18064 var disabled = this.options.disabled; 18065 if ( disabled === false ) { 18066 return; 18067 } 18068 18069 if ( index === undefined ) { 18070 disabled = false; 18071 } else { 18072 index = this._getIndex( index ); 18073 if ( $.isArray( disabled ) ) { 18074 disabled = $.map( disabled, function( num ) { 18075 return num !== index ? num : null; 18076 } ); 18077 } else { 18078 disabled = $.map( this.tabs, function( li, num ) { 18079 return num !== index ? num : null; 18080 } ); 18081 } 18082 } 18083 this._setOptionDisabled( disabled ); 18084 }, 18085 18086 disable: function( index ) { 18087 var disabled = this.options.disabled; 18088 if ( disabled === true ) { 18089 return; 18090 } 18091 18092 if ( index === undefined ) { 18093 disabled = true; 18094 } else { 18095 index = this._getIndex( index ); 18096 if ( $.inArray( index, disabled ) !== -1 ) { 18097 return; 18098 } 18099 if ( $.isArray( disabled ) ) { 18100 disabled = $.merge( [ index ], disabled ).sort(); 18101 } else { 18102 disabled = [ index ]; 18103 } 18104 } 18105 this._setOptionDisabled( disabled ); 18106 }, 18107 18108 load: function( index, event ) { 18109 index = this._getIndex( index ); 18110 var that = this, 18111 tab = this.tabs.eq( index ), 18112 anchor = tab.find( ".ui-tabs-anchor" ), 18113 panel = this._getPanelForTab( tab ), 18114 eventData = { 18115 tab: tab, 18116 panel: panel 18117 }, 18118 complete = function( jqXHR, status ) { 18119 if ( status === "abort" ) { 18120 that.panels.stop( false, true ); 18121 } 18122 18123 that._removeClass( tab, "ui-tabs-loading" ); 18124 panel.removeAttr( "aria-busy" ); 18125 18126 if ( jqXHR === that.xhr ) { 18127 delete that.xhr; 18128 } 18129 }; 18130 18131 // Not remote 18132 if ( this._isLocal( anchor[ 0 ] ) ) { 18133 return; 18134 } 18135 18136 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); 18137 18138 // Support: jQuery <1.8 18139 // jQuery <1.8 returns false if the request is canceled in beforeSend, 18140 // but as of 1.8, $.ajax() always returns a jqXHR object. 18141 if ( this.xhr && this.xhr.statusText !== "canceled" ) { 18142 this._addClass( tab, "ui-tabs-loading" ); 18143 panel.attr( "aria-busy", "true" ); 18144 18145 this.xhr 18146 .done( function( response, status, jqXHR ) { 18147 18148 // support: jQuery <1.8 18149 // http://bugs.jquery.com/ticket/11778 18150 setTimeout( function() { 18151 panel.html( response ); 18152 that._trigger( "load", event, eventData ); 18153 18154 complete( jqXHR, status ); 18155 }, 1 ); 18156 } ) 18157 .fail( function( jqXHR, status ) { 18158 18159 // support: jQuery <1.8 18160 // http://bugs.jquery.com/ticket/11778 18161 setTimeout( function() { 18162 complete( jqXHR, status ); 18163 }, 1 ); 18164 } ); 18165 } 18166 }, 18167 18168 _ajaxSettings: function( anchor, event, eventData ) { 18169 var that = this; 18170 return { 18171 18172 // Support: IE <11 only 18173 // Strip any hash that exists to prevent errors with the Ajax request 18174 url: anchor.attr( "href" ).replace( /#.*$/, "" ), 18175 beforeSend: function( jqXHR, settings ) { 18176 return that._trigger( "beforeLoad", event, 18177 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); 18178 } 18179 }; 18180 }, 18181 18182 _getPanelForTab: function( tab ) { 18183 var id = $( tab ).attr( "aria-controls" ); 18184 return this.element.find( this._sanitizeSelector( "#" + id ) ); 18185 } 18186 } ); 18187 18188 // DEPRECATED 18189 // TODO: Switch return back to widget declaration at top of file when this is removed 18190 if ( $.uiBackCompat !== false ) { 18191 18192 // Backcompat for ui-tab class (now ui-tabs-tab) 18193 $.widget( "ui.tabs", $.ui.tabs, { 18194 _processTabs: function() { 18195 this._superApply( arguments ); 18196 this._addClass( this.tabs, "ui-tab" ); 18197 } 18198 } ); 18199 } 18200 18201 var widgetsTabs = $.ui.tabs; 18202 18203 18204 /*! 18205 * jQuery UI Tooltip 1.12.1 18206 * http://jqueryui.com 18207 * 18208 * Copyright jQuery Foundation and other contributors 18209 * Released under the MIT license. 18210 * http://jquery.org/license 18211 */ 18212 18213 //>>label: Tooltip 18214 //>>group: Widgets 18215 //>>description: Shows additional information for any element on hover or focus. 18216 //>>docs: http://api.jqueryui.com/tooltip/ 18217 //>>demos: http://jqueryui.com/tooltip/ 18218 //>>css.structure: ../../themes/base/core.css 18219 //>>css.structure: ../../themes/base/tooltip.css 18220 //>>css.theme: ../../themes/base/theme.css 18221 18222 18223 18224 $.widget( "ui.tooltip", { 18225 version: "1.12.1", 18226 options: { 18227 classes: { 18228 "ui-tooltip": "ui-corner-all ui-widget-shadow" 18229 }, 18230 content: function() { 18231 18232 // support: IE<9, Opera in jQuery <1.7 18233 // .text() can't accept undefined, so coerce to a string 18234 var title = $( this ).attr( "title" ) || ""; 18235 18236 // Escape title, since we're going from an attribute to raw HTML 18237 return $( "<a>" ).text( title ).html(); 18238 }, 18239 hide: true, 18240 18241 // Disabled elements have inconsistent behavior across browsers (#8661) 18242 items: "[title]:not([disabled])", 18243 position: { 18244 my: "left top+15", 18245 at: "left bottom", 18246 collision: "flipfit flip" 18247 }, 18248 show: true, 18249 track: false, 18250 18251 // Callbacks 18252 close: null, 18253 open: null 18254 }, 18255 18256 _addDescribedBy: function( elem, id ) { 18257 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); 18258 describedby.push( id ); 18259 elem 18260 .data( "ui-tooltip-id", id ) 18261 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); 18262 }, 18263 18264 _removeDescribedBy: function( elem ) { 18265 var id = elem.data( "ui-tooltip-id" ), 18266 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), 18267 index = $.inArray( id, describedby ); 18268 18269 if ( index !== -1 ) { 18270 describedby.splice( index, 1 ); 18271 } 18272 18273 elem.removeData( "ui-tooltip-id" ); 18274 describedby = $.trim( describedby.join( " " ) ); 18275 if ( describedby ) { 18276 elem.attr( "aria-describedby", describedby ); 18277 } else { 18278 elem.removeAttr( "aria-describedby" ); 18279 } 18280 }, 18281 18282 _create: function() { 18283 this._on( { 18284 mouseover: "open", 18285 focusin: "open" 18286 } ); 18287 18288 // IDs of generated tooltips, needed for destroy 18289 this.tooltips = {}; 18290 18291 // IDs of parent tooltips where we removed the title attribute 18292 this.parents = {}; 18293 18294 // Append the aria-live region so tooltips announce correctly 18295 this.liveRegion = $( "<div>" ) 18296 .attr( { 18297 role: "log", 18298 "aria-live": "assertive", 18299 "aria-relevant": "additions" 18300 } ) 18301 .appendTo( this.document[ 0 ].body ); 18302 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 18303 18304 this.disabledTitles = $( [] ); 18305 }, 18306 18307 _setOption: function( key, value ) { 18308 var that = this; 18309 18310 this._super( key, value ); 18311 18312 if ( key === "content" ) { 18313 $.each( this.tooltips, function( id, tooltipData ) { 18314 that._updateContent( tooltipData.element ); 18315 } ); 18316 } 18317 }, 18318 18319 _setOptionDisabled: function( value ) { 18320 this[ value ? "_disable" : "_enable" ](); 18321 }, 18322 18323 _disable: function() { 18324 var that = this; 18325 18326 // Close open tooltips 18327 $.each( this.tooltips, function( id, tooltipData ) { 18328 var event = $.Event( "blur" ); 18329 event.target = event.currentTarget = tooltipData.element[ 0 ]; 18330 that.close( event, true ); 18331 } ); 18332 18333 // Remove title attributes to prevent native tooltips 18334 this.disabledTitles = this.disabledTitles.add( 18335 this.element.find( this.options.items ).addBack() 18336 .filter( function() { 18337 var element = $( this ); 18338 if ( element.is( "[title]" ) ) { 18339 return element 18340 .data( "ui-tooltip-title", element.attr( "title" ) ) 18341 .removeAttr( "title" ); 18342 } 18343 } ) 18344 ); 18345 }, 18346 18347 _enable: function() { 18348 18349 // restore title attributes 18350 this.disabledTitles.each( function() { 18351 var element = $( this ); 18352 if ( element.data( "ui-tooltip-title" ) ) { 18353 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18354 } 18355 } ); 18356 this.disabledTitles = $( [] ); 18357 }, 18358 18359 open: function( event ) { 18360 var that = this, 18361 target = $( event ? event.target : this.element ) 18362 18363 // we need closest here due to mouseover bubbling, 18364 // but always pointing at the same event target 18365 .closest( this.options.items ); 18366 18367 // No element to show a tooltip for or the tooltip is already open 18368 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 18369 return; 18370 } 18371 18372 if ( target.attr( "title" ) ) { 18373 target.data( "ui-tooltip-title", target.attr( "title" ) ); 18374 } 18375 18376 target.data( "ui-tooltip-open", true ); 18377 18378 // Kill parent tooltips, custom or native, for hover 18379 if ( event && event.type === "mouseover" ) { 18380 target.parents().each( function() { 18381 var parent = $( this ), 18382 blurEvent; 18383 if ( parent.data( "ui-tooltip-open" ) ) { 18384 blurEvent = $.Event( "blur" ); 18385 blurEvent.target = blurEvent.currentTarget = this; 18386 that.close( blurEvent, true ); 18387 } 18388 if ( parent.attr( "title" ) ) { 18389 parent.uniqueId(); 18390 that.parents[ this.id ] = { 18391 element: this, 18392 title: parent.attr( "title" ) 18393 }; 18394 parent.attr( "title", "" ); 18395 } 18396 } ); 18397 } 18398 18399 this._registerCloseHandlers( event, target ); 18400 this._updateContent( target, event ); 18401 }, 18402 18403 _updateContent: function( target, event ) { 18404 var content, 18405 contentOption = this.options.content, 18406 that = this, 18407 eventType = event ? event.type : null; 18408 18409 if ( typeof contentOption === "string" || contentOption.nodeType || 18410 contentOption.jquery ) { 18411 return this._open( event, target, contentOption ); 18412 } 18413 18414 content = contentOption.call( target[ 0 ], function( response ) { 18415 18416 // IE may instantly serve a cached response for ajax requests 18417 // delay this call to _open so the other call to _open runs first 18418 that._delay( function() { 18419 18420 // Ignore async response if tooltip was closed already 18421 if ( !target.data( "ui-tooltip-open" ) ) { 18422 return; 18423 } 18424 18425 // JQuery creates a special event for focusin when it doesn't 18426 // exist natively. To improve performance, the native event 18427 // object is reused and the type is changed. Therefore, we can't 18428 // rely on the type being correct after the event finished 18429 // bubbling, so we set it back to the previous value. (#8740) 18430 if ( event ) { 18431 event.type = eventType; 18432 } 18433 this._open( event, target, response ); 18434 } ); 18435 } ); 18436 if ( content ) { 18437 this._open( event, target, content ); 18438 } 18439 }, 18440 18441 _open: function( event, target, content ) { 18442 var tooltipData, tooltip, delayedShow, a11yContent, 18443 positionOption = $.extend( {}, this.options.position ); 18444 18445 if ( !content ) { 18446 return; 18447 } 18448 18449 // Content can be updated multiple times. If the tooltip already 18450 // exists, then just update the content and bail. 18451 tooltipData = this._find( target ); 18452 if ( tooltipData ) { 18453 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); 18454 return; 18455 } 18456 18457 // If we have a title, clear it to prevent the native tooltip 18458 // we have to check first to avoid defining a title if none exists 18459 // (we don't want to cause an element to start matching [title]) 18460 // 18461 // We use removeAttr only for key events, to allow IE to export the correct 18462 // accessible attributes. For mouse events, set to empty string to avoid 18463 // native tooltip showing up (happens only when removing inside mouseover). 18464 if ( target.is( "[title]" ) ) { 18465 if ( event && event.type === "mouseover" ) { 18466 target.attr( "title", "" ); 18467 } else { 18468 target.removeAttr( "title" ); 18469 } 18470 } 18471 18472 tooltipData = this._tooltip( target ); 18473 tooltip = tooltipData.tooltip; 18474 this._addDescribedBy( target, tooltip.attr( "id" ) ); 18475 tooltip.find( ".ui-tooltip-content" ).html( content ); 18476 18477 // Support: Voiceover on OS X, JAWS on IE <= 9 18478 // JAWS announces deletions even when aria-relevant="additions" 18479 // Voiceover will sometimes re-read the entire log region's contents from the beginning 18480 this.liveRegion.children().hide(); 18481 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() ); 18482 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); 18483 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 18484 a11yContent.appendTo( this.liveRegion ); 18485 18486 function position( event ) { 18487 positionOption.of = event; 18488 if ( tooltip.is( ":hidden" ) ) { 18489 return; 18490 } 18491 tooltip.position( positionOption ); 18492 } 18493 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 18494 this._on( this.document, { 18495 mousemove: position 18496 } ); 18497 18498 // trigger once to override element-relative positioning 18499 position( event ); 18500 } else { 18501 tooltip.position( $.extend( { 18502 of: target 18503 }, this.options.position ) ); 18504 } 18505 18506 tooltip.hide(); 18507 18508 this._show( tooltip, this.options.show ); 18509 18510 // Handle tracking tooltips that are shown with a delay (#8644). As soon 18511 // as the tooltip is visible, position the tooltip using the most recent 18512 // event. 18513 // Adds the check to add the timers only when both delay and track options are set (#14682) 18514 if ( this.options.track && this.options.show && this.options.show.delay ) { 18515 delayedShow = this.delayedShow = setInterval( function() { 18516 if ( tooltip.is( ":visible" ) ) { 18517 position( positionOption.of ); 18518 clearInterval( delayedShow ); 18519 } 18520 }, $.fx.interval ); 18521 } 18522 18523 this._trigger( "open", event, { tooltip: tooltip } ); 18524 }, 18525 18526 _registerCloseHandlers: function( event, target ) { 18527 var events = { 18528 keyup: function( event ) { 18529 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 18530 var fakeEvent = $.Event( event ); 18531 fakeEvent.currentTarget = target[ 0 ]; 18532 this.close( fakeEvent, true ); 18533 } 18534 } 18535 }; 18536 18537 // Only bind remove handler for delegated targets. Non-delegated 18538 // tooltips will handle this in destroy. 18539 if ( target[ 0 ] !== this.element[ 0 ] ) { 18540 events.remove = function() { 18541 this._removeTooltip( this._find( target ).tooltip ); 18542 }; 18543 } 18544 18545 if ( !event || event.type === "mouseover" ) { 18546 events.mouseleave = "close"; 18547 } 18548 if ( !event || event.type === "focusin" ) { 18549 events.focusout = "close"; 18550 } 18551 this._on( true, target, events ); 18552 }, 18553 18554 close: function( event ) { 18555 var tooltip, 18556 that = this, 18557 target = $( event ? event.currentTarget : this.element ), 18558 tooltipData = this._find( target ); 18559 18560 // The tooltip may already be closed 18561 if ( !tooltipData ) { 18562 18563 // We set ui-tooltip-open immediately upon open (in open()), but only set the 18564 // additional data once there's actually content to show (in _open()). So even if the 18565 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in 18566 // the period between open() and _open(). 18567 target.removeData( "ui-tooltip-open" ); 18568 return; 18569 } 18570 18571 tooltip = tooltipData.tooltip; 18572 18573 // Disabling closes the tooltip, so we need to track when we're closing 18574 // to avoid an infinite loop in case the tooltip becomes disabled on close 18575 if ( tooltipData.closing ) { 18576 return; 18577 } 18578 18579 // Clear the interval for delayed tracking tooltips 18580 clearInterval( this.delayedShow ); 18581 18582 // Only set title if we had one before (see comment in _open()) 18583 // If the title attribute has changed since open(), don't restore 18584 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 18585 target.attr( "title", target.data( "ui-tooltip-title" ) ); 18586 } 18587 18588 this._removeDescribedBy( target ); 18589 18590 tooltipData.hiding = true; 18591 tooltip.stop( true ); 18592 this._hide( tooltip, this.options.hide, function() { 18593 that._removeTooltip( $( this ) ); 18594 } ); 18595 18596 target.removeData( "ui-tooltip-open" ); 18597 this._off( target, "mouseleave focusout keyup" ); 18598 18599 // Remove 'remove' binding only on delegated targets 18600 if ( target[ 0 ] !== this.element[ 0 ] ) { 18601 this._off( target, "remove" ); 18602 } 18603 this._off( this.document, "mousemove" ); 18604 18605 if ( event && event.type === "mouseleave" ) { 18606 $.each( this.parents, function( id, parent ) { 18607 $( parent.element ).attr( "title", parent.title ); 18608 delete that.parents[ id ]; 18609 } ); 18610 } 18611 18612 tooltipData.closing = true; 18613 this._trigger( "close", event, { tooltip: tooltip } ); 18614 if ( !tooltipData.hiding ) { 18615 tooltipData.closing = false; 18616 } 18617 }, 18618 18619 _tooltip: function( element ) { 18620 var tooltip = $( "<div>" ).attr( "role", "tooltip" ), 18621 content = $( "<div>" ).appendTo( tooltip ), 18622 id = tooltip.uniqueId().attr( "id" ); 18623 18624 this._addClass( content, "ui-tooltip-content" ); 18625 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); 18626 18627 tooltip.appendTo( this._appendTo( element ) ); 18628 18629 return this.tooltips[ id ] = { 18630 element: element, 18631 tooltip: tooltip 18632 }; 18633 }, 18634 18635 _find: function( target ) { 18636 var id = target.data( "ui-tooltip-id" ); 18637 return id ? this.tooltips[ id ] : null; 18638 }, 18639 18640 _removeTooltip: function( tooltip ) { 18641 tooltip.remove(); 18642 delete this.tooltips[ tooltip.attr( "id" ) ]; 18643 }, 18644 18645 _appendTo: function( target ) { 18646 var element = target.closest( ".ui-front, dialog" ); 18647 18648 if ( !element.length ) { 18649 element = this.document[ 0 ].body; 18650 } 18651 18652 return element; 18653 }, 18654 18655 _destroy: function() { 18656 var that = this; 18657 18658 // Close open tooltips 18659 $.each( this.tooltips, function( id, tooltipData ) { 18660 18661 // Delegate to close method to handle common cleanup 18662 var event = $.Event( "blur" ), 18663 element = tooltipData.element; 18664 event.target = event.currentTarget = element[ 0 ]; 18665 that.close( event, true ); 18666 18667 // Remove immediately; destroying an open tooltip doesn't use the 18668 // hide animation 18669 $( "#" + id ).remove(); 18670 18671 // Restore the title 18672 if ( element.data( "ui-tooltip-title" ) ) { 18673 18674 // If the title attribute has changed since open(), don't restore 18675 if ( !element.attr( "title" ) ) { 18676 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18677 } 18678 element.removeData( "ui-tooltip-title" ); 18679 } 18680 } ); 18681 this.liveRegion.remove(); 18682 } 18683 } ); 18684 18685 // DEPRECATED 18686 // TODO: Switch return back to widget declaration at top of file when this is removed 18687 if ( $.uiBackCompat !== false ) { 18688 18689 // Backcompat for tooltipClass option 18690 $.widget( "ui.tooltip", $.ui.tooltip, { 18691 options: { 18692 tooltipClass: null 18693 }, 18694 _tooltip: function() { 18695 var tooltipData = this._superApply( arguments ); 18696 if ( this.options.tooltipClass ) { 18697 tooltipData.tooltip.addClass( this.options.tooltipClass ); 18698 } 18699 return tooltipData; 18700 } 18701 } ); 18702 } 18703 18704 var widgetsTooltip = $.ui.tooltip; 18705 18706 18707 18708 18709 }));