vendor: 500,580 bytes, lines 1-17463
1/*! jQuery UI - v1.14.1 - 2024-10-30 2* https://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-patch.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 OpenJS Foundation and other contributors; Licensed MIT */ 5 6( function( factory ) { 7 "use strict"; 8 9 if ( typeof define === "function" && define.amd ) { 10 11 // AMD. Register as an anonymous module. 12 define( [ "jquery" ], factory ); 13 } else { 14 15 // Browser globals 16 factory( jQuery ); 17 } 18} )( function( $ ) { 19 "use strict"; 20 21 $.ui = $.ui || {}; 22 23 var version = $.ui.version = "1.14.1"; 24 25 26 /*! 27 * jQuery UI Widget 1.14.1 28 * https://jqueryui.com 29 * 30 * Copyright OpenJS Foundation and other contributors 31 * Released under the MIT license. 32 * https://jquery.org/license 33 */ 34 35//>>label: Widget 36//>>group: Core 37//>>description: Provides a factory for creating stateful widgets with a common API. 38//>>docs: https://api.jqueryui.com/jQuery.widget/ 39//>>demos: https://jqueryui.com/widget/ 40 41 42 var widgetUuid = 0; 43 var widgetHasOwnProperty = Array.prototype.hasOwnProperty; 44 var widgetSlice = Array.prototype.slice; 45 46 $.cleanData = ( function( orig ) { 47 return function( elems ) { 48 var events, elem, i; 49 for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { 50 51 // Only trigger remove when necessary to save time 52 events = $._data( elem, "events" ); 53 if ( events && events.remove ) { 54 $( elem ).triggerHandler( "remove" ); 55 } 56 } 57 orig( elems ); 58 }; 59 } )( $.cleanData ); 60 61 $.widget = function( name, base, prototype ) { 62 var existingConstructor, constructor, basePrototype; 63 64 // ProxiedPrototype allows the provided prototype to remain unmodified 65 // so that it can be used as a mixin for multiple widgets (#8876) 66 var proxiedPrototype = {}; 67 68 var namespace = name.split( "." )[ 0 ]; 69 name = name.split( "." )[ 1 ]; 70 if ( name === "__proto__" || name === "constructor" ) { 71 return $.error( "Invalid widget name: " + name ); 72 } 73 var fullName = namespace + "-" + name; 74 75 if ( !prototype ) { 76 prototype = base; 77 base = $.Widget; 78 } 79 80 if ( Array.isArray( prototype ) ) { 81 prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); 82 } 83 84 // Create selector for plugin 85 $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) { 86 return !!$.data( elem, fullName ); 87 }; 88 89 $[ namespace ] = $[ namespace ] || {}; 90 existingConstructor = $[ namespace ][ name ]; 91 constructor = $[ namespace ][ name ] = function( options, element ) { 92 93 // Allow instantiation without "new" keyword 94 if ( !this || !this._createWidget ) { 95 return new constructor( options, element ); 96 } 97 98 // Allow instantiation without initializing for simple inheritance 99 // must use "new" keyword (the code above always passes args) 100 if ( arguments.length ) { 101 this._createWidget( options, element ); 102 } 103 }; 104 105 // Extend with the existing constructor to carry over any static properties 106 $.extend( constructor, existingConstructor, { 107 version: prototype.version, 108 109 // Copy the object used to create the prototype in case we need to 110 // redefine the widget later 111 _proto: $.extend( {}, prototype ), 112 113 // Track widgets that inherit from this widget in case this widget is 114 // redefined after a widget inherits from it 115 _childConstructors: [] 116 } ); 117 118 basePrototype = new base(); 119 120 // We need to make the options hash a property directly on the new instance 121 // otherwise we'll modify the options hash on the prototype that we're 122 // inheriting from 123 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 124 $.each( prototype, function( prop, value ) { 125 if ( typeof value !== "function" ) { 126 proxiedPrototype[ prop ] = value; 127 return; 128 } 129 proxiedPrototype[ prop ] = ( function() { 130 function _super() { 131 return base.prototype[ prop ].apply( this, arguments ); 132 } 133 134 function _superApply( args ) { 135 return base.prototype[ prop ].apply( this, args ); 136 } 137 138 return function() { 139 var __super = this._super; 140 var __superApply = this._superApply; 141 var returnValue; 142 143 this._super = _super; 144 this._superApply = _superApply; 145 146 returnValue = value.apply( this, arguments ); 147 148 this._super = __super; 149 this._superApply = __superApply; 150 151 return returnValue; 152 }; 153 } )(); 154 } ); 155 constructor.prototype = $.widget.extend( basePrototype, { 156 157 // TODO: remove support for widgetEventPrefix 158 // always use the name + a colon as the prefix, e.g., draggable:start 159 // don't prefix for widgets that aren't DOM-based 160 widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name 161 }, proxiedPrototype, { 162 constructor: constructor, 163 namespace: namespace, 164 widgetName: name, 165 widgetFullName: fullName 166 } ); 167 168 // If this widget is being redefined then we need to find all widgets that 169 // are inheriting from it and redefine all of them so that they inherit from 170 // the new version of this widget. We're essentially trying to replace one 171 // level in the prototype chain. 172 if ( existingConstructor ) { 173 $.each( existingConstructor._childConstructors, function( i, child ) { 174 var childPrototype = child.prototype; 175 176 // Redefine the child widget using the same prototype that was 177 // originally used, but inherit from the new version of the base 178 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, 179 child._proto ); 180 } ); 181 182 // Remove the list of existing child constructors from the old constructor 183 // so the old child constructors can be garbage collected 184 delete existingConstructor._childConstructors; 185 } else { 186 base._childConstructors.push( constructor ); 187 } 188 189 $.widget.bridge( name, constructor ); 190 191 return constructor; 192 }; 193 194 $.widget.extend = function( target ) { 195 var input = widgetSlice.call( arguments, 1 ); 196 var inputIndex = 0; 197 var inputLength = input.length; 198 var key; 199 var value; 200 201 for ( ; inputIndex < inputLength; inputIndex++ ) { 202 for ( key in input[ inputIndex ] ) { 203 value = input[ inputIndex ][ key ]; 204 if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) { 205 206 // Clone objects 207 if ( $.isPlainObject( value ) ) { 208 target[ key ] = $.isPlainObject( target[ key ] ) ? 209 $.widget.extend( {}, target[ key ], value ) : 210 211 // Don't extend strings, arrays, etc. with objects 212 $.widget.extend( {}, value ); 213 214 // Copy everything else by reference 215 } else { 216 target[ key ] = value; 217 } 218 } 219 } 220 } 221 return target; 222 }; 223 224 $.widget.bridge = function( name, object ) { 225 var fullName = object.prototype.widgetFullName || name; 226 $.fn[ name ] = function( options ) { 227 var isMethodCall = typeof options === "string"; 228 var args = widgetSlice.call( arguments, 1 ); 229 var returnValue = this; 230 231 if ( isMethodCall ) { 232 233 // If this is an empty collection, we need to have the instance method 234 // return undefined instead of the jQuery instance 235 if ( !this.length && options === "instance" ) { 236 returnValue = undefined; 237 } else { 238 this.each( function() { 239 var methodValue; 240 var instance = $.data( this, fullName ); 241 242 if ( options === "instance" ) { 243 returnValue = instance; 244 return false; 245 } 246 247 if ( !instance ) { 248 return $.error( "cannot call methods on " + name + 249 " prior to initialization; " + 250 "attempted to call method '" + options + "'" ); 251 } 252 253 if ( typeof instance[ options ] !== "function" || 254 options.charAt( 0 ) === "_" ) { 255 return $.error( "no such method '" + options + "' for " + name + 256 " widget instance" ); 257 } 258 259 methodValue = instance[ options ].apply( instance, args ); 260 261 if ( methodValue !== instance && methodValue !== undefined ) { 262 returnValue = methodValue && methodValue.jquery ? 263 returnValue.pushStack( methodValue.get() ) : 264 methodValue; 265 return false; 266 } 267 } ); 268 } 269 } else { 270 271 // Allow multiple hashes to be passed on init 272 if ( args.length ) { 273 options = $.widget.extend.apply( null, [ options ].concat( args ) ); 274 } 275 276 this.each( function() { 277 var instance = $.data( this, fullName ); 278 if ( instance ) { 279 instance.option( options || {} ); 280 if ( instance._init ) { 281 instance._init(); 282 } 283 } else { 284 $.data( this, fullName, new object( options, this ) ); 285 } 286 } ); 287 } 288 289 return returnValue; 290 }; 291 }; 292 293 $.Widget = function( /* options, element */ ) {}; 294 $.Widget._childConstructors = []; 295 296 $.Widget.prototype = { 297 widgetName: "widget", 298 widgetEventPrefix: "", 299 defaultElement: "<div>", 300 301 options: { 302 classes: {}, 303 disabled: false, 304 305 // Callbacks 306 create: null 307 }, 308 309 _createWidget: function( options, element ) { 310 element = $( element || this.defaultElement || this )[ 0 ]; 311 this.element = $( element ); 312 this.uuid = widgetUuid++; 313 this.eventNamespace = "." + this.widgetName + this.uuid; 314 315 this.bindings = $(); 316 this.hoverable = $(); 317 this.focusable = $(); 318 this.classesElementLookup = {}; 319 320 if ( element !== this ) { 321 $.data( element, this.widgetFullName, this ); 322 this._on( true, this.element, { 323 remove: function( event ) { 324 if ( event.target === element ) { 325 this.destroy(); 326 } 327 } 328 } ); 329 this.document = $( element.style ? 330 331 // Element within the document 332 element.ownerDocument : 333 334 // Element is window or document 335 element.document || element ); 336 this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); 337 } 338 339 this.options = $.widget.extend( {}, 340 this.options, 341 this._getCreateOptions(), 342 options ); 343 344 this._create(); 345 346 if ( this.options.disabled ) { 347 this._setOptionDisabled( this.options.disabled ); 348 } 349 350 this._trigger( "create", null, this._getCreateEventData() ); 351 this._init(); 352 }, 353 354 _getCreateOptions: function() { 355 return {}; 356 }, 357 358 _getCreateEventData: $.noop, 359 360 _create: $.noop, 361 362 _init: $.noop, 363 364 destroy: function() { 365 var that = this; 366 367 this._destroy(); 368 $.each( this.classesElementLookup, function( key, value ) { 369 that._removeClass( value, key ); 370 } ); 371 372 // We can probably remove the unbind calls in 2.0 373 // all event bindings should go through this._on() 374 this.element 375 .off( this.eventNamespace ) 376 .removeData( this.widgetFullName ); 377 this.widget() 378 .off( this.eventNamespace ) 379 .removeAttr( "aria-disabled" ); 380 381 // Clean up events and states 382 this.bindings.off( this.eventNamespace ); 383 }, 384 385 _destroy: $.noop, 386 387 widget: function() { 388 return this.element; 389 }, 390 391 option: function( key, value ) { 392 var options = key; 393 var parts; 394 var curOption; 395 var i; 396 397 if ( arguments.length === 0 ) { 398 399 // Don't return a reference to the internal hash 400 return $.widget.extend( {}, this.options ); 401 } 402 403 if ( typeof key === "string" ) { 404 405 // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 406 options = {}; 407 parts = key.split( "." ); 408 key = parts.shift(); 409 if ( parts.length ) { 410 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 411 for ( i = 0; i < parts.length - 1; i++ ) { 412 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 413 curOption = curOption[ parts[ i ] ]; 414 } 415 key = parts.pop(); 416 if ( arguments.length === 1 ) { 417 return curOption[ key ] === undefined ? null : curOption[ key ]; 418 } 419 curOption[ key ] = value; 420 } else { 421 if ( arguments.length === 1 ) { 422 return this.options[ key ] === undefined ? null : this.options[ key ]; 423 } 424 options[ key ] = value; 425 } 426 } 427 428 this._setOptions( options ); 429 430 return this; 431 }, 432 433 _setOptions: function( options ) { 434 var key; 435 436 for ( key in options ) { 437 this._setOption( key, options[ key ] ); 438 } 439 440 return this; 441 }, 442 443 _setOption: function( key, value ) { 444 if ( key === "classes" ) { 445 this._setOptionClasses( value ); 446 } 447 448 this.options[ key ] = value; 449 450 if ( key === "disabled" ) { 451 this._setOptionDisabled( value ); 452 } 453 454 return this; 455 }, 456 457 _setOptionClasses: function( value ) { 458 var classKey, elements, currentElements; 459 460 for ( classKey in value ) { 461 currentElements = this.classesElementLookup[ classKey ]; 462 if ( value[ classKey ] === this.options.classes[ classKey ] || 463 !currentElements || 464 !currentElements.length ) { 465 continue; 466 } 467 468 // We are doing this to create a new jQuery object because the _removeClass() call 469 // on the next line is going to destroy the reference to the current elements being 470 // tracked. We need to save a copy of this collection so that we can add the new classes 471 // below. 472 elements = $( currentElements.get() ); 473 this._removeClass( currentElements, classKey ); 474 475 // We don't use _addClass() here, because that uses this.options.classes 476 // for generating the string of classes. We want to use the value passed in from 477 // _setOption(), this is the new value of the classes option which was passed to 478 // _setOption(). We pass this value directly to _classes(). 479 elements.addClass( this._classes( { 480 element: elements, 481 keys: classKey, 482 classes: value, 483 add: true 484 } ) ); 485 } 486 }, 487 488 _setOptionDisabled: function( value ) { 489 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); 490 491 // If the widget is becoming disabled, then nothing is interactive 492 if ( value ) { 493 this._removeClass( this.hoverable, null, "ui-state-hover" ); 494 this._removeClass( this.focusable, null, "ui-state-focus" ); 495 } 496 }, 497 498 enable: function() { 499 return this._setOptions( { disabled: false } ); 500 }, 501 502 disable: function() { 503 return this._setOptions( { disabled: true } ); 504 }, 505 506 _classes: function( options ) { 507 var full = []; 508 var that = this; 509 510 options = $.extend( { 511 element: this.element, 512 classes: this.options.classes || {} 513 }, options ); 514 515 function bindRemoveEvent() { 516 var nodesToBind = []; 517 518 options.element.each( function( _, element ) { 519 var isTracked = $.map( that.classesElementLookup, function( elements ) { 520 return elements; 521 } ) 522 .some( function( elements ) { 523 return elements.is( element ); 524 } ); 525 526 if ( !isTracked ) { 527 nodesToBind.push( element ); 528 } 529 } ); 530 531 that._on( $( nodesToBind ), { 532 remove: "_untrackClassesElement" 533 } ); 534 } 535 536 function processClassString( classes, checkOption ) { 537 var current, i; 538 for ( i = 0; i < classes.length; i++ ) { 539 current = that.classesElementLookup[ classes[ i ] ] || $(); 540 if ( options.add ) { 541 bindRemoveEvent(); 542 current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) ); 543 } else { 544 current = $( current.not( options.element ).get() ); 545 } 546 that.classesElementLookup[ classes[ i ] ] = current; 547 full.push( classes[ i ] ); 548 if ( checkOption && options.classes[ classes[ i ] ] ) { 549 full.push( options.classes[ classes[ i ] ] ); 550 } 551 } 552 } 553 554 if ( options.keys ) { 555 processClassString( options.keys.match( /\S+/g ) || [], true ); 556 } 557 if ( options.extra ) { 558 processClassString( options.extra.match( /\S+/g ) || [] ); 559 } 560 561 return full.join( " " ); 562 }, 563 564 _untrackClassesElement: function( event ) { 565 var that = this; 566 $.each( that.classesElementLookup, function( key, value ) { 567 if ( $.inArray( event.target, value ) !== -1 ) { 568 that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); 569 } 570 } ); 571 572 this._off( $( event.target ) ); 573 }, 574 575 _removeClass: function( element, keys, extra ) { 576 return this._toggleClass( element, keys, extra, false ); 577 }, 578 579 _addClass: function( element, keys, extra ) { 580 return this._toggleClass( element, keys, extra, true ); 581 }, 582 583 _toggleClass: function( element, keys, extra, add ) { 584 add = ( typeof add === "boolean" ) ? add : extra; 585 var shift = ( typeof element === "string" || element === null ), 586 options = { 587 extra: shift ? keys : extra, 588 keys: shift ? element : keys, 589 element: shift ? this.element : element, 590 add: add 591 }; 592 options.element.toggleClass( this._classes( options ), add ); 593 return this; 594 }, 595 596 _on: function( suppressDisabledCheck, element, handlers ) { 597 var delegateElement; 598 var instance = this; 599 600 // No suppressDisabledCheck flag, shuffle arguments 601 if ( typeof suppressDisabledCheck !== "boolean" ) { 602 handlers = element; 603 element = suppressDisabledCheck; 604 suppressDisabledCheck = false; 605 } 606 607 // No element argument, shuffle and use this.element 608 if ( !handlers ) { 609 handlers = element; 610 element = this.element; 611 delegateElement = this.widget(); 612 } else { 613 element = delegateElement = $( element ); 614 this.bindings = this.bindings.add( element ); 615 } 616 617 $.each( handlers, function( event, handler ) { 618 function handlerProxy() { 619 620 // Allow widgets to customize the disabled handling 621 // - disabled as an array instead of boolean 622 // - disabled class as method for disabling individual parts 623 if ( !suppressDisabledCheck && 624 ( instance.options.disabled === true || 625 $( this ).hasClass( "ui-state-disabled" ) ) ) { 626 return; 627 } 628 return ( typeof handler === "string" ? instance[ handler ] : handler ) 629 .apply( instance, arguments ); 630 } 631 632 // Copy the guid so direct unbinding works 633 if ( typeof handler !== "string" ) { 634 handlerProxy.guid = handler.guid = 635 handler.guid || handlerProxy.guid || $.guid++; 636 } 637 638 var match = event.match( /^([\w:-]*)\s*(.*)$/ ); 639 var eventName = match[ 1 ] + instance.eventNamespace; 640 var selector = match[ 2 ]; 641 642 if ( selector ) { 643 delegateElement.on( eventName, selector, handlerProxy ); 644 } else { 645 element.on( eventName, handlerProxy ); 646 } 647 } ); 648 }, 649 650 _off: function( element, eventName ) { 651 eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + 652 this.eventNamespace; 653 element.off( eventName ); 654 655 // Clear the stack to avoid memory leaks (#10056) 656 this.bindings = $( this.bindings.not( element ).get() ); 657 this.focusable = $( this.focusable.not( element ).get() ); 658 this.hoverable = $( this.hoverable.not( element ).get() ); 659 }, 660 661 _delay: function( handler, delay ) { 662 function handlerProxy() { 663 return ( typeof handler === "string" ? instance[ handler ] : handler ) 664 .apply( instance, arguments ); 665 } 666 var instance = this; 667 return setTimeout( handlerProxy, delay || 0 ); 668 }, 669 670 _hoverable: function( element ) { 671 this.hoverable = this.hoverable.add( element ); 672 this._on( element, { 673 mouseenter: function( event ) { 674 this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); 675 }, 676 mouseleave: function( event ) { 677 this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); 678 } 679 } ); 680 }, 681 682 _focusable: function( element ) { 683 this.focusable = this.focusable.add( element ); 684 this._on( element, { 685 focusin: function( event ) { 686 this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); 687 }, 688 focusout: function( event ) { 689 this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); 690 } 691 } ); 692 }, 693 694 _trigger: function( type, event, data ) { 695 var prop, orig; 696 var callback = this.options[ type ]; 697 698 data = data || {}; 699 event = $.Event( event ); 700 event.type = ( type === this.widgetEventPrefix ? 701 type : 702 this.widgetEventPrefix + type ).toLowerCase(); 703 704 // The original event may come from any element 705 // so we need to reset the target on the new event 706 event.target = this.element[ 0 ]; 707 708 // Copy original event properties over to the new event 709 orig = event.originalEvent; 710 if ( orig ) { 711 for ( prop in orig ) { 712 if ( !( prop in event ) ) { 713 event[ prop ] = orig[ prop ]; 714 } 715 } 716 } 717 718 this.element.trigger( event, data ); 719 return !( typeof callback === "function" && 720 callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || 721 event.isDefaultPrevented() ); 722 } 723 }; 724 725 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 726 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 727 if ( typeof options === "string" ) { 728 options = { effect: options }; 729 } 730 731 var hasOptions; 732 var effectName = !options ? 733 method : 734 options === true || typeof options === "number" ? 735 defaultEffect : 736 options.effect || defaultEffect; 737 738 options = options || {}; 739 if ( typeof options === "number" ) { 740 options = { duration: options }; 741 } else if ( options === true ) { 742 options = {}; 743 } 744 745 hasOptions = !$.isEmptyObject( options ); 746 options.complete = callback; 747 748 if ( options.delay ) { 749 element.delay( options.delay ); 750 } 751 752 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 753 element[ method ]( options ); 754 } else if ( effectName !== method && element[ effectName ] ) { 755 element[ effectName ]( options.duration, options.easing, callback ); 756 } else { 757 element.queue( function( next ) { 758 $( this )[ method ](); 759 if ( callback ) { 760 callback.call( element[ 0 ] ); 761 } 762 next(); 763 } ); 764 } 765 }; 766 } ); 767 768 var widget = $.widget; 769 770 771 /*! 772 * jQuery UI Position 1.14.1 773 * https://jqueryui.com 774 * 775 * Copyright OpenJS Foundation and other contributors 776 * Released under the MIT license. 777 * https://jquery.org/license 778 * 779 * https://api.jqueryui.com/position/ 780 */ 781 782//>>label: Position 783//>>group: Core 784//>>description: Positions elements relative to other elements. 785//>>docs: https://api.jqueryui.com/position/ 786//>>demos: https://jqueryui.com/position/ 787 788 789 ( function() { 790 var cachedScrollbarWidth, 791 max = Math.max, 792 abs = Math.abs, 793 rhorizontal = /left|center|right/, 794 rvertical = /top|center|bottom/, 795 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 796 rposition = /^\w+/, 797 rpercent = /%$/, 798 _position = $.fn.position; 799 800 function getOffsets( offsets, width, height ) { 801 return [ 802 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 803 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 804 ]; 805 } 806 807 function parseCss( element, property ) { 808 return parseInt( $.css( element, property ), 10 ) || 0; 809 } 810 811 function isWindow( obj ) { 812 return obj != null && obj === obj.window; 813 } 814 815 function getDimensions( elem ) { 816 var raw = elem[ 0 ]; 817 if ( raw.nodeType === 9 ) { 818 return { 819 width: elem.width(), 820 height: elem.height(), 821 offset: { top: 0, left: 0 } 822 }; 823 } 824 if ( isWindow( raw ) ) { 825 return { 826 width: elem.width(), 827 height: elem.height(), 828 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 829 }; 830 } 831 if ( raw.preventDefault ) { 832 return { 833 width: 0, 834 height: 0, 835 offset: { top: raw.pageY, left: raw.pageX } 836 }; 837 } 838 return { 839 width: elem.outerWidth(), 840 height: elem.outerHeight(), 841 offset: elem.offset() 842 }; 843 } 844 845 $.position = { 846 scrollbarWidth: function() { 847 if ( cachedScrollbarWidth !== undefined ) { 848 return cachedScrollbarWidth; 849 } 850 var w1, w2, 851 div = $( "<div style=" + 852 "'display:block;position:absolute;width:200px;height:200px;overflow:hidden;'>" + 853 "<div style='height:300px;width:auto;'></div></div>" ), 854 innerDiv = div.children()[ 0 ]; 855 856 $( "body" ).append( div ); 857 w1 = innerDiv.offsetWidth; 858 div.css( "overflow", "scroll" ); 859 860 w2 = innerDiv.offsetWidth; 861 862 if ( w1 === w2 ) { 863 w2 = div[ 0 ].clientWidth; 864 } 865 866 div.remove(); 867 868 return ( cachedScrollbarWidth = w1 - w2 ); 869 }, 870 getScrollInfo: function( within ) { 871 var overflowX = within.isWindow || within.isDocument ? "" : 872 within.element.css( "overflow-x" ), 873 overflowY = within.isWindow || within.isDocument ? "" : 874 within.element.css( "overflow-y" ), 875 hasOverflowX = overflowX === "scroll" || 876 ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), 877 hasOverflowY = overflowY === "scroll" || 878 ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); 879 return { 880 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 881 height: hasOverflowX ? $.position.scrollbarWidth() : 0 882 }; 883 }, 884 getWithinInfo: function( element ) { 885 var withinElement = $( element || window ), 886 isElemWindow = isWindow( withinElement[ 0 ] ), 887 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, 888 hasOffset = !isElemWindow && !isDocument; 889 return { 890 element: withinElement, 891 isWindow: isElemWindow, 892 isDocument: isDocument, 893 offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, 894 scrollLeft: withinElement.scrollLeft(), 895 scrollTop: withinElement.scrollTop(), 896 width: withinElement.outerWidth(), 897 height: withinElement.outerHeight() 898 }; 899 } 900 }; 901 902 $.fn.position = function( options ) { 903 if ( !options || !options.of ) { 904 return _position.apply( this, arguments ); 905 } 906 907 // Make a copy, we don't want to modify arguments 908 options = $.extend( {}, options ); 909 910 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 911 912 // Make sure string options are treated as CSS selectors 913 target = typeof options.of === "string" ? 914 $( document ).find( options.of ) : 915 $( options.of ), 916 917 within = $.position.getWithinInfo( options.within ), 918 scrollInfo = $.position.getScrollInfo( within ), 919 collision = ( options.collision || "flip" ).split( " " ), 920 offsets = {}; 921 922 dimensions = getDimensions( target ); 923 if ( target[ 0 ].preventDefault ) { 924 925 // Force left top to allow flipping 926 options.at = "left top"; 927 } 928 targetWidth = dimensions.width; 929 targetHeight = dimensions.height; 930 targetOffset = dimensions.offset; 931 932 // Clone to reuse original targetOffset later 933 basePosition = $.extend( {}, targetOffset ); 934 935 // Force my and at to have valid horizontal and vertical positions 936 // if a value is missing or invalid, it will be converted to center 937 $.each( [ "my", "at" ], function() { 938 var pos = ( options[ this ] || "" ).split( " " ), 939 horizontalOffset, 940 verticalOffset; 941 942 if ( pos.length === 1 ) { 943 pos = rhorizontal.test( pos[ 0 ] ) ? 944 pos.concat( [ "center" ] ) : 945 rvertical.test( pos[ 0 ] ) ? 946 [ "center" ].concat( pos ) : 947 [ "center", "center" ]; 948 } 949 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 950 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 951 952 // Calculate offsets 953 horizontalOffset = roffset.exec( pos[ 0 ] ); 954 verticalOffset = roffset.exec( pos[ 1 ] ); 955 offsets[ this ] = [ 956 horizontalOffset ? horizontalOffset[ 0 ] : 0, 957 verticalOffset ? verticalOffset[ 0 ] : 0 958 ]; 959 960 // Reduce to just the positions without the offsets 961 options[ this ] = [ 962 rposition.exec( pos[ 0 ] )[ 0 ], 963 rposition.exec( pos[ 1 ] )[ 0 ] 964 ]; 965 } ); 966 967 // Normalize collision option 968 if ( collision.length === 1 ) { 969 collision[ 1 ] = collision[ 0 ]; 970 } 971 972 if ( options.at[ 0 ] === "right" ) { 973 basePosition.left += targetWidth; 974 } else if ( options.at[ 0 ] === "center" ) { 975 basePosition.left += targetWidth / 2; 976 } 977 978 if ( options.at[ 1 ] === "bottom" ) { 979 basePosition.top += targetHeight; 980 } else if ( options.at[ 1 ] === "center" ) { 981 basePosition.top += targetHeight / 2; 982 } 983 984 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 985 basePosition.left += atOffset[ 0 ]; 986 basePosition.top += atOffset[ 1 ]; 987 988 return this.each( function() { 989 var collisionPosition, using, 990 elem = $( this ), 991 elemWidth = elem.outerWidth(), 992 elemHeight = elem.outerHeight(), 993 marginLeft = parseCss( this, "marginLeft" ), 994 marginTop = parseCss( this, "marginTop" ), 995 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + 996 scrollInfo.width, 997 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + 998 scrollInfo.height, 999 position = $.extend( {}, basePosition ), 1000 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 1001 1002 if ( options.my[ 0 ] === "right" ) { 1003 position.left -= elemWidth; 1004 } else if ( options.my[ 0 ] === "center" ) { 1005 position.left -= elemWidth / 2; 1006 } 1007 1008 if ( options.my[ 1 ] === "bottom" ) { 1009 position.top -= elemHeight; 1010 } else if ( options.my[ 1 ] === "center" ) { 1011 position.top -= elemHeight / 2; 1012 } 1013 1014 position.left += myOffset[ 0 ]; 1015 position.top += myOffset[ 1 ]; 1016 1017 collisionPosition = { 1018 marginLeft: marginLeft, 1019 marginTop: marginTop 1020 }; 1021 1022 $.each( [ "left", "top" ], function( i, dir ) { 1023 if ( $.ui.position[ collision[ i ] ] ) { 1024 $.ui.position[ collision[ i ] ][ dir ]( position, { 1025 targetWidth: targetWidth, 1026 targetHeight: targetHeight, 1027 elemWidth: elemWidth, 1028 elemHeight: elemHeight, 1029 collisionPosition: collisionPosition, 1030 collisionWidth: collisionWidth, 1031 collisionHeight: collisionHeight, 1032 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 1033 my: options.my, 1034 at: options.at, 1035 within: within, 1036 elem: elem 1037 } ); 1038 } 1039 } ); 1040 1041 if ( options.using ) { 1042 1043 // Adds feedback as second argument to using callback, if present 1044 using = function( props ) { 1045 var left = targetOffset.left - position.left, 1046 right = left + targetWidth - elemWidth, 1047 top = targetOffset.top - position.top, 1048 bottom = top + targetHeight - elemHeight, 1049 feedback = { 1050 target: { 1051 element: target, 1052 left: targetOffset.left, 1053 top: targetOffset.top, 1054 width: targetWidth, 1055 height: targetHeight 1056 }, 1057 element: { 1058 element: elem, 1059 left: position.left, 1060 top: position.top, 1061 width: elemWidth, 1062 height: elemHeight 1063 }, 1064 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", 1065 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" 1066 }; 1067 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { 1068 feedback.horizontal = "center"; 1069 } 1070 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { 1071 feedback.vertical = "middle"; 1072 } 1073 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { 1074 feedback.important = "horizontal"; 1075 } else { 1076 feedback.important = "vertical"; 1077 } 1078 options.using.call( this, props, feedback ); 1079 }; 1080 } 1081 1082 elem.offset( $.extend( position, { using: using } ) ); 1083 } ); 1084 }; 1085 1086 $.ui.position = { 1087 fit: { 1088 left: function( position, data ) { 1089 var within = data.within, 1090 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, 1091 outerWidth = within.width, 1092 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1093 overLeft = withinOffset - collisionPosLeft, 1094 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, 1095 newOverRight; 1096 1097 // Element is wider than within 1098 if ( data.collisionWidth > outerWidth ) { 1099 1100 // Element is initially over the left side of within 1101 if ( overLeft > 0 && overRight <= 0 ) { 1102 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - 1103 withinOffset; 1104 position.left += overLeft - newOverRight; 1105 1106 // Element is initially over right side of within 1107 } else if ( overRight > 0 && overLeft <= 0 ) { 1108 position.left = withinOffset; 1109 1110 // Element is initially over both left and right sides of within 1111 } else { 1112 if ( overLeft > overRight ) { 1113 position.left = withinOffset + outerWidth - data.collisionWidth; 1114 } else { 1115 position.left = withinOffset; 1116 } 1117 } 1118 1119 // Too far left -> align with left edge 1120 } else if ( overLeft > 0 ) { 1121 position.left += overLeft; 1122 1123 // Too far right -> align with right edge 1124 } else if ( overRight > 0 ) { 1125 position.left -= overRight; 1126 1127 // Adjust based on position and margin 1128 } else { 1129 position.left = max( position.left - collisionPosLeft, position.left ); 1130 } 1131 }, 1132 top: function( position, data ) { 1133 var within = data.within, 1134 withinOffset = within.isWindow ? within.scrollTop : within.offset.top, 1135 outerHeight = data.within.height, 1136 collisionPosTop = position.top - data.collisionPosition.marginTop, 1137 overTop = withinOffset - collisionPosTop, 1138 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, 1139 newOverBottom; 1140 1141 // Element is taller than within 1142 if ( data.collisionHeight > outerHeight ) { 1143 1144 // Element is initially over the top of within 1145 if ( overTop > 0 && overBottom <= 0 ) { 1146 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - 1147 withinOffset; 1148 position.top += overTop - newOverBottom; 1149 1150 // Element is initially over bottom of within 1151 } else if ( overBottom > 0 && overTop <= 0 ) { 1152 position.top = withinOffset; 1153 1154 // Element is initially over both top and bottom of within 1155 } else { 1156 if ( overTop > overBottom ) { 1157 position.top = withinOffset + outerHeight - data.collisionHeight; 1158 } else { 1159 position.top = withinOffset; 1160 } 1161 } 1162 1163 // Too far up -> align with top 1164 } else if ( overTop > 0 ) { 1165 position.top += overTop; 1166 1167 // Too far down -> align with bottom edge 1168 } else if ( overBottom > 0 ) { 1169 position.top -= overBottom; 1170 1171 // Adjust based on position and margin 1172 } else { 1173 position.top = max( position.top - collisionPosTop, position.top ); 1174 } 1175 } 1176 }, 1177 flip: { 1178 left: function( position, data ) { 1179 var within = data.within, 1180 withinOffset = within.offset.left + within.scrollLeft, 1181 outerWidth = within.width, 1182 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, 1183 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1184 overLeft = collisionPosLeft - offsetLeft, 1185 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, 1186 myOffset = data.my[ 0 ] === "left" ? 1187 -data.elemWidth : 1188 data.my[ 0 ] === "right" ? 1189 data.elemWidth : 1190 0, 1191 atOffset = data.at[ 0 ] === "left" ? 1192 data.targetWidth : 1193 data.at[ 0 ] === "right" ? 1194 -data.targetWidth : 1195 0, 1196 offset = -2 * data.offset[ 0 ], 1197 newOverRight, 1198 newOverLeft; 1199 1200 if ( overLeft < 0 ) { 1201 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - 1202 outerWidth - withinOffset; 1203 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { 1204 position.left += myOffset + atOffset + offset; 1205 } 1206 } else if ( overRight > 0 ) { 1207 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + 1208 atOffset + offset - offsetLeft; 1209 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { 1210 position.left += myOffset + atOffset + offset; 1211 } 1212 } 1213 }, 1214 top: function( position, data ) { 1215 var within = data.within, 1216 withinOffset = within.offset.top + within.scrollTop, 1217 outerHeight = within.height, 1218 offsetTop = within.isWindow ? within.scrollTop : within.offset.top, 1219 collisionPosTop = position.top - data.collisionPosition.marginTop, 1220 overTop = collisionPosTop - offsetTop, 1221 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, 1222 top = data.my[ 1 ] === "top", 1223 myOffset = top ? 1224 -data.elemHeight : 1225 data.my[ 1 ] === "bottom" ? 1226 data.elemHeight : 1227 0, 1228 atOffset = data.at[ 1 ] === "top" ? 1229 data.targetHeight : 1230 data.at[ 1 ] === "bottom" ? 1231 -data.targetHeight : 1232 0, 1233 offset = -2 * data.offset[ 1 ], 1234 newOverTop, 1235 newOverBottom; 1236 if ( overTop < 0 ) { 1237 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - 1238 outerHeight - withinOffset; 1239 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { 1240 position.top += myOffset + atOffset + offset; 1241 } 1242 } else if ( overBottom > 0 ) { 1243 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + 1244 offset - offsetTop; 1245 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { 1246 position.top += myOffset + atOffset + offset; 1247 } 1248 } 1249 } 1250 }, 1251 flipfit: { 1252 left: function() { 1253 $.ui.position.flip.left.apply( this, arguments ); 1254 $.ui.position.fit.left.apply( this, arguments ); 1255 }, 1256 top: function() { 1257 $.ui.position.flip.top.apply( this, arguments ); 1258 $.ui.position.fit.top.apply( this, arguments ); 1259 } 1260 } 1261 }; 1262 1263 } )(); 1264 1265 var position = $.ui.position; 1266 1267 1268 /*! 1269 * jQuery UI :data 1.14.1 1270 * https://jqueryui.com 1271 * 1272 * Copyright OpenJS Foundation and other contributors 1273 * Released under the MIT license. 1274 * https://jquery.org/license 1275 */ 1276 1277//>>label: :data Selector 1278//>>group: Core 1279//>>description: Selects elements which have data stored under the specified key. 1280//>>docs: https://api.jqueryui.com/data-selector/ 1281 1282 1283 var data = $.extend( $.expr.pseudos, { 1284 data: $.expr.createPseudo( function( dataName ) { 1285 return function( elem ) { 1286 return !!$.data( elem, dataName ); 1287 }; 1288 } ) 1289 } ); 1290 1291 /*! 1292 * jQuery UI Disable Selection 1.14.1 1293 * https://jqueryui.com 1294 * 1295 * Copyright OpenJS Foundation and other contributors 1296 * Released under the MIT license. 1297 * https://jquery.org/license 1298 */ 1299 1300//>>label: disableSelection 1301//>>group: Core 1302//>>description: Disable selection of text content within the set of matched elements. 1303//>>docs: https://api.jqueryui.com/disableSelection/ 1304 1305// This file is deprecated 1306 1307 var disableSelection = $.fn.extend( { 1308 disableSelection: ( function() { 1309 var eventType = "onselectstart" in document.createElement( "div" ) ? 1310 "selectstart" : 1311 "mousedown"; 1312 1313 return function() { 1314 return this.on( eventType + ".ui-disableSelection", function( event ) { 1315 event.preventDefault(); 1316 } ); 1317 }; 1318 } )(), 1319 1320 enableSelection: function() { 1321 return this.off( ".ui-disableSelection" ); 1322 } 1323 } ); 1324 1325 1326 1327// Create a local jQuery because jQuery Color relies on it and the 1328// global may not exist with AMD and a custom build (#10199). 1329// This module is a noop if used as a regular AMD module. 1330// eslint-disable-next-line no-unused-vars 1331 var jQuery = $; 1332 1333 1334 /*! 1335 * jQuery Color Animations v3.0.0 1336 * https://github.com/jquery/jquery-color 1337 * 1338 * Copyright OpenJS Foundation and other contributors 1339 * Released under the MIT license. 1340 * https://jquery.org/license 1341 * 1342 * Date: Wed May 15 16:49:44 2024 +0200 1343 */ 1344 1345 1346 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + 1347 "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", 1348 1349 class2type = {}, 1350 toString = class2type.toString, 1351 1352 // plusequals test for += 100 -= 100 1353 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, 1354 1355 // a set of RE's that can match strings and generate color tuples. 1356 stringParsers = [ { 1357 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 1358 parse: function( execResult ) { 1359 return [ 1360 execResult[ 1 ], 1361 execResult[ 2 ], 1362 execResult[ 3 ], 1363 execResult[ 4 ] 1364 ]; 1365 } 1366 }, { 1367 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 1368 parse: function( execResult ) { 1369 return [ 1370 execResult[ 1 ] * 2.55, 1371 execResult[ 2 ] * 2.55, 1372 execResult[ 3 ] * 2.55, 1373 execResult[ 4 ] 1374 ]; 1375 } 1376 }, { 1377 1378 // this regex ignores A-F because it's compared against an already lowercased string 1379 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/, 1380 parse: function( execResult ) { 1381 return [ 1382 parseInt( execResult[ 1 ], 16 ), 1383 parseInt( execResult[ 2 ], 16 ), 1384 parseInt( execResult[ 3 ], 16 ), 1385 execResult[ 4 ] ? 1386 ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) : 1387 1 1388 ]; 1389 } 1390 }, { 1391 1392 // this regex ignores A-F because it's compared against an already lowercased string 1393 re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/, 1394 parse: function( execResult ) { 1395 return [ 1396 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 1397 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 1398 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ), 1399 execResult[ 4 ] ? 1400 ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 ) 1401 .toFixed( 2 ) : 1402 1 1403 ]; 1404 } 1405 }, { 1406 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 1407 space: "hsla", 1408 parse: function( execResult ) { 1409 return [ 1410 execResult[ 1 ], 1411 execResult[ 2 ] / 100, 1412 execResult[ 3 ] / 100, 1413 execResult[ 4 ] 1414 ]; 1415 } 1416 } ], 1417 1418 // jQuery.Color( ) 1419 color = jQuery.Color = function( color, green, blue, alpha ) { 1420 return new jQuery.Color.fn.parse( color, green, blue, alpha ); 1421 }, 1422 spaces = { 1423 rgba: { 1424 props: { 1425 red: { 1426 idx: 0, 1427 type: "byte" 1428 }, 1429 green: { 1430 idx: 1, 1431 type: "byte" 1432 }, 1433 blue: { 1434 idx: 2, 1435 type: "byte" 1436 } 1437 } 1438 }, 1439 1440 hsla: { 1441 props: { 1442 hue: { 1443 idx: 0, 1444 type: "degrees" 1445 }, 1446 saturation: { 1447 idx: 1, 1448 type: "percent" 1449 }, 1450 lightness: { 1451 idx: 2, 1452 type: "percent" 1453 } 1454 } 1455 } 1456 }, 1457 propTypes = { 1458 "byte": { 1459 floor: true, 1460 max: 255 1461 }, 1462 "percent": { 1463 max: 1 1464 }, 1465 "degrees": { 1466 mod: 360, 1467 floor: true 1468 } 1469 }, 1470 1471 // colors = jQuery.Color.names 1472 colors, 1473 1474 // local aliases of functions called often 1475 each = jQuery.each; 1476 1477// define cache name and alpha properties 1478// for rgba and hsla spaces 1479 each( spaces, function( spaceName, space ) { 1480 space.cache = "_" + spaceName; 1481 space.props.alpha = { 1482 idx: 3, 1483 type: "percent", 1484 def: 1 1485 }; 1486 } ); 1487 1488// Populate the class2type map 1489 jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 1490 function( _i, name ) { 1491 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 1492 } ); 1493 1494 function getType( obj ) { 1495 if ( obj == null ) { 1496 return obj + ""; 1497 } 1498 1499 return typeof obj === "object" ? 1500 class2type[ toString.call( obj ) ] || "object" : 1501 typeof obj; 1502 } 1503 1504 function clamp( value, prop, allowEmpty ) { 1505 var type = propTypes[ prop.type ] || {}; 1506 1507 if ( value == null ) { 1508 return ( allowEmpty || !prop.def ) ? null : prop.def; 1509 } 1510 1511 // ~~ is an short way of doing floor for positive numbers 1512 value = type.floor ? ~~value : parseFloat( value ); 1513 1514 if ( type.mod ) { 1515 1516 // we add mod before modding to make sure that negatives values 1517 // get converted properly: -10 -> 350 1518 return ( value + type.mod ) % type.mod; 1519 } 1520 1521 // for now all property types without mod have min and max 1522 return Math.min( type.max, Math.max( 0, value ) ); 1523 } 1524 1525 function stringParse( string ) { 1526 var inst = color(), 1527 rgba = inst._rgba = []; 1528 1529 string = string.toLowerCase(); 1530 1531 each( stringParsers, function( _i, parser ) { 1532 var parsed, 1533 match = parser.re.exec( string ), 1534 values = match && parser.parse( match ), 1535 spaceName = parser.space || "rgba"; 1536 1537 if ( values ) { 1538 parsed = inst[ spaceName ]( values ); 1539 1540 // if this was an rgba parse the assignment might happen twice 1541 // oh well.... 1542 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; 1543 rgba = inst._rgba = parsed._rgba; 1544 1545 // exit each( stringParsers ) here because we matched 1546 return false; 1547 } 1548 } ); 1549 1550 // Found a stringParser that handled it 1551 if ( rgba.length ) { 1552 1553 // if this came from a parsed string, force "transparent" when alpha is 0 1554 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) 1555 if ( rgba.join() === "0,0,0,0" ) { 1556 jQuery.extend( rgba, colors.transparent ); 1557 } 1558 return inst; 1559 } 1560 1561 // named colors 1562 return colors[ string ]; 1563 } 1564 1565 color.fn = jQuery.extend( color.prototype, { 1566 parse: function( red, green, blue, alpha ) { 1567 if ( red === undefined ) { 1568 this._rgba = [ null, null, null, null ]; 1569 return this; 1570 } 1571 if ( red.jquery || red.nodeType ) { 1572 red = jQuery( red ).css( green ); 1573 green = undefined; 1574 } 1575 1576 var inst = this, 1577 type = getType( red ), 1578 rgba = this._rgba = []; 1579 1580 // more than 1 argument specified - assume ( red, green, blue, alpha ) 1581 if ( green !== undefined ) { 1582 red = [ red, green, blue, alpha ]; 1583 type = "array"; 1584 } 1585 1586 if ( type === "string" ) { 1587 return this.parse( stringParse( red ) || colors._default ); 1588 } 1589 1590 if ( type === "array" ) { 1591 each( spaces.rgba.props, function( _key, prop ) { 1592 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); 1593 } ); 1594 return this; 1595 } 1596 1597 if ( type === "object" ) { 1598 if ( red instanceof color ) { 1599 each( spaces, function( _spaceName, space ) { 1600 if ( red[ space.cache ] ) { 1601 inst[ space.cache ] = red[ space.cache ].slice(); 1602 } 1603 } ); 1604 } else { 1605 each( spaces, function( _spaceName, space ) { 1606 var cache = space.cache; 1607 each( space.props, function( key, prop ) { 1608 1609 // if the cache doesn't exist, and we know how to convert 1610 if ( !inst[ cache ] && space.to ) { 1611 1612 // if the value was null, we don't need to copy it 1613 // if the key was alpha, we don't need to copy it either 1614 if ( key === "alpha" || red[ key ] == null ) { 1615 return; 1616 } 1617 inst[ cache ] = space.to( inst._rgba ); 1618 } 1619 1620 // this is the only case where we allow nulls for ALL properties. 1621 // call clamp with alwaysAllowEmpty 1622 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); 1623 } ); 1624 1625 // everything defined but alpha? 1626 if ( inst[ cache ] && jQuery.inArray( 1627 null, 1628 inst[ cache ].slice( 0, 3 ) 1629 ) < 0 ) { 1630 1631 // use the default of 1 1632 if ( inst[ cache ][ 3 ] == null ) { 1633 inst[ cache ][ 3 ] = 1; 1634 } 1635 1636 if ( space.from ) { 1637 inst._rgba = space.from( inst[ cache ] ); 1638 } 1639 } 1640 } ); 1641 } 1642 return this; 1643 } 1644 }, 1645 is: function( compare ) { 1646 var is = color( compare ), 1647 same = true, 1648 inst = this; 1649 1650 each( spaces, function( _, space ) { 1651 var localCache, 1652 isCache = is[ space.cache ]; 1653 if ( isCache ) { 1654 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; 1655 each( space.props, function( _, prop ) { 1656 if ( isCache[ prop.idx ] != null ) { 1657 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); 1658 return same; 1659 } 1660 } ); 1661 } 1662 return same; 1663 } ); 1664 return same; 1665 }, 1666 _space: function() { 1667 var used = [], 1668 inst = this; 1669 each( spaces, function( spaceName, space ) { 1670 if ( inst[ space.cache ] ) { 1671 used.push( spaceName ); 1672 } 1673 } ); 1674 return used.pop(); 1675 }, 1676 transition: function( other, distance ) { 1677 var end = color( other ), 1678 spaceName = end._space(), 1679 space = spaces[ spaceName ], 1680 startColor = this.alpha() === 0 ? color( "transparent" ) : this, 1681 start = startColor[ space.cache ] || space.to( startColor._rgba ), 1682 result = start.slice(); 1683 1684 end = end[ space.cache ]; 1685 each( space.props, function( _key, prop ) { 1686 var index = prop.idx, 1687 startValue = start[ index ], 1688 endValue = end[ index ], 1689 type = propTypes[ prop.type ] || {}; 1690 1691 // if null, don't override start value 1692 if ( endValue === null ) { 1693 return; 1694 } 1695 1696 // if null - use end 1697 if ( startValue === null ) { 1698 result[ index ] = endValue; 1699 } else { 1700 if ( type.mod ) { 1701 if ( endValue - startValue > type.mod / 2 ) { 1702 startValue += type.mod; 1703 } else if ( startValue - endValue > type.mod / 2 ) { 1704 startValue -= type.mod; 1705 } 1706 } 1707 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); 1708 } 1709 } ); 1710 return this[ spaceName ]( result ); 1711 }, 1712 blend: function( opaque ) { 1713 1714 // if we are already opaque - return ourself 1715 if ( this._rgba[ 3 ] === 1 ) { 1716 return this; 1717 } 1718 1719 var rgb = this._rgba.slice(), 1720 a = rgb.pop(), 1721 blend = color( opaque )._rgba; 1722 1723 return color( jQuery.map( rgb, function( v, i ) { 1724 return ( 1 - a ) * blend[ i ] + a * v; 1725 } ) ); 1726 }, 1727 toRgbaString: function() { 1728 var prefix = "rgba(", 1729 rgba = jQuery.map( this._rgba, function( v, i ) { 1730 if ( v != null ) { 1731 return v; 1732 } 1733 return i > 2 ? 1 : 0; 1734 } ); 1735 1736 if ( rgba[ 3 ] === 1 ) { 1737 rgba.pop(); 1738 prefix = "rgb("; 1739 } 1740 1741 return prefix + rgba.join( ", " ) + ")"; 1742 }, 1743 toHslaString: function() { 1744 var prefix = "hsla(", 1745 hsla = jQuery.map( this.hsla(), function( v, i ) { 1746 if ( v == null ) { 1747 v = i > 2 ? 1 : 0; 1748 } 1749 1750 // catch 1 and 2 1751 if ( i && i < 3 ) { 1752 v = Math.round( v * 100 ) + "%"; 1753 } 1754 return v; 1755 } ); 1756 1757 if ( hsla[ 3 ] === 1 ) { 1758 hsla.pop(); 1759 prefix = "hsl("; 1760 } 1761 return prefix + hsla.join( ", " ) + ")"; 1762 }, 1763 toHexString: function( includeAlpha ) { 1764 var rgba = this._rgba.slice(), 1765 alpha = rgba.pop(); 1766 1767 if ( includeAlpha ) { 1768 rgba.push( ~~( alpha * 255 ) ); 1769 } 1770 1771 return "#" + jQuery.map( rgba, function( v ) { 1772 1773 // default to 0 when nulls exist 1774 return ( "0" + ( v || 0 ).toString( 16 ) ).substr( -2 ); 1775 } ).join( "" ); 1776 }, 1777 toString: function() { 1778 return this.toRgbaString(); 1779 } 1780 } ); 1781 color.fn.parse.prototype = color.fn; 1782 1783// hsla conversions adapted from: 1784// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 1785 1786 function hue2rgb( p, q, h ) { 1787 h = ( h + 1 ) % 1; 1788 if ( h * 6 < 1 ) { 1789 return p + ( q - p ) * h * 6; 1790 } 1791 if ( h * 2 < 1 ) { 1792 return q; 1793 } 1794 if ( h * 3 < 2 ) { 1795 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; 1796 } 1797 return p; 1798 } 1799 1800 spaces.hsla.to = function( rgba ) { 1801 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { 1802 return [ null, null, null, rgba[ 3 ] ]; 1803 } 1804 var r = rgba[ 0 ] / 255, 1805 g = rgba[ 1 ] / 255, 1806 b = rgba[ 2 ] / 255, 1807 a = rgba[ 3 ], 1808 max = Math.max( r, g, b ), 1809 min = Math.min( r, g, b ), 1810 diff = max - min, 1811 add = max + min, 1812 l = add * 0.5, 1813 h, s; 1814 1815 if ( min === max ) { 1816 h = 0; 1817 } else if ( r === max ) { 1818 h = ( 60 * ( g - b ) / diff ) + 360; 1819 } else if ( g === max ) { 1820 h = ( 60 * ( b - r ) / diff ) + 120; 1821 } else { 1822 h = ( 60 * ( r - g ) / diff ) + 240; 1823 } 1824 1825 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% 1826 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) 1827 if ( diff === 0 ) { 1828 s = 0; 1829 } else if ( l <= 0.5 ) { 1830 s = diff / add; 1831 } else { 1832 s = diff / ( 2 - add ); 1833 } 1834 return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; 1835 }; 1836 1837 spaces.hsla.from = function( hsla ) { 1838 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { 1839 return [ null, null, null, hsla[ 3 ] ]; 1840 } 1841 var h = hsla[ 0 ] / 360, 1842 s = hsla[ 1 ], 1843 l = hsla[ 2 ], 1844 a = hsla[ 3 ], 1845 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, 1846 p = 2 * l - q; 1847 1848 return [ 1849 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), 1850 Math.round( hue2rgb( p, q, h ) * 255 ), 1851 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), 1852 a 1853 ]; 1854 }; 1855 1856 1857 each( spaces, function( spaceName, space ) { 1858 var props = space.props, 1859 cache = space.cache, 1860 to = space.to, 1861 from = space.from; 1862 1863 // makes rgba() and hsla() 1864 color.fn[ spaceName ] = function( value ) { 1865 1866 // generate a cache for this space if it doesn't exist 1867 if ( to && !this[ cache ] ) { 1868 this[ cache ] = to( this._rgba ); 1869 } 1870 if ( value === undefined ) { 1871 return this[ cache ].slice(); 1872 } 1873 1874 var ret, 1875 type = getType( value ), 1876 arr = ( type === "array" || type === "object" ) ? value : arguments, 1877 local = this[ cache ].slice(); 1878 1879 each( props, function( key, prop ) { 1880 var val = arr[ type === "object" ? key : prop.idx ]; 1881 if ( val == null ) { 1882 val = local[ prop.idx ]; 1883 } 1884 local[ prop.idx ] = clamp( val, prop ); 1885 } ); 1886 1887 if ( from ) { 1888 ret = color( from( local ) ); 1889 ret[ cache ] = local; 1890 return ret; 1891 } else { 1892 return color( local ); 1893 } 1894 }; 1895 1896 // makes red() green() blue() alpha() hue() saturation() lightness() 1897 each( props, function( key, prop ) { 1898 1899 // alpha is included in more than one space 1900 if ( color.fn[ key ] ) { 1901 return; 1902 } 1903 color.fn[ key ] = function( value ) { 1904 var local, cur, match, fn, 1905 vtype = getType( value ); 1906 1907 if ( key === "alpha" ) { 1908 fn = this._hsla ? "hsla" : "rgba"; 1909 } else { 1910 fn = spaceName; 1911 } 1912 local = this[ fn ](); 1913 cur = local[ prop.idx ]; 1914 1915 if ( vtype === "undefined" ) { 1916 return cur; 1917 } 1918 1919 if ( vtype === "function" ) { 1920 value = value.call( this, cur ); 1921 vtype = getType( value ); 1922 } 1923 if ( value == null && prop.empty ) { 1924 return this; 1925 } 1926 if ( vtype === "string" ) { 1927 match = rplusequals.exec( value ); 1928 if ( match ) { 1929 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); 1930 } 1931 } 1932 local[ prop.idx ] = value; 1933 return this[ fn ]( local ); 1934 }; 1935 } ); 1936 } ); 1937 1938// add cssHook and .fx.step function for each named hook. 1939// accept a space separated string of properties 1940 color.hook = function( hook ) { 1941 var hooks = hook.split( " " ); 1942 each( hooks, function( _i, hook ) { 1943 jQuery.cssHooks[ hook ] = { 1944 set: function( elem, value ) { 1945 var parsed; 1946 1947 if ( value !== "transparent" && 1948 ( getType( value ) !== "string" || 1949 ( parsed = stringParse( value ) ) ) ) { 1950 value = color( parsed || value ); 1951 value = value.toRgbaString(); 1952 } 1953 elem.style[ hook ] = value; 1954 } 1955 }; 1956 jQuery.fx.step[ hook ] = function( fx ) { 1957 if ( !fx.colorInit ) { 1958 fx.start = color( fx.elem, hook ); 1959 fx.end = color( fx.end ); 1960 fx.colorInit = true; 1961 } 1962 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); 1963 }; 1964 } ); 1965 1966 }; 1967 1968 color.hook( stepHooks ); 1969 1970 jQuery.cssHooks.borderColor = { 1971 expand: function( value ) { 1972 var expanded = {}; 1973 1974 each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) { 1975 expanded[ "border" + part + "Color" ] = value; 1976 } ); 1977 return expanded; 1978 } 1979 }; 1980 1981// Basic color names only. 1982// Usage of any of the other color names requires adding yourself or including 1983// jquery.color.svg-names.js. 1984 colors = jQuery.Color.names = { 1985 1986 // 4.1. Basic color keywords 1987 aqua: "#00ffff", 1988 black: "#000000", 1989 blue: "#0000ff", 1990 fuchsia: "#ff00ff", 1991 gray: "#808080", 1992 green: "#008000", 1993 lime: "#00ff00", 1994 maroon: "#800000", 1995 navy: "#000080", 1996 olive: "#808000", 1997 purple: "#800080", 1998 red: "#ff0000", 1999 silver: "#c0c0c0", 2000 teal: "#008080", 2001 white: "#ffffff", 2002 yellow: "#ffff00", 2003 2004 // 4.2.3. "transparent" color keyword 2005 transparent: [ null, null, null, 0 ], 2006 2007 _default: "#ffffff" 2008 }; 2009 2010 2011 /*! 2012 * jQuery UI Effects 1.14.1 2013 * https://jqueryui.com 2014 * 2015 * Copyright OpenJS Foundation and other contributors 2016 * Released under the MIT license. 2017 * https://jquery.org/license 2018 */ 2019 2020//>>label: Effects Core 2021//>>group: Effects 2022 /* eslint-disable max-len */ 2023//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects. 2024 /* eslint-enable max-len */ 2025//>>docs: https://api.jqueryui.com/category/effects-core/ 2026//>>demos: https://jqueryui.com/effect/ 2027 2028 2029 var dataSpace = "ui-effects-", 2030 dataSpaceStyle = "ui-effects-style", 2031 dataSpaceAnimated = "ui-effects-animated"; 2032 2033 $.effects = { 2034 effect: {} 2035 }; 2036 2037 /******************************************************************************/ 2038 /****************************** CLASS ANIMATIONS ******************************/ 2039 /******************************************************************************/ 2040 ( function() { 2041 2042 var classAnimationActions = [ "add", "remove", "toggle" ], 2043 shorthandStyles = { 2044 border: 1, 2045 borderBottom: 1, 2046 borderColor: 1, 2047 borderLeft: 1, 2048 borderRight: 1, 2049 borderTop: 1, 2050 borderWidth: 1, 2051 margin: 1, 2052 padding: 1 2053 }; 2054 2055 $.each( 2056 [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], 2057 function( _, prop ) { 2058 $.fx.step[ prop ] = function( fx ) { 2059 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { 2060 jQuery.style( fx.elem, prop, fx.end ); 2061 fx.setAttr = true; 2062 } 2063 }; 2064 } 2065 ); 2066 2067 function camelCase( string ) { 2068 return string.replace( /-([\da-z])/gi, function( all, letter ) { 2069 return letter.toUpperCase(); 2070 } ); 2071 } 2072 2073 function getElementStyles( elem ) { 2074 var key, len, 2075 style = elem.ownerDocument.defaultView.getComputedStyle( elem ), 2076 styles = {}; 2077 2078 len = style.length; 2079 while ( len-- ) { 2080 key = style[ len ]; 2081 if ( typeof style[ key ] === "string" ) { 2082 styles[ camelCase( key ) ] = style[ key ]; 2083 } 2084 } 2085 2086 return styles; 2087 } 2088 2089 function styleDifference( oldStyle, newStyle ) { 2090 var diff = {}, 2091 name, value; 2092 2093 for ( name in newStyle ) { 2094 value = newStyle[ name ]; 2095 if ( oldStyle[ name ] !== value ) { 2096 if ( !shorthandStyles[ name ] ) { 2097 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { 2098 diff[ name ] = value; 2099 } 2100 } 2101 } 2102 } 2103 2104 return diff; 2105 } 2106 2107 $.effects.animateClass = function( value, duration, easing, callback ) { 2108 var o = $.speed( duration, easing, callback ); 2109 2110 return this.queue( function() { 2111 var animated = $( this ), 2112 baseClass = animated.attr( "class" ) || "", 2113 applyClassChange, 2114 allAnimations = o.children ? animated.find( "*" ).addBack() : animated; 2115 2116 // Map the animated objects to store the original styles. 2117 allAnimations = allAnimations.map( function() { 2118 var el = $( this ); 2119 return { 2120 el: el, 2121 start: getElementStyles( this ) 2122 }; 2123 } ); 2124 2125 // Apply class change 2126 applyClassChange = function() { 2127 $.each( classAnimationActions, function( i, action ) { 2128 if ( value[ action ] ) { 2129 animated[ action + "Class" ]( value[ action ] ); 2130 } 2131 } ); 2132 }; 2133 applyClassChange(); 2134 2135 // Map all animated objects again - calculate new styles and diff 2136 allAnimations = allAnimations.map( function() { 2137 this.end = getElementStyles( this.el[ 0 ] ); 2138 this.diff = styleDifference( this.start, this.end ); 2139 return this; 2140 } ); 2141 2142 // Apply original class 2143 animated.attr( "class", baseClass ); 2144 2145 // Map all animated objects again - this time collecting a promise 2146 allAnimations = allAnimations.map( function() { 2147 var styleInfo = this, 2148 dfd = $.Deferred(), 2149 opts = $.extend( {}, o, { 2150 queue: false, 2151 complete: function() { 2152 dfd.resolve( styleInfo ); 2153 } 2154 } ); 2155 2156 this.el.animate( this.diff, opts ); 2157 return dfd.promise(); 2158 } ); 2159 2160 // Once all animations have completed: 2161 $.when.apply( $, allAnimations.get() ).done( function() { 2162 2163 // Set the final class 2164 applyClassChange(); 2165 2166 // For each animated element, 2167 // clear all css properties that were animated 2168 $.each( arguments, function() { 2169 var el = this.el; 2170 $.each( this.diff, function( key ) { 2171 el.css( key, "" ); 2172 } ); 2173 } ); 2174 2175 // This is guarnteed to be there if you use jQuery.speed() 2176 // it also handles dequeuing the next anim... 2177 o.complete.call( animated[ 0 ] ); 2178 } ); 2179 } ); 2180 }; 2181 2182 $.fn.extend( { 2183 addClass: ( function( orig ) { 2184 return function( classNames, speed, easing, callback ) { 2185 return speed ? 2186 $.effects.animateClass.call( this, 2187 { add: classNames }, speed, easing, callback ) : 2188 orig.apply( this, arguments ); 2189 }; 2190 } )( $.fn.addClass ), 2191 2192 removeClass: ( function( orig ) { 2193 return function( classNames, speed, easing, callback ) { 2194 return arguments.length > 1 ? 2195 $.effects.animateClass.call( this, 2196 { remove: classNames }, speed, easing, callback ) : 2197 orig.apply( this, arguments ); 2198 }; 2199 } )( $.fn.removeClass ), 2200 2201 toggleClass: ( function( orig ) { 2202 return function( classNames, force, speed, easing, callback ) { 2203 if ( typeof force === "boolean" || force === undefined ) { 2204 if ( !speed ) { 2205 2206 // Without speed parameter 2207 return orig.apply( this, arguments ); 2208 } else { 2209 return $.effects.animateClass.call( this, 2210 ( force ? { add: classNames } : { remove: classNames } ), 2211 speed, easing, callback ); 2212 } 2213 } else { 2214 2215 // Without force parameter 2216 return $.effects.animateClass.call( this, 2217 { toggle: classNames }, force, speed, easing ); 2218 } 2219 }; 2220 } )( $.fn.toggleClass ), 2221 2222 switchClass: function( remove, add, speed, easing, callback ) { 2223 return $.effects.animateClass.call( this, { 2224 add: add, 2225 remove: remove 2226 }, speed, easing, callback ); 2227 } 2228 } ); 2229 2230 } )(); 2231 2232 /******************************************************************************/ 2233 /*********************************** EFFECTS **********************************/ 2234 /******************************************************************************/ 2235 2236 ( function() { 2237 2238 if ( $.expr && $.expr.pseudos && $.expr.pseudos.animated ) { 2239 $.expr.pseudos.animated = ( function( orig ) { 2240 return function( elem ) { 2241 return !!$( elem ).data( dataSpaceAnimated ) || orig( elem ); 2242 }; 2243 } )( $.expr.pseudos.animated ); 2244 } 2245 2246 if ( $.uiBackCompat === true ) { 2247 $.extend( $.effects, { 2248 2249 // Saves a set of properties in a data storage 2250 save: function( element, set ) { 2251 var i = 0, length = set.length; 2252 for ( ; i < length; i++ ) { 2253 if ( set[ i ] !== null ) { 2254 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); 2255 } 2256 } 2257 }, 2258 2259 // Restores a set of previously saved properties from a data storage 2260 restore: function( element, set ) { 2261 var val, i = 0, length = set.length; 2262 for ( ; i < length; i++ ) { 2263 if ( set[ i ] !== null ) { 2264 val = element.data( dataSpace + set[ i ] ); 2265 element.css( set[ i ], val ); 2266 } 2267 } 2268 }, 2269 2270 setMode: function( el, mode ) { 2271 if ( mode === "toggle" ) { 2272 mode = el.is( ":hidden" ) ? "show" : "hide"; 2273 } 2274 return mode; 2275 }, 2276 2277 // Wraps the element around a wrapper that copies position properties 2278 createWrapper: function( element ) { 2279 2280 // If the element is already wrapped, return it 2281 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 2282 return element.parent(); 2283 } 2284 2285 // Wrap the element 2286 var props = { 2287 width: element.outerWidth( true ), 2288 height: element.outerHeight( true ), 2289 "float": element.css( "float" ) 2290 }, 2291 wrapper = $( "<div></div>" ) 2292 .addClass( "ui-effects-wrapper" ) 2293 .css( { 2294 fontSize: "100%", 2295 background: "transparent", 2296 border: "none", 2297 margin: 0, 2298 padding: 0 2299 } ), 2300 2301 // Store the size in case width/height are defined in % - Fixes #5245 2302 size = { 2303 width: element.width(), 2304 height: element.height() 2305 }, 2306 active = document.activeElement; 2307 2308 // Support: Firefox 2309 // Firefox incorrectly exposes anonymous content 2310 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 2311 try { 2312 // eslint-disable-next-line no-unused-expressions 2313 active.id; 2314 } catch ( e ) { 2315 active = document.body; 2316 } 2317 2318 element.wrap( wrapper ); 2319 2320 // Fixes #7595 - Elements lose focus when wrapped. 2321 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 2322 $( active ).trigger( "focus" ); 2323 } 2324 2325 // Hotfix for jQuery 1.4 since some change in wrap() seems to actually 2326 // lose the reference to the wrapped element 2327 wrapper = element.parent(); 2328 2329 // Transfer positioning properties to the wrapper 2330 if ( element.css( "position" ) === "static" ) { 2331 wrapper.css( { position: "relative" } ); 2332 element.css( { position: "relative" } ); 2333 } else { 2334 $.extend( props, { 2335 position: element.css( "position" ), 2336 zIndex: element.css( "z-index" ) 2337 } ); 2338 $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) { 2339 props[ pos ] = element.css( pos ); 2340 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { 2341 props[ pos ] = "auto"; 2342 } 2343 } ); 2344 element.css( { 2345 position: "relative", 2346 top: 0, 2347 left: 0, 2348 right: "auto", 2349 bottom: "auto" 2350 } ); 2351 } 2352 element.css( size ); 2353 2354 return wrapper.css( props ).show(); 2355 }, 2356 2357 removeWrapper: function( element ) { 2358 var active = document.activeElement; 2359 2360 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 2361 element.parent().replaceWith( element ); 2362 2363 // Fixes #7595 - Elements lose focus when wrapped. 2364 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 2365 $( active ).trigger( "focus" ); 2366 } 2367 } 2368 2369 return element; 2370 } 2371 } ); 2372 } 2373 2374 $.extend( $.effects, { 2375 version: "1.14.1", 2376 2377 define: function( name, mode, effect ) { 2378 if ( !effect ) { 2379 effect = mode; 2380 mode = "effect"; 2381 } 2382 2383 $.effects.effect[ name ] = effect; 2384 $.effects.effect[ name ].mode = mode; 2385 2386 return effect; 2387 }, 2388 2389 scaledDimensions: function( element, percent, direction ) { 2390 if ( percent === 0 ) { 2391 return { 2392 height: 0, 2393 width: 0, 2394 outerHeight: 0, 2395 outerWidth: 0 2396 }; 2397 } 2398 2399 var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1, 2400 y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1; 2401 2402 return { 2403 height: element.height() * y, 2404 width: element.width() * x, 2405 outerHeight: element.outerHeight() * y, 2406 outerWidth: element.outerWidth() * x 2407 }; 2408 2409 }, 2410 2411 clipToBox: function( animation ) { 2412 return { 2413 width: animation.clip.right - animation.clip.left, 2414 height: animation.clip.bottom - animation.clip.top, 2415 left: animation.clip.left, 2416 top: animation.clip.top 2417 }; 2418 }, 2419 2420 // Injects recently queued functions to be first in line (after "inprogress") 2421 unshift: function( element, queueLength, count ) { 2422 var queue = element.queue(); 2423 2424 if ( queueLength > 1 ) { 2425 queue.splice.apply( queue, 2426 [ 1, 0 ].concat( queue.splice( queueLength, count ) ) ); 2427 } 2428 element.dequeue(); 2429 }, 2430 2431 saveStyle: function( element ) { 2432 element.data( dataSpaceStyle, element[ 0 ].style.cssText ); 2433 }, 2434 2435 restoreStyle: function( element ) { 2436 element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || ""; 2437 element.removeData( dataSpaceStyle ); 2438 }, 2439 2440 mode: function( element, mode ) { 2441 var hidden = element.is( ":hidden" ); 2442 2443 if ( mode === "toggle" ) { 2444 mode = hidden ? "show" : "hide"; 2445 } 2446 if ( hidden ? mode === "hide" : mode === "show" ) { 2447 mode = "none"; 2448 } 2449 return mode; 2450 }, 2451 2452 // Translates a [top,left] array into a baseline value 2453 getBaseline: function( origin, original ) { 2454 var y, x; 2455 2456 switch ( origin[ 0 ] ) { 2457 case "top": 2458 y = 0; 2459 break; 2460 case "middle": 2461 y = 0.5; 2462 break; 2463 case "bottom": 2464 y = 1; 2465 break; 2466 default: 2467 y = origin[ 0 ] / original.height; 2468 } 2469 2470 switch ( origin[ 1 ] ) { 2471 case "left": 2472 x = 0; 2473 break; 2474 case "center": 2475 x = 0.5; 2476 break; 2477 case "right": 2478 x = 1; 2479 break; 2480 default: 2481 x = origin[ 1 ] / original.width; 2482 } 2483 2484 return { 2485 x: x, 2486 y: y 2487 }; 2488 }, 2489 2490 // Creates a placeholder element so that the original element can be made absolute 2491 createPlaceholder: function( element ) { 2492 var placeholder, 2493 cssPosition = element.css( "position" ), 2494 position = element.position(); 2495 2496 // Lock in margins first to account for form elements, which 2497 // will change margin if you explicitly set height 2498 // see: https://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380 2499 // Support: Safari 2500 element.css( { 2501 marginTop: element.css( "marginTop" ), 2502 marginBottom: element.css( "marginBottom" ), 2503 marginLeft: element.css( "marginLeft" ), 2504 marginRight: element.css( "marginRight" ) 2505 } ) 2506 .outerWidth( element.outerWidth() ) 2507 .outerHeight( element.outerHeight() ); 2508 2509 if ( /^(static|relative)/.test( cssPosition ) ) { 2510 cssPosition = "absolute"; 2511 2512 placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( { 2513 2514 // Convert inline to inline block to account for inline elements 2515 // that turn to inline block based on content (like img) 2516 display: /^(inline|ruby)/.test( element.css( "display" ) ) ? 2517 "inline-block" : 2518 "block", 2519 visibility: "hidden", 2520 2521 // Margins need to be set to account for margin collapse 2522 marginTop: element.css( "marginTop" ), 2523 marginBottom: element.css( "marginBottom" ), 2524 marginLeft: element.css( "marginLeft" ), 2525 marginRight: element.css( "marginRight" ), 2526 "float": element.css( "float" ) 2527 } ) 2528 .outerWidth( element.outerWidth() ) 2529 .outerHeight( element.outerHeight() ) 2530 .addClass( "ui-effects-placeholder" ); 2531 2532 element.data( dataSpace + "placeholder", placeholder ); 2533 } 2534 2535 element.css( { 2536 position: cssPosition, 2537 left: position.left, 2538 top: position.top 2539 } ); 2540 2541 return placeholder; 2542 }, 2543 2544 removePlaceholder: function( element ) { 2545 var dataKey = dataSpace + "placeholder", 2546 placeholder = element.data( dataKey ); 2547 2548 if ( placeholder ) { 2549 placeholder.remove(); 2550 element.removeData( dataKey ); 2551 } 2552 }, 2553 2554 // Removes a placeholder if it exists and restores 2555 // properties that were modified during placeholder creation 2556 cleanUp: function( element ) { 2557 $.effects.restoreStyle( element ); 2558 $.effects.removePlaceholder( element ); 2559 }, 2560 2561 setTransition: function( element, list, factor, value ) { 2562 value = value || {}; 2563 $.each( list, function( i, x ) { 2564 var unit = element.cssUnit( x ); 2565 if ( unit[ 0 ] > 0 ) { 2566 value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; 2567 } 2568 } ); 2569 return value; 2570 } 2571 } ); 2572 2573// Return an effect options object for the given parameters: 2574 function _normalizeArguments( effect, options, speed, callback ) { 2575 2576 // Allow passing all options as the first parameter 2577 if ( $.isPlainObject( effect ) ) { 2578 options = effect; 2579 effect = effect.effect; 2580 } 2581 2582 // Convert to an object 2583 effect = { effect: effect }; 2584 2585 // Catch (effect, null, ...) 2586 if ( options == null ) { 2587 options = {}; 2588 } 2589 2590 // Catch (effect, callback) 2591 if ( typeof options === "function" ) { 2592 callback = options; 2593 speed = null; 2594 options = {}; 2595 } 2596 2597 // Catch (effect, speed, ?) 2598 if ( typeof options === "number" || $.fx.speeds[ options ] ) { 2599 callback = speed; 2600 speed = options; 2601 options = {}; 2602 } 2603 2604 // Catch (effect, options, callback) 2605 if ( typeof speed === "function" ) { 2606 callback = speed; 2607 speed = null; 2608 } 2609 2610 // Add options to effect 2611 if ( options ) { 2612 $.extend( effect, options ); 2613 } 2614 2615 speed = speed || options.duration; 2616 effect.duration = $.fx.off ? 0 : 2617 typeof speed === "number" ? speed : 2618 speed in $.fx.speeds ? $.fx.speeds[ speed ] : 2619 $.fx.speeds._default; 2620 2621 effect.complete = callback || options.complete; 2622 2623 return effect; 2624 } 2625 2626 function standardAnimationOption( option ) { 2627 2628 // Valid standard speeds (nothing, number, named speed) 2629 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { 2630 return true; 2631 } 2632 2633 // Invalid strings - treat as "normal" speed 2634 if ( typeof option === "string" && !$.effects.effect[ option ] ) { 2635 return true; 2636 } 2637 2638 // Complete callback 2639 if ( typeof option === "function" ) { 2640 return true; 2641 } 2642 2643 // Options hash (but not naming an effect) 2644 if ( typeof option === "object" && !option.effect ) { 2645 return true; 2646 } 2647 2648 // Didn't match any standard API 2649 return false; 2650 } 2651 2652 $.fn.extend( { 2653 effect: function( /* effect, options, speed, callback */ ) { 2654 var args = _normalizeArguments.apply( this, arguments ), 2655 effectMethod = $.effects.effect[ args.effect ], 2656 defaultMode = effectMethod.mode, 2657 queue = args.queue, 2658 queueName = queue || "fx", 2659 complete = args.complete, 2660 mode = args.mode, 2661 modes = [], 2662 prefilter = function( next ) { 2663 var el = $( this ), 2664 normalizedMode = $.effects.mode( el, mode ) || defaultMode; 2665 2666 // Sentinel for duck-punching the :animated pseudo-selector 2667 el.data( dataSpaceAnimated, true ); 2668 2669 // Save effect mode for later use, 2670 // we can't just call $.effects.mode again later, 2671 // as the .show() below destroys the initial state 2672 modes.push( normalizedMode ); 2673 2674 // See $.uiBackCompat inside of run() for removal of defaultMode in 1.14 2675 if ( defaultMode && ( normalizedMode === "show" || 2676 ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) { 2677 el.show(); 2678 } 2679 2680 if ( !defaultMode || normalizedMode !== "none" ) { 2681 $.effects.saveStyle( el ); 2682 } 2683 2684 if ( typeof next === "function" ) { 2685 next(); 2686 } 2687 }; 2688 2689 if ( $.fx.off || !effectMethod ) { 2690 2691 // Delegate to the original method (e.g., .show()) if possible 2692 if ( mode ) { 2693 return this[ mode ]( args.duration, complete ); 2694 } else { 2695 return this.each( function() { 2696 if ( complete ) { 2697 complete.call( this ); 2698 } 2699 } ); 2700 } 2701 } 2702 2703 function run( next ) { 2704 var elem = $( this ); 2705 2706 function cleanup() { 2707 elem.removeData( dataSpaceAnimated ); 2708 2709 $.effects.cleanUp( elem ); 2710 2711 if ( args.mode === "hide" ) { 2712 elem.hide(); 2713 } 2714 2715 done(); 2716 } 2717 2718 function done() { 2719 if ( typeof complete === "function" ) { 2720 complete.call( elem[ 0 ] ); 2721 } 2722 2723 if ( typeof next === "function" ) { 2724 next(); 2725 } 2726 } 2727 2728 // Override mode option on a per element basis, 2729 // as toggle can be either show or hide depending on element state 2730 args.mode = modes.shift(); 2731 2732 if ( $.uiBackCompat === true && !defaultMode ) { 2733 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { 2734 2735 // Call the core method to track "olddisplay" properly 2736 elem[ mode ](); 2737 done(); 2738 } else { 2739 effectMethod.call( elem[ 0 ], args, done ); 2740 } 2741 } else { 2742 if ( args.mode === "none" ) { 2743 2744 // Call the core method to track "olddisplay" properly 2745 elem[ mode ](); 2746 done(); 2747 } else { 2748 effectMethod.call( elem[ 0 ], args, cleanup ); 2749 } 2750 } 2751 } 2752 2753 // Run prefilter on all elements first to ensure that 2754 // any showing or hiding happens before placeholder creation, 2755 // which ensures that any layout changes are correctly captured. 2756 return queue === false ? 2757 this.each( prefilter ).each( run ) : 2758 this.queue( queueName, prefilter ).queue( queueName, run ); 2759 }, 2760 2761 show: ( function( orig ) { 2762 return function( option ) { 2763 if ( standardAnimationOption( option ) ) { 2764 return orig.apply( this, arguments ); 2765 } else { 2766 var args = _normalizeArguments.apply( this, arguments ); 2767 args.mode = "show"; 2768 return this.effect.call( this, args ); 2769 } 2770 }; 2771 } )( $.fn.show ), 2772 2773 hide: ( function( orig ) { 2774 return function( option ) { 2775 if ( standardAnimationOption( option ) ) { 2776 return orig.apply( this, arguments ); 2777 } else { 2778 var args = _normalizeArguments.apply( this, arguments ); 2779 args.mode = "hide"; 2780 return this.effect.call( this, args ); 2781 } 2782 }; 2783 } )( $.fn.hide ), 2784 2785 toggle: ( function( orig ) { 2786 return function( option ) { 2787 if ( standardAnimationOption( option ) || typeof option === "boolean" ) { 2788 return orig.apply( this, arguments ); 2789 } else { 2790 var args = _normalizeArguments.apply( this, arguments ); 2791 args.mode = "toggle"; 2792 return this.effect.call( this, args ); 2793 } 2794 }; 2795 } )( $.fn.toggle ), 2796 2797 cssUnit: function( key ) { 2798 var style = this.css( key ), 2799 val = []; 2800 2801 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { 2802 if ( style.indexOf( unit ) > 0 ) { 2803 val = [ parseFloat( style ), unit ]; 2804 } 2805 } ); 2806 return val; 2807 }, 2808 2809 cssClip: function( clipObj ) { 2810 if ( clipObj ) { 2811 return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " + 2812 clipObj.bottom + "px " + clipObj.left + "px)" ); 2813 } 2814 return parseClip( this.css( "clip" ), this ); 2815 }, 2816 2817 transfer: function( options, done ) { 2818 var element = $( this ), 2819 target = $( options.to ), 2820 targetFixed = target.css( "position" ) === "fixed", 2821 body = $( "body" ), 2822 fixTop = targetFixed ? body.scrollTop() : 0, 2823 fixLeft = targetFixed ? body.scrollLeft() : 0, 2824 endPosition = target.offset(), 2825 animation = { 2826 top: endPosition.top - fixTop, 2827 left: endPosition.left - fixLeft, 2828 height: target.innerHeight(), 2829 width: target.innerWidth() 2830 }, 2831 startPosition = element.offset(), 2832 transfer = $( "<div class='ui-effects-transfer'></div>" ); 2833 2834 transfer 2835 .appendTo( "body" ) 2836 .addClass( options.className ) 2837 .css( { 2838 top: startPosition.top - fixTop, 2839 left: startPosition.left - fixLeft, 2840 height: element.innerHeight(), 2841 width: element.innerWidth(), 2842 position: targetFixed ? "fixed" : "absolute" 2843 } ) 2844 .animate( animation, options.duration, options.easing, function() { 2845 transfer.remove(); 2846 if ( typeof done === "function" ) { 2847 done(); 2848 } 2849 } ); 2850 } 2851 } ); 2852 2853 function parseClip( str, element ) { 2854 var outerWidth = element.outerWidth(), 2855 outerHeight = element.outerHeight(), 2856 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)\)$/, 2857 values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ]; 2858 2859 return { 2860 top: parseFloat( values[ 1 ] ) || 0, 2861 right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ), 2862 bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ), 2863 left: parseFloat( values[ 4 ] ) || 0 2864 }; 2865 } 2866 2867 $.fx.step.clip = function( fx ) { 2868 if ( !fx.clipInit ) { 2869 fx.start = $( fx.elem ).cssClip(); 2870 if ( typeof fx.end === "string" ) { 2871 fx.end = parseClip( fx.end, fx.elem ); 2872 } 2873 fx.clipInit = true; 2874 } 2875 2876 $( fx.elem ).cssClip( { 2877 top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top, 2878 right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right, 2879 bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom, 2880 left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left 2881 } ); 2882 }; 2883 2884 } )(); 2885 2886 /******************************************************************************/ 2887 /*********************************** EASING ***********************************/ 2888 /******************************************************************************/ 2889 2890 ( function() { 2891 2892// Based on easing equations from Robert Penner (http://robertpenner.com/easing) 2893 2894 var baseEasings = {}; 2895 2896 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { 2897 baseEasings[ name ] = function( p ) { 2898 return Math.pow( p, i + 2 ); 2899 }; 2900 } ); 2901 2902 $.extend( baseEasings, { 2903 Sine: function( p ) { 2904 return 1 - Math.cos( p * Math.PI / 2 ); 2905 }, 2906 Circ: function( p ) { 2907 return 1 - Math.sqrt( 1 - p * p ); 2908 }, 2909 Elastic: function( p ) { 2910 return p === 0 || p === 1 ? p : 2911 -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 ); 2912 }, 2913 Back: function( p ) { 2914 return p * p * ( 3 * p - 2 ); 2915 }, 2916 Bounce: function( p ) { 2917 var pow2, 2918 bounce = 4; 2919 2920 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} 2921 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); 2922 } 2923 } ); 2924 2925 $.each( baseEasings, function( name, easeIn ) { 2926 $.easing[ "easeIn" + name ] = easeIn; 2927 $.easing[ "easeOut" + name ] = function( p ) { 2928 return 1 - easeIn( 1 - p ); 2929 }; 2930 $.easing[ "easeInOut" + name ] = function( p ) { 2931 return p < 0.5 ? 2932 easeIn( p * 2 ) / 2 : 2933 1 - easeIn( p * -2 + 2 ) / 2; 2934 }; 2935 } ); 2936 2937 } )(); 2938 2939 var effect = $.effects; 2940 2941 2942 /*! 2943 * jQuery UI Effects Blind 1.14.1 2944 * https://jqueryui.com 2945 * 2946 * Copyright OpenJS Foundation and other contributors 2947 * Released under the MIT license. 2948 * https://jquery.org/license 2949 */ 2950 2951//>>label: Blind Effect 2952//>>group: Effects 2953//>>description: Blinds the element. 2954//>>docs: https://api.jqueryui.com/blind-effect/ 2955//>>demos: https://jqueryui.com/effect/ 2956 2957 2958 var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) { 2959 var map = { 2960 up: [ "bottom", "top" ], 2961 vertical: [ "bottom", "top" ], 2962 down: [ "top", "bottom" ], 2963 left: [ "right", "left" ], 2964 horizontal: [ "right", "left" ], 2965 right: [ "left", "right" ] 2966 }, 2967 element = $( this ), 2968 direction = options.direction || "up", 2969 start = element.cssClip(), 2970 animate = { clip: $.extend( {}, start ) }, 2971 placeholder = $.effects.createPlaceholder( element ); 2972 2973 animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ]; 2974 2975 if ( options.mode === "show" ) { 2976 element.cssClip( animate.clip ); 2977 if ( placeholder ) { 2978 placeholder.css( $.effects.clipToBox( animate ) ); 2979 } 2980 2981 animate.clip = start; 2982 } 2983 2984 if ( placeholder ) { 2985 placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing ); 2986 } 2987 2988 element.animate( animate, { 2989 queue: false, 2990 duration: options.duration, 2991 easing: options.easing, 2992 complete: done 2993 } ); 2994 } ); 2995 2996 2997 /*! 2998 * jQuery UI Effects Bounce 1.14.1 2999 * https://jqueryui.com 3000 * 3001 * Copyright OpenJS Foundation and other contributors 3002 * Released under the MIT license. 3003 * https://jquery.org/license 3004 */ 3005 3006//>>label: Bounce Effect 3007//>>group: Effects 3008//>>description: Bounces an element horizontally or vertically n times. 3009//>>docs: https://api.jqueryui.com/bounce-effect/ 3010//>>demos: https://jqueryui.com/effect/ 3011 3012 3013 var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) { 3014 var upAnim, downAnim, refValue, 3015 element = $( this ), 3016 3017 // Defaults: 3018 mode = options.mode, 3019 hide = mode === "hide", 3020 show = mode === "show", 3021 direction = options.direction || "up", 3022 distance = options.distance, 3023 times = options.times || 5, 3024 3025 // Number of internal animations 3026 anims = times * 2 + ( show || hide ? 1 : 0 ), 3027 speed = options.duration / anims, 3028 easing = options.easing, 3029 3030 // Utility: 3031 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3032 motion = ( direction === "up" || direction === "left" ), 3033 i = 0, 3034 3035 queuelen = element.queue().length; 3036 3037 $.effects.createPlaceholder( element ); 3038 3039 refValue = element.css( ref ); 3040 3041 // Default distance for the BIGGEST bounce is the outer Distance / 3 3042 if ( !distance ) { 3043 distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; 3044 } 3045 3046 if ( show ) { 3047 downAnim = { opacity: 1 }; 3048 downAnim[ ref ] = refValue; 3049 3050 // If we are showing, force opacity 0 and set the initial position 3051 // then do the "first" animation 3052 element 3053 .css( "opacity", 0 ) 3054 .css( ref, motion ? -distance * 2 : distance * 2 ) 3055 .animate( downAnim, speed, easing ); 3056 } 3057 3058 // Start at the smallest distance if we are hiding 3059 if ( hide ) { 3060 distance = distance / Math.pow( 2, times - 1 ); 3061 } 3062 3063 downAnim = {}; 3064 downAnim[ ref ] = refValue; 3065 3066 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here 3067 for ( ; i < times; i++ ) { 3068 upAnim = {}; 3069 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 3070 3071 element 3072 .animate( upAnim, speed, easing ) 3073 .animate( downAnim, speed, easing ); 3074 3075 distance = hide ? distance * 2 : distance / 2; 3076 } 3077 3078 // Last Bounce when Hiding 3079 if ( hide ) { 3080 upAnim = { opacity: 0 }; 3081 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 3082 3083 element.animate( upAnim, speed, easing ); 3084 } 3085 3086 element.queue( done ); 3087 3088 $.effects.unshift( element, queuelen, anims + 1 ); 3089 } ); 3090 3091 3092 /*! 3093 * jQuery UI Effects Clip 1.14.1 3094 * https://jqueryui.com 3095 * 3096 * Copyright OpenJS Foundation and other contributors 3097 * Released under the MIT license. 3098 * https://jquery.org/license 3099 */ 3100 3101//>>label: Clip Effect 3102//>>group: Effects 3103//>>description: Clips the element on and off like an old TV. 3104//>>docs: https://api.jqueryui.com/clip-effect/ 3105//>>demos: https://jqueryui.com/effect/ 3106 3107 3108 var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) { 3109 var start, 3110 animate = {}, 3111 element = $( this ), 3112 direction = options.direction || "vertical", 3113 both = direction === "both", 3114 horizontal = both || direction === "horizontal", 3115 vertical = both || direction === "vertical"; 3116 3117 start = element.cssClip(); 3118 animate.clip = { 3119 top: vertical ? ( start.bottom - start.top ) / 2 : start.top, 3120 right: horizontal ? ( start.right - start.left ) / 2 : start.right, 3121 bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom, 3122 left: horizontal ? ( start.right - start.left ) / 2 : start.left 3123 }; 3124 3125 $.effects.createPlaceholder( element ); 3126 3127 if ( options.mode === "show" ) { 3128 element.cssClip( animate.clip ); 3129 animate.clip = start; 3130 } 3131 3132 element.animate( animate, { 3133 queue: false, 3134 duration: options.duration, 3135 easing: options.easing, 3136 complete: done 3137 } ); 3138 3139 } ); 3140 3141 3142 /*! 3143 * jQuery UI Effects Drop 1.14.1 3144 * https://jqueryui.com 3145 * 3146 * Copyright OpenJS Foundation and other contributors 3147 * Released under the MIT license. 3148 * https://jquery.org/license 3149 */ 3150 3151//>>label: Drop Effect 3152//>>group: Effects 3153//>>description: Moves an element in one direction and hides it at the same time. 3154//>>docs: https://api.jqueryui.com/drop-effect/ 3155//>>demos: https://jqueryui.com/effect/ 3156 3157 3158 var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) { 3159 3160 var distance, 3161 element = $( this ), 3162 mode = options.mode, 3163 show = mode === "show", 3164 direction = options.direction || "left", 3165 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3166 motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=", 3167 oppositeMotion = ( motion === "+=" ) ? "-=" : "+=", 3168 animation = { 3169 opacity: 0 3170 }; 3171 3172 $.effects.createPlaceholder( element ); 3173 3174 distance = options.distance || 3175 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; 3176 3177 animation[ ref ] = motion + distance; 3178 3179 if ( show ) { 3180 element.css( animation ); 3181 3182 animation[ ref ] = oppositeMotion + distance; 3183 animation.opacity = 1; 3184 } 3185 3186 // Animate 3187 element.animate( animation, { 3188 queue: false, 3189 duration: options.duration, 3190 easing: options.easing, 3191 complete: done 3192 } ); 3193 } ); 3194 3195 3196 /*! 3197 * jQuery UI Effects Explode 1.14.1 3198 * https://jqueryui.com 3199 * 3200 * Copyright OpenJS Foundation and other contributors 3201 * Released under the MIT license. 3202 * https://jquery.org/license 3203 */ 3204 3205//>>label: Explode Effect 3206//>>group: Effects 3207 /* eslint-disable max-len */ 3208//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness. 3209 /* eslint-enable max-len */ 3210//>>docs: https://api.jqueryui.com/explode-effect/ 3211//>>demos: https://jqueryui.com/effect/ 3212 3213 3214 var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) { 3215 3216 var i, j, left, top, mx, my, 3217 rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3, 3218 cells = rows, 3219 element = $( this ), 3220 mode = options.mode, 3221 show = mode === "show", 3222 3223 // Show and then visibility:hidden the element before calculating offset 3224 offset = element.show().css( "visibility", "hidden" ).offset(), 3225 3226 // Width and height of a piece 3227 width = Math.ceil( element.outerWidth() / cells ), 3228 height = Math.ceil( element.outerHeight() / rows ), 3229 pieces = []; 3230 3231 // Children animate complete: 3232 function childComplete() { 3233 pieces.push( this ); 3234 if ( pieces.length === rows * cells ) { 3235 animComplete(); 3236 } 3237 } 3238 3239 // Clone the element for each row and cell. 3240 for ( i = 0; i < rows; i++ ) { // ===> 3241 top = offset.top + i * height; 3242 my = i - ( rows - 1 ) / 2; 3243 3244 for ( j = 0; j < cells; j++ ) { // ||| 3245 left = offset.left + j * width; 3246 mx = j - ( cells - 1 ) / 2; 3247 3248 // Create a clone of the now hidden main element that will be absolute positioned 3249 // within a wrapper div off the -left and -top equal to size of our pieces 3250 element 3251 .clone() 3252 .appendTo( "body" ) 3253 .wrap( "<div></div>" ) 3254 .css( { 3255 position: "absolute", 3256 visibility: "visible", 3257 left: -j * width, 3258 top: -i * height 3259 } ) 3260 3261 // Select the wrapper - make it overflow: hidden and absolute positioned based on 3262 // where the original was located +left and +top equal to the size of pieces 3263 .parent() 3264 .addClass( "ui-effects-explode" ) 3265 .css( { 3266 position: "absolute", 3267 overflow: "hidden", 3268 width: width, 3269 height: height, 3270 left: left + ( show ? mx * width : 0 ), 3271 top: top + ( show ? my * height : 0 ), 3272 opacity: show ? 0 : 1 3273 } ) 3274 .animate( { 3275 left: left + ( show ? 0 : mx * width ), 3276 top: top + ( show ? 0 : my * height ), 3277 opacity: show ? 1 : 0 3278 }, options.duration || 500, options.easing, childComplete ); 3279 } 3280 } 3281 3282 function animComplete() { 3283 element.css( { 3284 visibility: "visible" 3285 } ); 3286 $( pieces ).remove(); 3287 done(); 3288 } 3289 } ); 3290 3291 3292 /*! 3293 * jQuery UI Effects Fade 1.14.1 3294 * https://jqueryui.com 3295 * 3296 * Copyright OpenJS Foundation and other contributors 3297 * Released under the MIT license. 3298 * https://jquery.org/license 3299 */ 3300 3301//>>label: Fade Effect 3302//>>group: Effects 3303//>>description: Fades the element. 3304//>>docs: https://api.jqueryui.com/fade-effect/ 3305//>>demos: https://jqueryui.com/effect/ 3306 3307 3308 var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) { 3309 var show = options.mode === "show"; 3310 3311 $( this ) 3312 .css( "opacity", show ? 0 : 1 ) 3313 .animate( { 3314 opacity: show ? 1 : 0 3315 }, { 3316 queue: false, 3317 duration: options.duration, 3318 easing: options.easing, 3319 complete: done 3320 } ); 3321 } ); 3322 3323 3324 /*! 3325 * jQuery UI Effects Fold 1.14.1 3326 * https://jqueryui.com 3327 * 3328 * Copyright OpenJS Foundation and other contributors 3329 * Released under the MIT license. 3330 * https://jquery.org/license 3331 */ 3332 3333//>>label: Fold Effect 3334//>>group: Effects 3335//>>description: Folds an element first horizontally and then vertically. 3336//>>docs: https://api.jqueryui.com/fold-effect/ 3337//>>demos: https://jqueryui.com/effect/ 3338 3339 3340 var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) { 3341 3342 // Create element 3343 var element = $( this ), 3344 mode = options.mode, 3345 show = mode === "show", 3346 hide = mode === "hide", 3347 size = options.size || 15, 3348 percent = /([0-9]+)%/.exec( size ), 3349 horizFirst = !!options.horizFirst, 3350 ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ], 3351 duration = options.duration / 2, 3352 3353 placeholder = $.effects.createPlaceholder( element ), 3354 3355 start = element.cssClip(), 3356 animation1 = { clip: $.extend( {}, start ) }, 3357 animation2 = { clip: $.extend( {}, start ) }, 3358 3359 distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ], 3360 3361 queuelen = element.queue().length; 3362 3363 if ( percent ) { 3364 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; 3365 } 3366 animation1.clip[ ref[ 0 ] ] = size; 3367 animation2.clip[ ref[ 0 ] ] = size; 3368 animation2.clip[ ref[ 1 ] ] = 0; 3369 3370 if ( show ) { 3371 element.cssClip( animation2.clip ); 3372 if ( placeholder ) { 3373 placeholder.css( $.effects.clipToBox( animation2 ) ); 3374 } 3375 3376 animation2.clip = start; 3377 } 3378 3379 // Animate 3380 element 3381 .queue( function( next ) { 3382 if ( placeholder ) { 3383 placeholder 3384 .animate( $.effects.clipToBox( animation1 ), duration, options.easing ) 3385 .animate( $.effects.clipToBox( animation2 ), duration, options.easing ); 3386 } 3387 3388 next(); 3389 } ) 3390 .animate( animation1, duration, options.easing ) 3391 .animate( animation2, duration, options.easing ) 3392 .queue( done ); 3393 3394 $.effects.unshift( element, queuelen, 4 ); 3395 } ); 3396 3397 3398 /*! 3399 * jQuery UI Effects Highlight 1.14.1 3400 * https://jqueryui.com 3401 * 3402 * Copyright OpenJS Foundation and other contributors 3403 * Released under the MIT license. 3404 * https://jquery.org/license 3405 */ 3406 3407//>>label: Highlight Effect 3408//>>group: Effects 3409//>>description: Highlights the background of an element in a defined color for a custom duration. 3410//>>docs: https://api.jqueryui.com/highlight-effect/ 3411//>>demos: https://jqueryui.com/effect/ 3412 3413 3414 var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) { 3415 var element = $( this ), 3416 animation = { 3417 backgroundColor: element.css( "backgroundColor" ) 3418 }; 3419 3420 if ( options.mode === "hide" ) { 3421 animation.opacity = 0; 3422 } 3423 3424 $.effects.saveStyle( element ); 3425 3426 element 3427 .css( { 3428 backgroundImage: "none", 3429 backgroundColor: options.color || "#ffff99" 3430 } ) 3431 .animate( animation, { 3432 queue: false, 3433 duration: options.duration, 3434 easing: options.easing, 3435 complete: done 3436 } ); 3437 } ); 3438 3439 3440 /*! 3441 * jQuery UI Effects Size 1.14.1 3442 * https://jqueryui.com 3443 * 3444 * Copyright OpenJS Foundation and other contributors 3445 * Released under the MIT license. 3446 * https://jquery.org/license 3447 */ 3448 3449//>>label: Size Effect 3450//>>group: Effects 3451//>>description: Resize an element to a specified width and height. 3452//>>docs: https://api.jqueryui.com/size-effect/ 3453//>>demos: https://jqueryui.com/effect/ 3454 3455 3456 var effectsEffectSize = $.effects.define( "size", function( options, done ) { 3457 3458 // Create element 3459 var baseline, factor, temp, 3460 element = $( this ), 3461 3462 // Copy for children 3463 cProps = [ "fontSize" ], 3464 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], 3465 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], 3466 3467 // Set options 3468 mode = options.mode, 3469 restore = mode !== "effect", 3470 scale = options.scale || "both", 3471 origin = options.origin || [ "middle", "center" ], 3472 position = element.css( "position" ), 3473 pos = element.position(), 3474 original = $.effects.scaledDimensions( element ), 3475 from = options.from || original, 3476 to = options.to || $.effects.scaledDimensions( element, 0 ); 3477 3478 $.effects.createPlaceholder( element ); 3479 3480 if ( mode === "show" ) { 3481 temp = from; 3482 from = to; 3483 to = temp; 3484 } 3485 3486 // Set scaling factor 3487 factor = { 3488 from: { 3489 y: from.height / original.height, 3490 x: from.width / original.width 3491 }, 3492 to: { 3493 y: to.height / original.height, 3494 x: to.width / original.width 3495 } 3496 }; 3497 3498 // Scale the css box 3499 if ( scale === "box" || scale === "both" ) { 3500 3501 // Vertical props scaling 3502 if ( factor.from.y !== factor.to.y ) { 3503 from = $.effects.setTransition( element, vProps, factor.from.y, from ); 3504 to = $.effects.setTransition( element, vProps, factor.to.y, to ); 3505 } 3506 3507 // Horizontal props scaling 3508 if ( factor.from.x !== factor.to.x ) { 3509 from = $.effects.setTransition( element, hProps, factor.from.x, from ); 3510 to = $.effects.setTransition( element, hProps, factor.to.x, to ); 3511 } 3512 } 3513 3514 // Scale the content 3515 if ( scale === "content" || scale === "both" ) { 3516 3517 // Vertical props scaling 3518 if ( factor.from.y !== factor.to.y ) { 3519 from = $.effects.setTransition( element, cProps, factor.from.y, from ); 3520 to = $.effects.setTransition( element, cProps, factor.to.y, to ); 3521 } 3522 } 3523 3524 // Adjust the position properties based on the provided origin points 3525 if ( origin ) { 3526 baseline = $.effects.getBaseline( origin, original ); 3527 from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top; 3528 from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left; 3529 to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top; 3530 to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left; 3531 } 3532 delete from.outerHeight; 3533 delete from.outerWidth; 3534 element.css( from ); 3535 3536 // Animate the children if desired 3537 if ( scale === "content" || scale === "both" ) { 3538 3539 vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps ); 3540 hProps = hProps.concat( [ "marginLeft", "marginRight" ] ); 3541 3542 // Only animate children with width attributes specified 3543 // TODO: is this right? should we include anything with css width specified as well 3544 element.find( "*[width]" ).each( function() { 3545 var child = $( this ), 3546 childOriginal = $.effects.scaledDimensions( child ), 3547 childFrom = { 3548 height: childOriginal.height * factor.from.y, 3549 width: childOriginal.width * factor.from.x, 3550 outerHeight: childOriginal.outerHeight * factor.from.y, 3551 outerWidth: childOriginal.outerWidth * factor.from.x 3552 }, 3553 childTo = { 3554 height: childOriginal.height * factor.to.y, 3555 width: childOriginal.width * factor.to.x, 3556 outerHeight: childOriginal.height * factor.to.y, 3557 outerWidth: childOriginal.width * factor.to.x 3558 }; 3559 3560 // Vertical props scaling 3561 if ( factor.from.y !== factor.to.y ) { 3562 childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom ); 3563 childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo ); 3564 } 3565 3566 // Horizontal props scaling 3567 if ( factor.from.x !== factor.to.x ) { 3568 childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom ); 3569 childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo ); 3570 } 3571 3572 if ( restore ) { 3573 $.effects.saveStyle( child ); 3574 } 3575 3576 // Animate children 3577 child.css( childFrom ); 3578 child.animate( childTo, options.duration, options.easing, function() { 3579 3580 // Restore children 3581 if ( restore ) { 3582 $.effects.restoreStyle( child ); 3583 } 3584 } ); 3585 } ); 3586 } 3587 3588 // Animate 3589 element.animate( to, { 3590 queue: false, 3591 duration: options.duration, 3592 easing: options.easing, 3593 complete: function() { 3594 3595 var offset = element.offset(); 3596 3597 if ( to.opacity === 0 ) { 3598 element.css( "opacity", from.opacity ); 3599 } 3600 3601 if ( !restore ) { 3602 element 3603 .css( "position", position === "static" ? "relative" : position ) 3604 .offset( offset ); 3605 3606 // Need to save style here so that automatic style restoration 3607 // doesn't restore to the original styles from before the animation. 3608 $.effects.saveStyle( element ); 3609 } 3610 3611 done(); 3612 } 3613 } ); 3614 3615 } ); 3616 3617 3618 /*! 3619 * jQuery UI Effects Scale 1.14.1 3620 * https://jqueryui.com 3621 * 3622 * Copyright OpenJS Foundation and other contributors 3623 * Released under the MIT license. 3624 * https://jquery.org/license 3625 */ 3626 3627//>>label: Scale Effect 3628//>>group: Effects 3629//>>description: Grows or shrinks an element and its content. 3630//>>docs: https://api.jqueryui.com/scale-effect/ 3631//>>demos: https://jqueryui.com/effect/ 3632 3633 3634 var effectsEffectScale = $.effects.define( "scale", function( options, done ) { 3635 3636 // Create element 3637 var el = $( this ), 3638 mode = options.mode, 3639 percent = parseInt( options.percent, 10 ) || 3640 ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ), 3641 3642 newOptions = $.extend( true, { 3643 from: $.effects.scaledDimensions( el ), 3644 to: $.effects.scaledDimensions( el, percent, options.direction || "both" ), 3645 origin: options.origin || [ "middle", "center" ] 3646 }, options ); 3647 3648 // Fade option to support puff 3649 if ( options.fade ) { 3650 newOptions.from.opacity = 1; 3651 newOptions.to.opacity = 0; 3652 } 3653 3654 $.effects.effect.size.call( this, newOptions, done ); 3655 } ); 3656 3657 3658 /*! 3659 * jQuery UI Effects Puff 1.14.1 3660 * https://jqueryui.com 3661 * 3662 * Copyright OpenJS Foundation and other contributors 3663 * Released under the MIT license. 3664 * https://jquery.org/license 3665 */ 3666 3667//>>label: Puff Effect 3668//>>group: Effects 3669//>>description: Creates a puff effect by scaling the element up and hiding it at the same time. 3670//>>docs: https://api.jqueryui.com/puff-effect/ 3671//>>demos: https://jqueryui.com/effect/ 3672 3673 3674 var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) { 3675 var newOptions = $.extend( true, {}, options, { 3676 fade: true, 3677 percent: parseInt( options.percent, 10 ) || 150 3678 } ); 3679 3680 $.effects.effect.scale.call( this, newOptions, done ); 3681 } ); 3682 3683 3684 /*! 3685 * jQuery UI Effects Pulsate 1.14.1 3686 * https://jqueryui.com 3687 * 3688 * Copyright OpenJS Foundation and other contributors 3689 * Released under the MIT license. 3690 * https://jquery.org/license 3691 */ 3692 3693//>>label: Pulsate Effect 3694//>>group: Effects 3695//>>description: Pulsates an element n times by changing the opacity to zero and back. 3696//>>docs: https://api.jqueryui.com/pulsate-effect/ 3697//>>demos: https://jqueryui.com/effect/ 3698 3699 3700 var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) { 3701 var element = $( this ), 3702 mode = options.mode, 3703 show = mode === "show", 3704 hide = mode === "hide", 3705 showhide = show || hide, 3706 3707 // Showing or hiding leaves off the "last" animation 3708 anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), 3709 duration = options.duration / anims, 3710 animateTo = 0, 3711 i = 1, 3712 queuelen = element.queue().length; 3713 3714 if ( show || !element.is( ":visible" ) ) { 3715 element.css( "opacity", 0 ).show(); 3716 animateTo = 1; 3717 } 3718 3719 // Anims - 1 opacity "toggles" 3720 for ( ; i < anims; i++ ) { 3721 element.animate( { opacity: animateTo }, duration, options.easing ); 3722 animateTo = 1 - animateTo; 3723 } 3724 3725 element.animate( { opacity: animateTo }, duration, options.easing ); 3726 3727 element.queue( done ); 3728 3729 $.effects.unshift( element, queuelen, anims + 1 ); 3730 } ); 3731 3732 3733 /*! 3734 * jQuery UI Effects Shake 1.14.1 3735 * https://jqueryui.com 3736 * 3737 * Copyright OpenJS Foundation and other contributors 3738 * Released under the MIT license. 3739 * https://jquery.org/license 3740 */ 3741 3742//>>label: Shake Effect 3743//>>group: Effects 3744//>>description: Shakes an element horizontally or vertically n times. 3745//>>docs: https://api.jqueryui.com/shake-effect/ 3746//>>demos: https://jqueryui.com/effect/ 3747 3748 3749 var effectsEffectShake = $.effects.define( "shake", function( options, done ) { 3750 3751 var i = 1, 3752 element = $( this ), 3753 direction = options.direction || "left", 3754 distance = options.distance || 20, 3755 times = options.times || 3, 3756 anims = times * 2 + 1, 3757 speed = Math.round( options.duration / anims ), 3758 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3759 positiveMotion = ( direction === "up" || direction === "left" ), 3760 animation = {}, 3761 animation1 = {}, 3762 animation2 = {}, 3763 3764 queuelen = element.queue().length; 3765 3766 $.effects.createPlaceholder( element ); 3767 3768 // Animation 3769 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; 3770 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; 3771 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; 3772 3773 // Animate 3774 element.animate( animation, speed, options.easing ); 3775 3776 // Shakes 3777 for ( ; i < times; i++ ) { 3778 element 3779 .animate( animation1, speed, options.easing ) 3780 .animate( animation2, speed, options.easing ); 3781 } 3782 3783 element 3784 .animate( animation1, speed, options.easing ) 3785 .animate( animation, speed / 2, options.easing ) 3786 .queue( done ); 3787 3788 $.effects.unshift( element, queuelen, anims + 1 ); 3789 } ); 3790 3791 3792 /*! 3793 * jQuery UI Effects Slide 1.14.1 3794 * https://jqueryui.com 3795 * 3796 * Copyright OpenJS Foundation and other contributors 3797 * Released under the MIT license. 3798 * https://jquery.org/license 3799 */ 3800 3801//>>label: Slide Effect 3802//>>group: Effects 3803//>>description: Slides an element in and out of the viewport. 3804//>>docs: https://api.jqueryui.com/slide-effect/ 3805//>>demos: https://jqueryui.com/effect/ 3806 3807 3808 var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) { 3809 var startClip, startRef, 3810 element = $( this ), 3811 map = { 3812 up: [ "bottom", "top" ], 3813 down: [ "top", "bottom" ], 3814 left: [ "right", "left" ], 3815 right: [ "left", "right" ] 3816 }, 3817 mode = options.mode, 3818 direction = options.direction || "left", 3819 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 3820 positiveMotion = ( direction === "up" || direction === "left" ), 3821 distance = options.distance || 3822 element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ), 3823 animation = {}; 3824 3825 $.effects.createPlaceholder( element ); 3826 3827 startClip = element.cssClip(); 3828 startRef = element.position()[ ref ]; 3829 3830 // Define hide animation 3831 animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef; 3832 animation.clip = element.cssClip(); 3833 animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ]; 3834 3835 // Reverse the animation if we're showing 3836 if ( mode === "show" ) { 3837 element.cssClip( animation.clip ); 3838 element.css( ref, animation[ ref ] ); 3839 animation.clip = startClip; 3840 animation[ ref ] = startRef; 3841 } 3842 3843 // Actually animate 3844 element.animate( animation, { 3845 queue: false, 3846 duration: options.duration, 3847 easing: options.easing, 3848 complete: done 3849 } ); 3850 } ); 3851 3852 3853 /*! 3854 * jQuery UI Effects Transfer 1.14.1 3855 * https://jqueryui.com 3856 * 3857 * Copyright OpenJS Foundation and other contributors 3858 * Released under the MIT license. 3859 * https://jquery.org/license 3860 */ 3861 3862//>>label: Transfer Effect 3863//>>group: Effects 3864//>>description: Displays a transfer effect from one element to another. 3865//>>docs: https://api.jqueryui.com/transfer-effect/ 3866//>>demos: https://jqueryui.com/effect/ 3867 3868 3869 var effect; 3870 if ( $.uiBackCompat === true ) { 3871 effect = $.effects.define( "transfer", function( options, done ) { 3872 $( this ).transfer( options, done ); 3873 } ); 3874 } 3875 var effectsEffectTransfer = effect; 3876 3877 3878 /*! 3879 * jQuery UI Focusable 1.14.1 3880 * https://jqueryui.com 3881 * 3882 * Copyright OpenJS Foundation and other contributors 3883 * Released under the MIT license. 3884 * https://jquery.org/license 3885 */ 3886 3887//>>label: :focusable Selector 3888//>>group: Core 3889//>>description: Selects elements which can be focused. 3890//>>docs: https://api.jqueryui.com/focusable-selector/ 3891 3892 3893// Selectors 3894 $.ui.focusable = function( element, hasTabindex ) { 3895 var map, mapName, img, focusableIfVisible, fieldset, 3896 nodeName = element.nodeName.toLowerCase(); 3897 3898 if ( "area" === nodeName ) { 3899 map = element.parentNode; 3900 mapName = map.name; 3901 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { 3902 return false; 3903 } 3904 img = $( "img[usemap='#" + mapName + "']" ); 3905 return img.length > 0 && img.is( ":visible" ); 3906 } 3907 3908 if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { 3909 focusableIfVisible = !element.disabled; 3910 3911 if ( focusableIfVisible ) { 3912 3913 // Form controls within a disabled fieldset are disabled. 3914 // However, controls within the fieldset's legend do not get disabled. 3915 // Since controls generally aren't placed inside legends, we skip 3916 // this portion of the check. 3917 fieldset = $( element ).closest( "fieldset" )[ 0 ]; 3918 if ( fieldset ) { 3919 focusableIfVisible = !fieldset.disabled; 3920 } 3921 } 3922 } else if ( "a" === nodeName ) { 3923 focusableIfVisible = element.href || hasTabindex; 3924 } else { 3925 focusableIfVisible = hasTabindex; 3926 } 3927 3928 return focusableIfVisible && $( element ).is( ":visible" ) && 3929 $( element ).css( "visibility" ) === "visible"; 3930 }; 3931 3932 $.extend( $.expr.pseudos, { 3933 focusable: function( element ) { 3934 return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); 3935 } 3936 } ); 3937 3938 var focusable = $.ui.focusable; 3939 3940 3941 /*! 3942 * jQuery UI Form Reset Mixin 1.14.1 3943 * https://jqueryui.com 3944 * 3945 * Copyright OpenJS Foundation and other contributors 3946 * Released under the MIT license. 3947 * https://jquery.org/license 3948 */ 3949 3950//>>label: Form Reset Mixin 3951//>>group: Core 3952//>>description: Refresh input widgets when their form is reset 3953//>>docs: https://api.jqueryui.com/form-reset-mixin/ 3954 3955 3956 var formResetMixin = $.ui.formResetMixin = { 3957 _formResetHandler: function() { 3958 var form = $( this ); 3959 3960 // Wait for the form reset to actually happen before refreshing 3961 setTimeout( function() { 3962 var instances = form.data( "ui-form-reset-instances" ); 3963 $.each( instances, function() { 3964 this.refresh(); 3965 } ); 3966 } ); 3967 }, 3968 3969 _bindFormResetHandler: function() { 3970 this.form = $( this.element.prop( "form" ) ); 3971 if ( !this.form.length ) { 3972 return; 3973 } 3974 3975 var instances = this.form.data( "ui-form-reset-instances" ) || []; 3976 if ( !instances.length ) { 3977 3978 // We don't use _on() here because we use a single event handler per form 3979 this.form.on( "reset.ui-form-reset", this._formResetHandler ); 3980 } 3981 instances.push( this ); 3982 this.form.data( "ui-form-reset-instances", instances ); 3983 }, 3984 3985 _unbindFormResetHandler: function() { 3986 if ( !this.form.length ) { 3987 return; 3988 } 3989 3990 var instances = this.form.data( "ui-form-reset-instances" ); 3991 instances.splice( $.inArray( this, instances ), 1 ); 3992 if ( instances.length ) { 3993 this.form.data( "ui-form-reset-instances", instances ); 3994 } else { 3995 this.form 3996 .removeData( "ui-form-reset-instances" ) 3997 .off( "reset.ui-form-reset" ); 3998 } 3999 } 4000 }; 4001 4002 4003 /*! 4004 * jQuery UI Legacy jQuery Core patches 1.14.1 4005 * https://jqueryui.com 4006 * 4007 * Copyright OpenJS Foundation and other contributors 4008 * Released under the MIT license. 4009 * https://jquery.org/license 4010 * 4011 */ 4012 4013//>>label: Legacy jQuery Core patches 4014//>>group: Core 4015//>>description: Backport `.even()`, `.odd()` and `$.escapeSelector` to older jQuery Core versions (deprecated) 4016 4017 4018// Support: jQuery 2.2.x or older. 4019// This method has been defined in jQuery 3.0.0. 4020// Code from https://github.com/jquery/jquery/blob/e539bac79e666bba95bba86d690b4e609dca2286/src/selector/escapeSelector.js 4021 if ( !$.escapeSelector ) { 4022 $.escapeSelector = function( id ) { 4023 return CSS.escape( id + "" ); 4024 }; 4025 } 4026 4027// Support: jQuery 3.4.x or older 4028// These methods have been defined in jQuery 3.5.0. 4029 if ( !$.fn.even || !$.fn.odd ) { 4030 $.fn.extend( { 4031 even: function() { 4032 return this.filter( function( i ) { 4033 return i % 2 === 0; 4034 } ); 4035 }, 4036 odd: function() { 4037 return this.filter( function( i ) { 4038 return i % 2 === 1; 4039 } ); 4040 } 4041 } ); 4042 } 4043 4044 ; 4045 /*! 4046 * jQuery UI Keycode 1.14.1 4047 * https://jqueryui.com 4048 * 4049 * Copyright OpenJS Foundation and other contributors 4050 * Released under the MIT license. 4051 * https://jquery.org/license 4052 */ 4053 4054//>>label: Keycode 4055//>>group: Core 4056//>>description: Provide keycodes as keynames 4057//>>docs: https://api.jqueryui.com/jQuery.ui.keyCode/ 4058 4059 4060 var keycode = $.ui.keyCode = { 4061 BACKSPACE: 8, 4062 COMMA: 188, 4063 DELETE: 46, 4064 DOWN: 40, 4065 END: 35, 4066 ENTER: 13, 4067 ESCAPE: 27, 4068 HOME: 36, 4069 LEFT: 37, 4070 PAGE_DOWN: 34, 4071 PAGE_UP: 33, 4072 PERIOD: 190, 4073 RIGHT: 39, 4074 SPACE: 32, 4075 TAB: 9, 4076 UP: 38 4077 }; 4078 4079 4080 /*! 4081 * jQuery UI Labels 1.14.1 4082 * https://jqueryui.com 4083 * 4084 * Copyright OpenJS Foundation and other contributors 4085 * Released under the MIT license. 4086 * https://jquery.org/license 4087 */ 4088 4089//>>label: labels 4090//>>group: Core 4091//>>description: Find all the labels associated with a given input 4092//>>docs: https://api.jqueryui.com/labels/ 4093 4094 4095 var labels = $.fn.labels = function() { 4096 var ancestor, selector, id, labels, ancestors; 4097 4098 if ( !this.length ) { 4099 return this.pushStack( [] ); 4100 } 4101 4102 // Check control.labels first 4103 if ( this[ 0 ].labels && this[ 0 ].labels.length ) { 4104 return this.pushStack( this[ 0 ].labels ); 4105 } 4106 4107 // If `control.labels` is empty - e.g. inside of document fragments - find 4108 // the labels manually 4109 labels = this.eq( 0 ).parents( "label" ); 4110 4111 // Look for the label based on the id 4112 id = this.attr( "id" ); 4113 if ( id ) { 4114 4115 // We don't search against the document in case the element 4116 // is disconnected from the DOM 4117 ancestor = this.eq( 0 ).parents().last(); 4118 4119 // Get a full set of top level ancestors 4120 ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); 4121 4122 // Create a selector for the label based on the id 4123 selector = "label[for='" + CSS.escape( id ) + "']"; 4124 4125 labels = labels.add( ancestors.find( selector ).addBack( selector ) ); 4126 4127 } 4128 4129 // Return whatever we have found for labels 4130 return this.pushStack( labels ); 4131 }; 4132 4133 4134 /*! 4135 * jQuery UI Scroll Parent 1.14.1 4136 * https://jqueryui.com 4137 * 4138 * Copyright OpenJS Foundation and other contributors 4139 * Released under the MIT license. 4140 * https://jquery.org/license 4141 */ 4142 4143//>>label: scrollParent 4144//>>group: Core 4145//>>description: Get the closest ancestor element that is scrollable. 4146//>>docs: https://api.jqueryui.com/scrollParent/ 4147 4148 4149 var scrollParent = $.fn.scrollParent = function( includeHidden ) { 4150 var position = this.css( "position" ), 4151 excludeStaticParent = position === "absolute", 4152 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, 4153 scrollParent = this.parents().filter( function() { 4154 var parent = $( this ); 4155 if ( excludeStaticParent && parent.css( "position" ) === "static" ) { 4156 return false; 4157 } 4158 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + 4159 parent.css( "overflow-x" ) ); 4160 } ).eq( 0 ); 4161 4162 return position === "fixed" || !scrollParent.length ? 4163 $( this[ 0 ].ownerDocument || document ) : 4164 scrollParent; 4165 }; 4166 4167 4168 /*! 4169 * jQuery UI Tabbable 1.14.1 4170 * https://jqueryui.com 4171 * 4172 * Copyright OpenJS Foundation and other contributors 4173 * Released under the MIT license. 4174 * https://jquery.org/license 4175 */ 4176 4177//>>label: :tabbable Selector 4178//>>group: Core 4179//>>description: Selects elements which can be tabbed to. 4180//>>docs: https://api.jqueryui.com/tabbable-selector/ 4181 4182 4183 var tabbable = $.extend( $.expr.pseudos, { 4184 tabbable: function( element ) { 4185 var tabIndex = $.attr( element, "tabindex" ), 4186 hasTabindex = tabIndex != null; 4187 return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); 4188 } 4189 } ); 4190 4191 4192 /*! 4193 * jQuery UI Unique ID 1.14.1 4194 * https://jqueryui.com 4195 * 4196 * Copyright OpenJS Foundation and other contributors 4197 * Released under the MIT license. 4198 * https://jquery.org/license 4199 */ 4200 4201//>>label: uniqueId 4202//>>group: Core 4203//>>description: Functions to generate and remove uniqueId's 4204//>>docs: https://api.jqueryui.com/uniqueId/ 4205 4206 4207 var uniqueId = $.fn.extend( { 4208 uniqueId: ( function() { 4209 var uuid = 0; 4210 4211 return function() { 4212 return this.each( function() { 4213 if ( !this.id ) { 4214 this.id = "ui-id-" + ( ++uuid ); 4215 } 4216 } ); 4217 }; 4218 } )(), 4219 4220 removeUniqueId: function() { 4221 return this.each( function() { 4222 if ( /^ui-id-\d+$/.test( this.id ) ) { 4223 $( this ).removeAttr( "id" ); 4224 } 4225 } ); 4226 } 4227 } ); 4228 4229 4230 /*! 4231 * jQuery UI Accordion 1.14.1 4232 * https://jqueryui.com 4233 * 4234 * Copyright OpenJS Foundation and other contributors 4235 * Released under the MIT license. 4236 * https://jquery.org/license 4237 */ 4238 4239//>>label: Accordion 4240//>>group: Widgets 4241 /* eslint-disable max-len */ 4242//>>description: Displays collapsible content panels for presenting information in a limited amount of space. 4243 /* eslint-enable max-len */ 4244//>>docs: https://api.jqueryui.com/accordion/ 4245//>>demos: https://jqueryui.com/accordion/ 4246//>>css.structure: ../../themes/base/core.css 4247//>>css.structure: ../../themes/base/accordion.css 4248//>>css.theme: ../../themes/base/theme.css 4249 4250 4251 var widgetsAccordion = $.widget( "ui.accordion", { 4252 version: "1.14.1", 4253 options: { 4254 active: 0, 4255 animate: {}, 4256 classes: { 4257 "ui-accordion-header": "ui-corner-top", 4258 "ui-accordion-header-collapsed": "ui-corner-all", 4259 "ui-accordion-content": "ui-corner-bottom" 4260 }, 4261 collapsible: false, 4262 event: "click", 4263 header: function( elem ) { 4264 return elem 4265 .find( "> li > :first-child" ) 4266 .add( 4267 elem.find( "> :not(li)" ) 4268 4269 // Support: jQuery <3.5 only 4270 // We could use `.even()` but that's unavailable in older jQuery. 4271 .filter( function( i ) { 4272 return i % 2 === 0; 4273 } ) 4274 ); 4275 }, 4276 heightStyle: "auto", 4277 icons: { 4278 activeHeader: "ui-icon-triangle-1-s", 4279 header: "ui-icon-triangle-1-e" 4280 }, 4281 4282 // Callbacks 4283 activate: null, 4284 beforeActivate: null 4285 }, 4286 4287 hideProps: { 4288 borderTopWidth: "hide", 4289 borderBottomWidth: "hide", 4290 paddingTop: "hide", 4291 paddingBottom: "hide", 4292 height: "hide" 4293 }, 4294 4295 showProps: { 4296 borderTopWidth: "show", 4297 borderBottomWidth: "show", 4298 paddingTop: "show", 4299 paddingBottom: "show", 4300 height: "show" 4301 }, 4302 4303 _create: function() { 4304 var options = this.options; 4305 4306 this.prevShow = this.prevHide = $(); 4307 this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); 4308 this.element.attr( "role", "tablist" ); 4309 4310 // Don't allow collapsible: false and active: false / null 4311 if ( !options.collapsible && ( options.active === false || options.active == null ) ) { 4312 options.active = 0; 4313 } 4314 4315 this._processPanels(); 4316 4317 // handle negative values 4318 if ( options.active < 0 ) { 4319 options.active += this.headers.length; 4320 } 4321 this._refresh(); 4322 }, 4323 4324 _getCreateEventData: function() { 4325 return { 4326 header: this.active, 4327 panel: !this.active.length ? $() : this.active.next() 4328 }; 4329 }, 4330 4331 _createIcons: function() { 4332 var icon, children, 4333 icons = this.options.icons; 4334 4335 if ( icons ) { 4336 icon = $( "<span>" ); 4337 this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); 4338 icon.prependTo( this.headers ); 4339 children = this.active.children( ".ui-accordion-header-icon" ); 4340 this._removeClass( children, icons.header ) 4341 ._addClass( children, null, icons.activeHeader ) 4342 ._addClass( this.headers, "ui-accordion-icons" ); 4343 } 4344 }, 4345 4346 _destroyIcons: function() { 4347 this._removeClass( this.headers, "ui-accordion-icons" ); 4348 this.headers.children( ".ui-accordion-header-icon" ).remove(); 4349 }, 4350 4351 _destroy: function() { 4352 var contents; 4353 4354 // Clean up main element 4355 this.element.removeAttr( "role" ); 4356 4357 // Clean up headers 4358 this.headers 4359 .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) 4360 .removeUniqueId(); 4361 4362 this._destroyIcons(); 4363 4364 // Clean up content panels 4365 contents = this.headers.next() 4366 .css( "display", "" ) 4367 .removeAttr( "role aria-hidden aria-labelledby" ) 4368 .removeUniqueId(); 4369 4370 if ( this.options.heightStyle !== "content" ) { 4371 contents.css( "height", "" ); 4372 } 4373 }, 4374 4375 _setOption: function( key, value ) { 4376 if ( key === "active" ) { 4377 4378 // _activate() will handle invalid values and update this.options 4379 this._activate( value ); 4380 return; 4381 } 4382 4383 if ( key === "event" ) { 4384 if ( this.options.event ) { 4385 this._off( this.headers, this.options.event ); 4386 } 4387 this._setupEvents( value ); 4388 } 4389 4390 this._super( key, value ); 4391 4392 // Setting collapsible: false while collapsed; open first panel 4393 if ( key === "collapsible" && !value && this.options.active === false ) { 4394 this._activate( 0 ); 4395 } 4396 4397 if ( key === "icons" ) { 4398 this._destroyIcons(); 4399 if ( value ) { 4400 this._createIcons(); 4401 } 4402 } 4403 }, 4404 4405 _setOptionDisabled: function( value ) { 4406 this._super( value ); 4407 4408 this.element.attr( "aria-disabled", value ); 4409 this._toggleClass( null, "ui-state-disabled", !!value ); 4410 }, 4411 4412 _keydown: function( event ) { 4413 if ( event.altKey || event.ctrlKey ) { 4414 return; 4415 } 4416 4417 var keyCode = $.ui.keyCode, 4418 length = this.headers.length, 4419 currentIndex = this.headers.index( event.target ), 4420 toFocus = false; 4421 4422 switch ( event.keyCode ) { 4423 case keyCode.RIGHT: 4424 case keyCode.DOWN: 4425 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 4426 break; 4427 case keyCode.LEFT: 4428 case keyCode.UP: 4429 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 4430 break; 4431 case keyCode.SPACE: 4432 case keyCode.ENTER: 4433 this._eventHandler( event ); 4434 break; 4435 case keyCode.HOME: 4436 toFocus = this.headers[ 0 ]; 4437 break; 4438 case keyCode.END: 4439 toFocus = this.headers[ length - 1 ]; 4440 break; 4441 } 4442 4443 if ( toFocus ) { 4444 $( event.target ).attr( "tabIndex", -1 ); 4445 $( toFocus ).attr( "tabIndex", 0 ); 4446 $( toFocus ).trigger( "focus" ); 4447 event.preventDefault(); 4448 } 4449 }, 4450 4451 _panelKeyDown: function( event ) { 4452 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { 4453 $( event.currentTarget ).prev().trigger( "focus" ); 4454 } 4455 }, 4456 4457 refresh: function() { 4458 var options = this.options; 4459 this._processPanels(); 4460 4461 // Was collapsed or no panel 4462 if ( ( options.active === false && options.collapsible === true ) || 4463 !this.headers.length ) { 4464 options.active = false; 4465 this.active = $(); 4466 4467 // active false only when collapsible is true 4468 } else if ( options.active === false ) { 4469 this._activate( 0 ); 4470 4471 // was active, but active panel is gone 4472 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 4473 4474 // all remaining panel are disabled 4475 if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { 4476 options.active = false; 4477 this.active = $(); 4478 4479 // activate previous panel 4480 } else { 4481 this._activate( Math.max( 0, options.active - 1 ) ); 4482 } 4483 4484 // was active, active panel still exists 4485 } else { 4486 4487 // make sure active index is correct 4488 options.active = this.headers.index( this.active ); 4489 } 4490 4491 this._destroyIcons(); 4492 4493 this._refresh(); 4494 }, 4495 4496 _processPanels: function() { 4497 var prevHeaders = this.headers, 4498 prevPanels = this.panels; 4499 4500 if ( typeof this.options.header === "function" ) { 4501 this.headers = this.options.header( this.element ); 4502 } else { 4503 this.headers = this.element.find( this.options.header ); 4504 } 4505 this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", 4506 "ui-state-default" ); 4507 4508 this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); 4509 this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); 4510 4511 // Avoid memory leaks (#10056) 4512 if ( prevPanels ) { 4513 this._off( prevHeaders.not( this.headers ) ); 4514 this._off( prevPanels.not( this.panels ) ); 4515 } 4516 }, 4517 4518 _refresh: function() { 4519 var maxHeight, 4520 options = this.options, 4521 heightStyle = options.heightStyle, 4522 parent = this.element.parent(); 4523 4524 this.active = this._findActive( options.active ); 4525 this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) 4526 ._removeClass( this.active, "ui-accordion-header-collapsed" ); 4527 this._addClass( this.active.next(), "ui-accordion-content-active" ); 4528 this.active.next().show(); 4529 4530 this.headers 4531 .attr( "role", "tab" ) 4532 .each( function() { 4533 var header = $( this ), 4534 headerId = header.uniqueId().attr( "id" ), 4535 panel = header.next(), 4536 panelId = panel.uniqueId().attr( "id" ); 4537 header.attr( "aria-controls", panelId ); 4538 panel.attr( "aria-labelledby", headerId ); 4539 } ) 4540 .next() 4541 .attr( "role", "tabpanel" ); 4542 4543 this.headers 4544 .not( this.active ) 4545 .attr( { 4546 "aria-selected": "false", 4547 "aria-expanded": "false", 4548 tabIndex: -1 4549 } ) 4550 .next() 4551 .attr( { 4552 "aria-hidden": "true" 4553 } ) 4554 .hide(); 4555 4556 // Make sure at least one header is in the tab order 4557 if ( !this.active.length ) { 4558 this.headers.eq( 0 ).attr( "tabIndex", 0 ); 4559 } else { 4560 this.active.attr( { 4561 "aria-selected": "true", 4562 "aria-expanded": "true", 4563 tabIndex: 0 4564 } ) 4565 .next() 4566 .attr( { 4567 "aria-hidden": "false" 4568 } ); 4569 } 4570 4571 this._createIcons(); 4572 4573 this._setupEvents( options.event ); 4574 4575 if ( heightStyle === "fill" ) { 4576 maxHeight = parent.height(); 4577 this.element.siblings( ":visible" ).each( function() { 4578 var elem = $( this ), 4579 position = elem.css( "position" ); 4580 4581 if ( position === "absolute" || position === "fixed" ) { 4582 return; 4583 } 4584 maxHeight -= elem.outerHeight( true ); 4585 } ); 4586 4587 this.headers.each( function() { 4588 maxHeight -= $( this ).outerHeight( true ); 4589 } ); 4590 4591 this.headers.next() 4592 .each( function() { 4593 $( this ).height( Math.max( 0, maxHeight - 4594 $( this ).innerHeight() + $( this ).height() ) ); 4595 } ) 4596 .css( "overflow", "auto" ); 4597 } else if ( heightStyle === "auto" ) { 4598 maxHeight = 0; 4599 this.headers.next() 4600 .each( function() { 4601 var isVisible = $( this ).is( ":visible" ); 4602 if ( !isVisible ) { 4603 $( this ).show(); 4604 } 4605 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); 4606 if ( !isVisible ) { 4607 $( this ).hide(); 4608 } 4609 } ) 4610 .height( maxHeight ); 4611 } 4612 }, 4613 4614 _activate: function( index ) { 4615 var active = this._findActive( index )[ 0 ]; 4616 4617 // Trying to activate the already active panel 4618 if ( active === this.active[ 0 ] ) { 4619 return; 4620 } 4621 4622 // Trying to collapse, simulate a click on the currently active header 4623 active = active || this.active[ 0 ]; 4624 4625 this._eventHandler( { 4626 target: active, 4627 currentTarget: active, 4628 preventDefault: $.noop 4629 } ); 4630 }, 4631 4632 _findActive: function( selector ) { 4633 return typeof selector === "number" ? this.headers.eq( selector ) : $(); 4634 }, 4635 4636 _setupEvents: function( event ) { 4637 var events = { 4638 keydown: "_keydown" 4639 }; 4640 if ( event ) { 4641 $.each( event.split( " " ), function( index, eventName ) { 4642 events[ eventName ] = "_eventHandler"; 4643 } ); 4644 } 4645 4646 this._off( this.headers.add( this.headers.next() ) ); 4647 this._on( this.headers, events ); 4648 this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); 4649 this._hoverable( this.headers ); 4650 this._focusable( this.headers ); 4651 }, 4652 4653 _eventHandler: function( event ) { 4654 var activeChildren, clickedChildren, 4655 options = this.options, 4656 active = this.active, 4657 clicked = $( event.currentTarget ), 4658 clickedIsActive = clicked[ 0 ] === active[ 0 ], 4659 collapsing = clickedIsActive && options.collapsible, 4660 toShow = collapsing ? $() : clicked.next(), 4661 toHide = active.next(), 4662 eventData = { 4663 oldHeader: active, 4664 oldPanel: toHide, 4665 newHeader: collapsing ? $() : clicked, 4666 newPanel: toShow 4667 }; 4668 4669 event.preventDefault(); 4670 4671 if ( 4672 4673 // click on active header, but not collapsible 4674 ( clickedIsActive && !options.collapsible ) || 4675 4676 // allow canceling activation 4677 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 4678 return; 4679 } 4680 4681 options.active = collapsing ? false : this.headers.index( clicked ); 4682 4683 // When the call to ._toggle() comes after the class changes 4684 // it causes a very odd bug in IE 8 (see #6720) 4685 this.active = clickedIsActive ? $() : clicked; 4686 this._toggle( eventData ); 4687 4688 // Switch classes 4689 // corner classes on the previously active header stay after the animation 4690 this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); 4691 if ( options.icons ) { 4692 activeChildren = active.children( ".ui-accordion-header-icon" ); 4693 this._removeClass( activeChildren, null, options.icons.activeHeader ) 4694 ._addClass( activeChildren, null, options.icons.header ); 4695 } 4696 4697 if ( !clickedIsActive ) { 4698 this._removeClass( clicked, "ui-accordion-header-collapsed" ) 4699 ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); 4700 if ( options.icons ) { 4701 clickedChildren = clicked.children( ".ui-accordion-header-icon" ); 4702 this._removeClass( clickedChildren, null, options.icons.header ) 4703 ._addClass( clickedChildren, null, options.icons.activeHeader ); 4704 } 4705 4706 this._addClass( clicked.next(), "ui-accordion-content-active" ); 4707 } 4708 }, 4709 4710 _toggle: function( data ) { 4711 var toShow = data.newPanel, 4712 toHide = this.prevShow.length ? this.prevShow : data.oldPanel; 4713 4714 // Handle activating a panel during the animation for another activation 4715 this.prevShow.add( this.prevHide ).stop( true, true ); 4716 this.prevShow = toShow; 4717 this.prevHide = toHide; 4718 4719 if ( this.options.animate ) { 4720 this._animate( toShow, toHide, data ); 4721 } else { 4722 toHide.hide(); 4723 toShow.show(); 4724 this._toggleComplete( data ); 4725 } 4726 4727 toHide.attr( { 4728 "aria-hidden": "true" 4729 } ); 4730 toHide.prev().attr( { 4731 "aria-selected": "false", 4732 "aria-expanded": "false" 4733 } ); 4734 4735 // if we're switching panels, remove the old header from the tab order 4736 // if we're opening from collapsed state, remove the previous header from the tab order 4737 // if we're collapsing, then keep the collapsing header in the tab order 4738 if ( toShow.length && toHide.length ) { 4739 toHide.prev().attr( { 4740 "tabIndex": -1, 4741 "aria-expanded": "false" 4742 } ); 4743 } else if ( toShow.length ) { 4744 this.headers.filter( function() { 4745 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; 4746 } ) 4747 .attr( "tabIndex", -1 ); 4748 } 4749 4750 toShow 4751 .attr( "aria-hidden", "false" ) 4752 .prev() 4753 .attr( { 4754 "aria-selected": "true", 4755 "aria-expanded": "true", 4756 tabIndex: 0 4757 } ); 4758 }, 4759 4760 _animate: function( toShow, toHide, data ) { 4761 var total, easing, duration, 4762 that = this, 4763 adjust = 0, 4764 boxSizing = toShow.css( "box-sizing" ), 4765 down = toShow.length && 4766 ( !toHide.length || ( toShow.index() < toHide.index() ) ), 4767 animate = this.options.animate || {}, 4768 options = down && animate.down || animate, 4769 complete = function() { 4770 that._toggleComplete( data ); 4771 }; 4772 4773 if ( typeof options === "number" ) { 4774 duration = options; 4775 } 4776 if ( typeof options === "string" ) { 4777 easing = options; 4778 } 4779 4780 // fall back from options to animation in case of partial down settings 4781 easing = easing || options.easing || animate.easing; 4782 duration = duration || options.duration || animate.duration; 4783 4784 if ( !toHide.length ) { 4785 return toShow.animate( this.showProps, duration, easing, complete ); 4786 } 4787 if ( !toShow.length ) { 4788 return toHide.animate( this.hideProps, duration, easing, complete ); 4789 } 4790 4791 total = toShow.show().outerHeight(); 4792 toHide.animate( this.hideProps, { 4793 duration: duration, 4794 easing: easing, 4795 step: function( now, fx ) { 4796 fx.now = Math.round( now ); 4797 } 4798 } ); 4799 toShow 4800 .hide() 4801 .animate( this.showProps, { 4802 duration: duration, 4803 easing: easing, 4804 complete: complete, 4805 step: function( now, fx ) { 4806 fx.now = Math.round( now ); 4807 if ( fx.prop !== "height" ) { 4808 if ( boxSizing === "content-box" ) { 4809 adjust += fx.now; 4810 } 4811 } else if ( that.options.heightStyle !== "content" ) { 4812 fx.now = Math.round( total - toHide.outerHeight() - adjust ); 4813 adjust = 0; 4814 } 4815 } 4816 } ); 4817 }, 4818 4819 _toggleComplete: function( data ) { 4820 var toHide = data.oldPanel, 4821 prev = toHide.prev(); 4822 4823 this._removeClass( toHide, "ui-accordion-content-active" ); 4824 this._removeClass( prev, "ui-accordion-header-active" ) 4825 ._addClass( prev, "ui-accordion-header-collapsed" ); 4826 4827 this._trigger( "activate", null, data ); 4828 } 4829 } ); 4830 4831 4832 /*! 4833 * jQuery UI Menu 1.14.1 4834 * https://jqueryui.com 4835 * 4836 * Copyright OpenJS Foundation and other contributors 4837 * Released under the MIT license. 4838 * https://jquery.org/license 4839 */ 4840 4841//>>label: Menu 4842//>>group: Widgets 4843//>>description: Creates nestable menus. 4844//>>docs: https://api.jqueryui.com/menu/ 4845//>>demos: https://jqueryui.com/menu/ 4846//>>css.structure: ../../themes/base/core.css 4847//>>css.structure: ../../themes/base/menu.css 4848//>>css.theme: ../../themes/base/theme.css 4849 4850 4851 var widgetsMenu = $.widget( "ui.menu", { 4852 version: "1.14.1", 4853 defaultElement: "<ul>", 4854 delay: 300, 4855 options: { 4856 icons: { 4857 submenu: "ui-icon-caret-1-e" 4858 }, 4859 items: "> *", 4860 menus: "ul", 4861 position: { 4862 my: "left top", 4863 at: "right top" 4864 }, 4865 role: "menu", 4866 4867 // Callbacks 4868 blur: null, 4869 focus: null, 4870 select: null 4871 }, 4872 4873 _create: function() { 4874 this.activeMenu = this.element; 4875 4876 // Flag used to prevent firing of the click handler 4877 // as the event bubbles up through nested menus 4878 this.mouseHandled = false; 4879 this.lastMousePosition = { x: null, y: null }; 4880 this.element 4881 .uniqueId() 4882 .attr( { 4883 role: this.options.role, 4884 tabIndex: 0 4885 } ); 4886 4887 this._addClass( "ui-menu", "ui-widget ui-widget-content" ); 4888 this._on( { 4889 4890 // Prevent focus from sticking to links inside menu after clicking 4891 // them (focus should always stay on UL during navigation). 4892 "mousedown .ui-menu-item": function( event ) { 4893 event.preventDefault(); 4894 4895 this._activateItem( event ); 4896 }, 4897 "click .ui-menu-item": function( event ) { 4898 var target = $( event.target ); 4899 var active = $( this.document[ 0 ].activeElement ); 4900 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { 4901 this.select( event ); 4902 4903 // Only set the mouseHandled flag if the event will bubble, see #9469. 4904 if ( !event.isPropagationStopped() ) { 4905 this.mouseHandled = true; 4906 } 4907 4908 // Open submenu on click 4909 if ( target.has( ".ui-menu" ).length ) { 4910 this.expand( event ); 4911 } else if ( !this.element.is( ":focus" ) && 4912 active.closest( ".ui-menu" ).length ) { 4913 4914 // Redirect focus to the menu 4915 this.element.trigger( "focus", [ true ] ); 4916 4917 // If the active item is on the top level, let it stay active. 4918 // Otherwise, blur the active item since it is no longer visible. 4919 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { 4920 clearTimeout( this.timer ); 4921 } 4922 } 4923 } 4924 }, 4925 "mouseenter .ui-menu-item": "_activateItem", 4926 "mousemove .ui-menu-item": "_activateItem", 4927 mouseleave: "collapseAll", 4928 "mouseleave .ui-menu": "collapseAll", 4929 focus: function( event, keepActiveItem ) { 4930 4931 // If there's already an active item, keep it active 4932 // If not, activate the first item 4933 var item = this.active || this._menuItems().first(); 4934 4935 if ( !keepActiveItem ) { 4936 this.focus( event, item ); 4937 } 4938 }, 4939 blur: function( event ) { 4940 this._delay( function() { 4941 var notContained = !$.contains( 4942 this.element[ 0 ], 4943 this.document[ 0 ].activeElement 4944 ); 4945 if ( notContained ) { 4946 this.collapseAll( event ); 4947 } 4948 } ); 4949 }, 4950 keydown: "_keydown" 4951 } ); 4952 4953 this.refresh(); 4954 4955 // Clicks outside of a menu collapse any open menus 4956 this._on( this.document, { 4957 click: function( event ) { 4958 if ( this._closeOnDocumentClick( event ) ) { 4959 this.collapseAll( event, true ); 4960 } 4961 4962 // Reset the mouseHandled flag 4963 this.mouseHandled = false; 4964 } 4965 } ); 4966 }, 4967 4968 _activateItem: function( event ) { 4969 4970 // Ignore mouse events while typeahead is active, see #10458. 4971 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse 4972 // is over an item in the menu 4973 if ( this.previousFilter ) { 4974 return; 4975 } 4976 4977 // If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356) 4978 if ( event.clientX === this.lastMousePosition.x && 4979 event.clientY === this.lastMousePosition.y ) { 4980 return; 4981 } 4982 4983 this.lastMousePosition = { 4984 x: event.clientX, 4985 y: event.clientY 4986 }; 4987 4988 var actualTarget = $( event.target ).closest( ".ui-menu-item" ), 4989 target = $( event.currentTarget ); 4990 4991 // Ignore bubbled events on parent items, see #11641 4992 if ( actualTarget[ 0 ] !== target[ 0 ] ) { 4993 return; 4994 } 4995 4996 // If the item is already active, there's nothing to do 4997 if ( target.is( ".ui-state-active" ) ) { 4998 return; 4999 } 5000 5001 // Remove ui-state-active class from siblings of the newly focused menu item 5002 // to avoid a jump caused by adjacent elements both having a class with a border 5003 this._removeClass( target.siblings().children( ".ui-state-active" ), 5004 null, "ui-state-active" ); 5005 this.focus( event, target ); 5006 }, 5007 5008 _destroy: function() { 5009 var items = this.element.find( ".ui-menu-item" ) 5010 .removeAttr( "role aria-disabled" ), 5011 submenus = items.children( ".ui-menu-item-wrapper" ) 5012 .removeUniqueId() 5013 .removeAttr( "tabIndex role aria-haspopup" ); 5014 5015 // Destroy (sub)menus 5016 this.element 5017 .removeAttr( "aria-activedescendant" ) 5018 .find( ".ui-menu" ).addBack() 5019 .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " + 5020 "tabIndex" ) 5021 .removeUniqueId() 5022 .show(); 5023 5024 submenus.children().each( function() { 5025 var elem = $( this ); 5026 if ( elem.data( "ui-menu-submenu-caret" ) ) { 5027 elem.remove(); 5028 } 5029 } ); 5030 }, 5031 5032 _keydown: function( event ) { 5033 var match, prev, character, skip, 5034 preventDefault = true; 5035 5036 switch ( event.keyCode ) { 5037 case $.ui.keyCode.PAGE_UP: 5038 this.previousPage( event ); 5039 break; 5040 case $.ui.keyCode.PAGE_DOWN: 5041 this.nextPage( event ); 5042 break; 5043 case $.ui.keyCode.HOME: 5044 this._move( "first", "first", event ); 5045 break; 5046 case $.ui.keyCode.END: 5047 this._move( "last", "last", event ); 5048 break; 5049 case $.ui.keyCode.UP: 5050 this.previous( event ); 5051 break; 5052 case $.ui.keyCode.DOWN: 5053 this.next( event ); 5054 break; 5055 case $.ui.keyCode.LEFT: 5056 this.collapse( event ); 5057 break; 5058 case $.ui.keyCode.RIGHT: 5059 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 5060 this.expand( event ); 5061 } 5062 break; 5063 case $.ui.keyCode.ENTER: 5064 case $.ui.keyCode.SPACE: 5065 this._activate( event ); 5066 break; 5067 case $.ui.keyCode.ESCAPE: 5068 this.collapse( event ); 5069 break; 5070 default: 5071 preventDefault = false; 5072 prev = this.previousFilter || ""; 5073 skip = false; 5074 5075 // Support number pad values 5076 character = event.keyCode >= 96 && event.keyCode <= 105 ? 5077 ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode ); 5078 5079 clearTimeout( this.filterTimer ); 5080 5081 if ( character === prev ) { 5082 skip = true; 5083 } else { 5084 character = prev + character; 5085 } 5086 5087 match = this._filterMenuItems( character ); 5088 match = skip && match.index( this.active.next() ) !== -1 ? 5089 this.active.nextAll( ".ui-menu-item" ) : 5090 match; 5091 5092 // If no matches on the current filter, reset to the last character pressed 5093 // to move down the menu to the first item that starts with that character 5094 if ( !match.length ) { 5095 character = String.fromCharCode( event.keyCode ); 5096 match = this._filterMenuItems( character ); 5097 } 5098 5099 if ( match.length ) { 5100 this.focus( event, match ); 5101 this.previousFilter = character; 5102 this.filterTimer = this._delay( function() { 5103 delete this.previousFilter; 5104 }, 1000 ); 5105 } else { 5106 delete this.previousFilter; 5107 } 5108 } 5109 5110 if ( preventDefault ) { 5111 event.preventDefault(); 5112 } 5113 }, 5114 5115 _activate: function( event ) { 5116 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 5117 if ( this.active.children( "[aria-haspopup='true']" ).length ) { 5118 this.expand( event ); 5119 } else { 5120 this.select( event ); 5121 } 5122 } 5123 }, 5124 5125 refresh: function() { 5126 var menus, items, newSubmenus, newItems, newWrappers, 5127 that = this, 5128 icon = this.options.icons.submenu, 5129 submenus = this.element.find( this.options.menus ); 5130 5131 this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length ); 5132 5133 // Initialize nested menus 5134 newSubmenus = submenus.filter( ":not(.ui-menu)" ) 5135 .hide() 5136 .attr( { 5137 role: this.options.role, 5138 "aria-hidden": "true", 5139 "aria-expanded": "false" 5140 } ) 5141 .each( function() { 5142 var menu = $( this ), 5143 item = menu.prev(), 5144 submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true ); 5145 5146 that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon ); 5147 item 5148 .attr( "aria-haspopup", "true" ) 5149 .prepend( submenuCaret ); 5150 menu.attr( "aria-labelledby", item.attr( "id" ) ); 5151 } ); 5152 5153 this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" ); 5154 5155 menus = submenus.add( this.element ); 5156 items = menus.find( this.options.items ); 5157 5158 // Initialize menu-items containing spaces and/or dashes only as dividers 5159 items.not( ".ui-menu-item" ).each( function() { 5160 var item = $( this ); 5161 if ( that._isDivider( item ) ) { 5162 that._addClass( item, "ui-menu-divider", "ui-widget-content" ); 5163 } 5164 } ); 5165 5166 // Don't refresh list items that are already adapted 5167 newItems = items.not( ".ui-menu-item, .ui-menu-divider" ); 5168 newWrappers = newItems.children() 5169 .not( ".ui-menu" ) 5170 .uniqueId() 5171 .attr( { 5172 tabIndex: -1, 5173 role: this._itemRole() 5174 } ); 5175 this._addClass( newItems, "ui-menu-item" ) 5176 ._addClass( newWrappers, "ui-menu-item-wrapper" ); 5177 5178 // Add aria-disabled attribute to any disabled menu item 5179 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); 5180 5181 // If the active item has been removed, blur the menu 5182 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 5183 this.blur(); 5184 } 5185 }, 5186 5187 _itemRole: function() { 5188 return { 5189 menu: "menuitem", 5190 listbox: "option" 5191 }[ this.options.role ]; 5192 }, 5193 5194 _setOption: function( key, value ) { 5195 if ( key === "icons" ) { 5196 var icons = this.element.find( ".ui-menu-icon" ); 5197 this._removeClass( icons, null, this.options.icons.submenu ) 5198 ._addClass( icons, null, value.submenu ); 5199 } 5200 this._super( key, value ); 5201 }, 5202 5203 _setOptionDisabled: function( value ) { 5204 this._super( value ); 5205 5206 this.element.attr( "aria-disabled", String( value ) ); 5207 this._toggleClass( null, "ui-state-disabled", !!value ); 5208 }, 5209 5210 focus: function( event, item ) { 5211 var nested, focused, activeParent; 5212 this.blur( event, event && event.type === "focus" ); 5213 5214 this._scrollIntoView( item ); 5215 5216 this.active = item.first(); 5217 5218 focused = this.active.children( ".ui-menu-item-wrapper" ); 5219 this._addClass( focused, null, "ui-state-active" ); 5220 5221 // Only update aria-activedescendant if there's a role 5222 // otherwise we assume focus is managed elsewhere 5223 if ( this.options.role ) { 5224 this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); 5225 } 5226 5227 // Highlight active parent menu item, if any 5228 activeParent = this.active 5229 .parent() 5230 .closest( ".ui-menu-item" ) 5231 .children( ".ui-menu-item-wrapper" ); 5232 this._addClass( activeParent, null, "ui-state-active" ); 5233 5234 if ( event && event.type === "keydown" ) { 5235 this._close(); 5236 } else { 5237 this.timer = this._delay( function() { 5238 this._close(); 5239 }, this.delay ); 5240 } 5241 5242 nested = item.children( ".ui-menu" ); 5243 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { 5244 this._startOpening( nested ); 5245 } 5246 this.activeMenu = item.parent(); 5247 5248 this._trigger( "focus", event, { item: item } ); 5249 }, 5250 5251 _scrollIntoView: function( item ) { 5252 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; 5253 if ( this._hasScroll() ) { 5254 borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0; 5255 paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0; 5256 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; 5257 scroll = this.activeMenu.scrollTop(); 5258 elementHeight = this.activeMenu.height(); 5259 itemHeight = item.outerHeight(); 5260 5261 if ( offset < 0 ) { 5262 this.activeMenu.scrollTop( scroll + offset ); 5263 } else if ( offset + itemHeight > elementHeight ) { 5264 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); 5265 } 5266 } 5267 }, 5268 5269 blur: function( event, fromFocus ) { 5270 if ( !fromFocus ) { 5271 clearTimeout( this.timer ); 5272 } 5273 5274 if ( !this.active ) { 5275 return; 5276 } 5277 5278 this._removeClass( this.active.children( ".ui-menu-item-wrapper" ), 5279 null, "ui-state-active" ); 5280 5281 this._trigger( "blur", event, { item: this.active } ); 5282 this.active = null; 5283 }, 5284 5285 _startOpening: function( submenu ) { 5286 clearTimeout( this.timer ); 5287 5288 // Don't open if already open fixes a Firefox bug that caused a .5 pixel 5289 // shift in the submenu position when mousing over the caret icon 5290 if ( submenu.attr( "aria-hidden" ) !== "true" ) { 5291 return; 5292 } 5293 5294 this.timer = this._delay( function() { 5295 this._close(); 5296 this._open( submenu ); 5297 }, this.delay ); 5298 }, 5299 5300 _open: function( submenu ) { 5301 var position = $.extend( { 5302 of: this.active 5303 }, this.options.position ); 5304 5305 clearTimeout( this.timer ); 5306 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) 5307 .hide() 5308 .attr( "aria-hidden", "true" ); 5309 5310 submenu 5311 .show() 5312 .removeAttr( "aria-hidden" ) 5313 .attr( "aria-expanded", "true" ) 5314 .position( position ); 5315 }, 5316 5317 collapseAll: function( event, all ) { 5318 clearTimeout( this.timer ); 5319 this.timer = this._delay( function() { 5320 5321 // If we were passed an event, look for the submenu that contains the event 5322 var currentMenu = all ? this.element : 5323 $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); 5324 5325 // If we found no valid submenu ancestor, use the main menu to close all 5326 // sub menus anyway 5327 if ( !currentMenu.length ) { 5328 currentMenu = this.element; 5329 } 5330 5331 this._close( currentMenu ); 5332 5333 this.blur( event ); 5334 5335 // Work around active item staying active after menu is blurred 5336 this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" ); 5337 5338 this.activeMenu = currentMenu; 5339 }, all ? 0 : this.delay ); 5340 }, 5341 5342 // With no arguments, closes the currently active menu - if nothing is active 5343 // it closes all menus. If passed an argument, it will search for menus BELOW 5344 _close: function( startMenu ) { 5345 if ( !startMenu ) { 5346 startMenu = this.active ? this.active.parent() : this.element; 5347 } 5348 5349 startMenu.find( ".ui-menu" ) 5350 .hide() 5351 .attr( "aria-hidden", "true" ) 5352 .attr( "aria-expanded", "false" ); 5353 }, 5354 5355 _closeOnDocumentClick: function( event ) { 5356 return !$( event.target ).closest( ".ui-menu" ).length; 5357 }, 5358 5359 _isDivider: function( item ) { 5360 5361 // Match hyphen, em dash, en dash 5362 return !/[^\-\u2014\u2013\s]/.test( item.text() ); 5363 }, 5364 5365 collapse: function( event ) { 5366 var newItem = this.active && 5367 this.active.parent().closest( ".ui-menu-item", this.element ); 5368 if ( newItem && newItem.length ) { 5369 this._close(); 5370 this.focus( event, newItem ); 5371 } 5372 }, 5373 5374 expand: function( event ) { 5375 var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first(); 5376 5377 if ( newItem && newItem.length ) { 5378 this._open( newItem.parent() ); 5379 5380 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT 5381 this._delay( function() { 5382 this.focus( event, newItem ); 5383 } ); 5384 } 5385 }, 5386 5387 next: function( event ) { 5388 this._move( "next", "first", event ); 5389 }, 5390 5391 previous: function( event ) { 5392 this._move( "prev", "last", event ); 5393 }, 5394 5395 isFirstItem: function() { 5396 return this.active && !this.active.prevAll( ".ui-menu-item" ).length; 5397 }, 5398 5399 isLastItem: function() { 5400 return this.active && !this.active.nextAll( ".ui-menu-item" ).length; 5401 }, 5402 5403 _menuItems: function( menu ) { 5404 return ( menu || this.element ) 5405 .find( this.options.items ) 5406 .filter( ".ui-menu-item" ); 5407 }, 5408 5409 _move: function( direction, filter, event ) { 5410 var next; 5411 if ( this.active ) { 5412 if ( direction === "first" || direction === "last" ) { 5413 next = this.active 5414 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) 5415 .last(); 5416 } else { 5417 next = this.active 5418 [ direction + "All" ]( ".ui-menu-item" ) 5419 .first(); 5420 } 5421 } 5422 if ( !next || !next.length || !this.active ) { 5423 next = this._menuItems( this.activeMenu )[ filter ](); 5424 } 5425 5426 this.focus( event, next ); 5427 }, 5428 5429 nextPage: function( event ) { 5430 var item, base, height; 5431 5432 if ( !this.active ) { 5433 this.next( event ); 5434 return; 5435 } 5436 if ( this.isLastItem() ) { 5437 return; 5438 } 5439 if ( this._hasScroll() ) { 5440 base = this.active.offset().top; 5441 height = this.element.innerHeight(); 5442 5443 // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back. 5444 if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) { 5445 height += this.element[ 0 ].offsetHeight - this.element.outerHeight(); 5446 } 5447 5448 this.active.nextAll( ".ui-menu-item" ).each( function() { 5449 item = $( this ); 5450 return item.offset().top - base - height < 0; 5451 } ); 5452 5453 this.focus( event, item ); 5454 } else { 5455 this.focus( event, this._menuItems( this.activeMenu ) 5456 [ !this.active ? "first" : "last" ]() ); 5457 } 5458 }, 5459 5460 previousPage: function( event ) { 5461 var item, base, height; 5462 if ( !this.active ) { 5463 this.next( event ); 5464 return; 5465 } 5466 if ( this.isFirstItem() ) { 5467 return; 5468 } 5469 if ( this._hasScroll() ) { 5470 base = this.active.offset().top; 5471 height = this.element.innerHeight(); 5472 5473 // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back. 5474 if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) { 5475 height += this.element[ 0 ].offsetHeight - this.element.outerHeight(); 5476 } 5477 5478 this.active.prevAll( ".ui-menu-item" ).each( function() { 5479 item = $( this ); 5480 return item.offset().top - base + height > 0; 5481 } ); 5482 5483 this.focus( event, item ); 5484 } else { 5485 this.focus( event, this._menuItems( this.activeMenu ).first() ); 5486 } 5487 }, 5488 5489 _hasScroll: function() { 5490 return this.element.outerHeight() < this.element.prop( "scrollHeight" ); 5491 }, 5492 5493 select: function( event ) { 5494 5495 // TODO: It should never be possible to not have an active item at this 5496 // point, but the tests don't trigger mouseenter before click. 5497 this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); 5498 var ui = { item: this.active }; 5499 if ( !this.active.has( ".ui-menu" ).length ) { 5500 this.collapseAll( event, true ); 5501 } 5502 this._trigger( "select", event, ui ); 5503 }, 5504 5505 _filterMenuItems: function( character ) { 5506 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), 5507 regex = new RegExp( "^" + escapedCharacter, "i" ); 5508 5509 return this.activeMenu 5510 .find( this.options.items ) 5511 5512 // Only match on items, not dividers or other content (#10571) 5513 .filter( ".ui-menu-item" ) 5514 .filter( function() { 5515 return regex.test( 5516 String.prototype.trim.call( 5517 $( this ).children( ".ui-menu-item-wrapper" ).text() ) ); 5518 } ); 5519 } 5520 } ); 5521 5522 5523 /*! 5524 * jQuery UI Autocomplete 1.14.1 5525 * https://jqueryui.com 5526 * 5527 * Copyright OpenJS Foundation and other contributors 5528 * Released under the MIT license. 5529 * https://jquery.org/license 5530 */ 5531 5532//>>label: Autocomplete 5533//>>group: Widgets 5534//>>description: Lists suggested words as the user is typing. 5535//>>docs: https://api.jqueryui.com/autocomplete/ 5536//>>demos: https://jqueryui.com/autocomplete/ 5537//>>css.structure: ../../themes/base/core.css 5538//>>css.structure: ../../themes/base/autocomplete.css 5539//>>css.theme: ../../themes/base/theme.css 5540 5541 5542 $.widget( "ui.autocomplete", { 5543 version: "1.14.1", 5544 defaultElement: "<input>", 5545 options: { 5546 appendTo: null, 5547 autoFocus: false, 5548 delay: 300, 5549 minLength: 1, 5550 position: { 5551 my: "left top", 5552 at: "left bottom", 5553 collision: "none" 5554 }, 5555 source: null, 5556 5557 // Callbacks 5558 change: null, 5559 close: null, 5560 focus: null, 5561 open: null, 5562 response: null, 5563 search: null, 5564 select: null 5565 }, 5566 5567 requestIndex: 0, 5568 pending: 0, 5569 liveRegionTimer: null, 5570 5571 _create: function() { 5572 5573 // Some browsers only repeat keydown events, not keypress events, 5574 // so we use the suppressKeyPress flag to determine if we've already 5575 // handled the keydown event. #7269 5576 // Unfortunately the code for & in keypress is the same as the up arrow, 5577 // so we use the suppressKeyPressRepeat flag to avoid handling keypress 5578 // events when we know the keydown event was used to modify the 5579 // search term. #7799 5580 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, 5581 nodeName = this.element[ 0 ].nodeName.toLowerCase(), 5582 isTextarea = nodeName === "textarea", 5583 isInput = nodeName === "input"; 5584 5585 // Textareas are always multi-line 5586 // Inputs are always single-line, even if inside a contentEditable element 5587 // All other element types are determined by whether they're contentEditable 5588 this.isMultiLine = isTextarea || 5589 !isInput && this.element.prop( "contentEditable" ) === "true"; 5590 5591 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; 5592 this.isNewMenu = true; 5593 5594 this._addClass( "ui-autocomplete-input" ); 5595 this.element.attr( "autocomplete", "off" ); 5596 5597 this._on( this.element, { 5598 keydown: function( event ) { 5599 if ( this.element.prop( "readOnly" ) ) { 5600 suppressKeyPress = true; 5601 suppressInput = true; 5602 suppressKeyPressRepeat = true; 5603 return; 5604 } 5605 5606 suppressKeyPress = false; 5607 suppressInput = false; 5608 suppressKeyPressRepeat = false; 5609 var keyCode = $.ui.keyCode; 5610 switch ( event.keyCode ) { 5611 case keyCode.PAGE_UP: 5612 suppressKeyPress = true; 5613 this._move( "previousPage", event ); 5614 break; 5615 case keyCode.PAGE_DOWN: 5616 suppressKeyPress = true; 5617 this._move( "nextPage", event ); 5618 break; 5619 case keyCode.UP: 5620 suppressKeyPress = true; 5621 this._keyEvent( "previous", event ); 5622 break; 5623 case keyCode.DOWN: 5624 suppressKeyPress = true; 5625 this._keyEvent( "next", event ); 5626 break; 5627 case keyCode.ENTER: 5628 5629 // when menu is open and has focus 5630 if ( this.menu.active ) { 5631 5632 // #6055 - Opera still allows the keypress to occur 5633 // which causes forms to submit 5634 suppressKeyPress = true; 5635 event.preventDefault(); 5636 this.menu.select( event ); 5637 } 5638 break; 5639 case keyCode.TAB: 5640 if ( this.menu.active ) { 5641 this.menu.select( event ); 5642 } 5643 break; 5644 case keyCode.ESCAPE: 5645 if ( this.menu.element.is( ":visible" ) ) { 5646 if ( !this.isMultiLine ) { 5647 this._value( this.term ); 5648 } 5649 this.close( event ); 5650 5651 // Different browsers have different default behavior for escape 5652 // Single press can mean undo or clear 5653 event.preventDefault(); 5654 } 5655 break; 5656 default: 5657 suppressKeyPressRepeat = true; 5658 5659 // search timeout should be triggered before the input value is changed 5660 this._searchTimeout( event ); 5661 break; 5662 } 5663 }, 5664 keypress: function( event ) { 5665 if ( suppressKeyPress ) { 5666 suppressKeyPress = false; 5667 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 5668 event.preventDefault(); 5669 } 5670 return; 5671 } 5672 if ( suppressKeyPressRepeat ) { 5673 return; 5674 } 5675 5676 // Replicate some key handlers to allow them to repeat in Firefox and Opera 5677 var keyCode = $.ui.keyCode; 5678 switch ( event.keyCode ) { 5679 case keyCode.PAGE_UP: 5680 this._move( "previousPage", event ); 5681 break; 5682 case keyCode.PAGE_DOWN: 5683 this._move( "nextPage", event ); 5684 break; 5685 case keyCode.UP: 5686 this._keyEvent( "previous", event ); 5687 break; 5688 case keyCode.DOWN: 5689 this._keyEvent( "next", event ); 5690 break; 5691 } 5692 }, 5693 input: function( event ) { 5694 if ( suppressInput ) { 5695 suppressInput = false; 5696 event.preventDefault(); 5697 return; 5698 } 5699 this._searchTimeout( event ); 5700 }, 5701 focus: function() { 5702 this.selectedItem = null; 5703 this.previous = this._value(); 5704 }, 5705 blur: function( event ) { 5706 clearTimeout( this.searching ); 5707 this.close( event ); 5708 this._change( event ); 5709 } 5710 } ); 5711 5712 this._initSource(); 5713 this.menu = $( "<ul>" ) 5714 .appendTo( this._appendTo() ) 5715 .menu( { 5716 5717 // disable ARIA support, the live region takes care of that 5718 role: null 5719 } ) 5720 .hide() 5721 .menu( "instance" ); 5722 5723 this._addClass( this.menu.element, "ui-autocomplete", "ui-front" ); 5724 this._on( this.menu.element, { 5725 mousedown: function( event ) { 5726 5727 // Prevent moving focus out of the text field 5728 event.preventDefault(); 5729 }, 5730 menufocus: function( event, ui ) { 5731 var label, item; 5732 5733 // Support: Firefox 5734 // Prevent accidental activation of menu items in Firefox (#7024 #9118) 5735 if ( this.isNewMenu ) { 5736 this.isNewMenu = false; 5737 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { 5738 this.menu.blur(); 5739 5740 this.document.one( "mousemove", function() { 5741 $( event.target ).trigger( event.originalEvent ); 5742 } ); 5743 5744 return; 5745 } 5746 } 5747 5748 item = ui.item.data( "ui-autocomplete-item" ); 5749 if ( false !== this._trigger( "focus", event, { item: item } ) ) { 5750 5751 // use value to match what will end up in the input, if it was a key event 5752 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { 5753 this._value( item.value ); 5754 } 5755 } 5756 5757 // Announce the value in the liveRegion 5758 label = ui.item.attr( "aria-label" ) || item.value; 5759 if ( label && String.prototype.trim.call( label ).length ) { 5760 clearTimeout( this.liveRegionTimer ); 5761 this.liveRegionTimer = this._delay( function() { 5762 this.liveRegion.html( $( "<div>" ).text( label ) ); 5763 }, 100 ); 5764 } 5765 }, 5766 menuselect: function( event, ui ) { 5767 var item = ui.item.data( "ui-autocomplete-item" ), 5768 previous = this.previous; 5769 5770 // Only trigger when focus was lost (click on menu) 5771 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { 5772 this.element.trigger( "focus" ); 5773 this.previous = previous; 5774 } 5775 5776 if ( false !== this._trigger( "select", event, { item: item } ) ) { 5777 this._value( item.value ); 5778 } 5779 5780 // reset the term after the select event 5781 // this allows custom select handling to work properly 5782 this.term = this._value(); 5783 5784 this.close( event ); 5785 this.selectedItem = item; 5786 } 5787 } ); 5788 5789 this.liveRegion = $( "<div>", { 5790 role: "status", 5791 "aria-live": "assertive", 5792 "aria-relevant": "additions" 5793 } ) 5794 .appendTo( this.document[ 0 ].body ); 5795 5796 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 5797 5798 // Turning off autocomplete prevents the browser from remembering the 5799 // value when navigating through history, so we re-enable autocomplete 5800 // if the page is unloaded before the widget is destroyed. #7790 5801 this._on( this.window, { 5802 beforeunload: function() { 5803 this.element.removeAttr( "autocomplete" ); 5804 } 5805 } ); 5806 }, 5807 5808 _destroy: function() { 5809 clearTimeout( this.searching ); 5810 this.element.removeAttr( "autocomplete" ); 5811 this.menu.element.remove(); 5812 this.liveRegion.remove(); 5813 }, 5814 5815 _setOption: function( key, value ) { 5816 this._super( key, value ); 5817 if ( key === "source" ) { 5818 this._initSource(); 5819 } 5820 if ( key === "appendTo" ) { 5821 this.menu.element.appendTo( this._appendTo() ); 5822 } 5823 if ( key === "disabled" && value && this.xhr ) { 5824 this.xhr.abort(); 5825 } 5826 }, 5827 5828 _isEventTargetInWidget: function( event ) { 5829 var menuElement = this.menu.element[ 0 ]; 5830 5831 return event.target === this.element[ 0 ] || 5832 event.target === menuElement || 5833 $.contains( menuElement, event.target ); 5834 }, 5835 5836 _closeOnClickOutside: function( event ) { 5837 if ( !this._isEventTargetInWidget( event ) ) { 5838 this.close(); 5839 } 5840 }, 5841 5842 _appendTo: function() { 5843 var element = this.options.appendTo; 5844 5845 if ( element ) { 5846 element = element.jquery || element.nodeType ? 5847 $( element ) : 5848 this.document.find( element ).eq( 0 ); 5849 } 5850 5851 if ( !element || !element[ 0 ] ) { 5852 element = this.element.closest( ".ui-front, dialog" ); 5853 } 5854 5855 if ( !element.length ) { 5856 element = this.document[ 0 ].body; 5857 } 5858 5859 return element; 5860 }, 5861 5862 _initSource: function() { 5863 var array, url, 5864 that = this; 5865 if ( Array.isArray( this.options.source ) ) { 5866 array = this.options.source; 5867 this.source = function( request, response ) { 5868 response( $.ui.autocomplete.filter( array, request.term ) ); 5869 }; 5870 } else if ( typeof this.options.source === "string" ) { 5871 url = this.options.source; 5872 this.source = function( request, response ) { 5873 if ( that.xhr ) { 5874 that.xhr.abort(); 5875 } 5876 that.xhr = $.ajax( { 5877 url: url, 5878 data: request, 5879 dataType: "json", 5880 success: function( data ) { 5881 response( data ); 5882 }, 5883 error: function() { 5884 response( [] ); 5885 } 5886 } ); 5887 }; 5888 } else { 5889 this.source = this.options.source; 5890 } 5891 }, 5892 5893 _searchTimeout: function( event ) { 5894 clearTimeout( this.searching ); 5895 this.searching = this._delay( function() { 5896 5897 // Search if the value has changed, or if the user retypes the same value (see #7434) 5898 var equalValues = this.term === this._value(), 5899 menuVisible = this.menu.element.is( ":visible" ), 5900 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; 5901 5902 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { 5903 this.selectedItem = null; 5904 this.search( null, event ); 5905 } 5906 }, this.options.delay ); 5907 }, 5908 5909 search: function( value, event ) { 5910 value = value != null ? value : this._value(); 5911 5912 // Always save the actual value, not the one passed as an argument 5913 this.term = this._value(); 5914 5915 if ( value.length < this.options.minLength ) { 5916 return this.close( event ); 5917 } 5918 5919 if ( this._trigger( "search", event ) === false ) { 5920 return; 5921 } 5922 5923 return this._search( value ); 5924 }, 5925 5926 _search: function( value ) { 5927 this.pending++; 5928 this._addClass( "ui-autocomplete-loading" ); 5929 this.cancelSearch = false; 5930 5931 this.source( { term: value }, this._response() ); 5932 }, 5933 5934 _response: function() { 5935 var index = ++this.requestIndex; 5936 5937 return function( content ) { 5938 if ( index === this.requestIndex ) { 5939 this.__response( content ); 5940 } 5941 5942 this.pending--; 5943 if ( !this.pending ) { 5944 this._removeClass( "ui-autocomplete-loading" ); 5945 } 5946 }.bind( this ); 5947 }, 5948 5949 __response: function( content ) { 5950 if ( content ) { 5951 content = this._normalize( content ); 5952 } 5953 this._trigger( "response", null, { content: content } ); 5954 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { 5955 this._suggest( content ); 5956 this._trigger( "open" ); 5957 } else { 5958 5959 // use ._close() instead of .close() so we don't cancel future searches 5960 this._close(); 5961 } 5962 }, 5963 5964 close: function( event ) { 5965 this.cancelSearch = true; 5966 this._close( event ); 5967 }, 5968 5969 _close: function( event ) { 5970 5971 // Remove the handler that closes the menu on outside clicks 5972 this._off( this.document, "mousedown" ); 5973 5974 if ( this.menu.element.is( ":visible" ) ) { 5975 this.menu.element.hide(); 5976 this.menu.blur(); 5977 this.isNewMenu = true; 5978 this._trigger( "close", event ); 5979 } 5980 }, 5981 5982 _change: function( event ) { 5983 if ( this.previous !== this._value() ) { 5984 this._trigger( "change", event, { item: this.selectedItem } ); 5985 } 5986 }, 5987 5988 _normalize: function( items ) { 5989 5990 // assume all items have the right format when the first item is complete 5991 if ( items.length && items[ 0 ].label && items[ 0 ].value ) { 5992 return items; 5993 } 5994 return $.map( items, function( item ) { 5995 if ( typeof item === "string" ) { 5996 return { 5997 label: item, 5998 value: item 5999 }; 6000 } 6001 return $.extend( {}, item, { 6002 label: item.label || item.value, 6003 value: item.value || item.label 6004 } ); 6005 } ); 6006 }, 6007 6008 _suggest: function( items ) { 6009 var ul = this.menu.element.empty(); 6010 this._renderMenu( ul, items ); 6011 this.isNewMenu = true; 6012 this.menu.refresh(); 6013 6014 // Size and position menu 6015 ul.show(); 6016 this._resizeMenu(); 6017 ul.position( $.extend( { 6018 of: this.element 6019 }, this.options.position ) ); 6020 6021 if ( this.options.autoFocus ) { 6022 this.menu.next(); 6023 } 6024 6025 // Listen for interactions outside of the widget (#6642) 6026 this._on( this.document, { 6027 mousedown: "_closeOnClickOutside" 6028 } ); 6029 }, 6030 6031 _resizeMenu: function() { 6032 var ul = this.menu.element; 6033 ul.outerWidth( Math.max( 6034 6035 // Firefox wraps long text (possibly a rounding bug) 6036 // so we add 1px to avoid the wrapping (#7513) 6037 ul.width( "" ).outerWidth() + 1, 6038 this.element.outerWidth() 6039 ) ); 6040 }, 6041 6042 _renderMenu: function( ul, items ) { 6043 var that = this; 6044 $.each( items, function( index, item ) { 6045 that._renderItemData( ul, item ); 6046 } ); 6047 }, 6048 6049 _renderItemData: function( ul, item ) { 6050 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 6051 }, 6052 6053 _renderItem: function( ul, item ) { 6054 return $( "<li>" ) 6055 .append( $( "<div>" ).text( item.label ) ) 6056 .appendTo( ul ); 6057 }, 6058 6059 _move: function( direction, event ) { 6060 if ( !this.menu.element.is( ":visible" ) ) { 6061 this.search( null, event ); 6062 return; 6063 } 6064 if ( this.menu.isFirstItem() && /^previous/.test( direction ) || 6065 this.menu.isLastItem() && /^next/.test( direction ) ) { 6066 6067 if ( !this.isMultiLine ) { 6068 this._value( this.term ); 6069 } 6070 6071 this.menu.blur(); 6072 return; 6073 } 6074 this.menu[ direction ]( event ); 6075 }, 6076 6077 widget: function() { 6078 return this.menu.element; 6079 }, 6080 6081 _value: function() { 6082 return this.valueMethod.apply( this.element, arguments ); 6083 }, 6084 6085 _keyEvent: function( keyEvent, event ) { 6086 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 6087 this._move( keyEvent, event ); 6088 6089 // Prevents moving cursor to beginning/end of the text field in some browsers 6090 event.preventDefault(); 6091 } 6092 } 6093 } ); 6094 6095 $.extend( $.ui.autocomplete, { 6096 escapeRegex: function( value ) { 6097 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 6098 }, 6099 filter: function( array, term ) { 6100 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 6101 return $.grep( array, function( value ) { 6102 return matcher.test( value.label || value.value || value ); 6103 } ); 6104 } 6105 } ); 6106 6107// Live region extension, adding a `messages` option 6108// NOTE: This is an experimental API. We are still investigating 6109// a full solution for string manipulation and internationalization. 6110 $.widget( "ui.autocomplete", $.ui.autocomplete, { 6111 options: { 6112 messages: { 6113 noResults: "No search results.", 6114 results: function( amount ) { 6115 return amount + ( amount > 1 ? " results are" : " result is" ) + 6116 " available, use up and down arrow keys to navigate."; 6117 } 6118 } 6119 }, 6120 6121 __response: function( content ) { 6122 var message; 6123 this._superApply( arguments ); 6124 if ( this.options.disabled || this.cancelSearch ) { 6125 return; 6126 } 6127 if ( content && content.length ) { 6128 message = this.options.messages.results( content.length ); 6129 } else { 6130 message = this.options.messages.noResults; 6131 } 6132 clearTimeout( this.liveRegionTimer ); 6133 this.liveRegionTimer = this._delay( function() { 6134 this.liveRegion.html( $( "<div>" ).text( message ) ); 6135 }, 100 ); 6136 } 6137 } ); 6138 6139 var widgetsAutocomplete = $.ui.autocomplete; 6140 6141 6142 /*! 6143 * jQuery UI Controlgroup 1.14.1 6144 * https://jqueryui.com 6145 * 6146 * Copyright OpenJS Foundation and other contributors 6147 * Released under the MIT license. 6148 * https://jquery.org/license 6149 */ 6150 6151//>>label: Controlgroup 6152//>>group: Widgets 6153//>>description: Visually groups form control widgets 6154//>>docs: https://api.jqueryui.com/controlgroup/ 6155//>>demos: https://jqueryui.com/controlgroup/ 6156//>>css.structure: ../../themes/base/core.css 6157//>>css.structure: ../../themes/base/controlgroup.css 6158//>>css.theme: ../../themes/base/theme.css 6159 6160 6161 var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g; 6162 6163 var widgetsControlgroup = $.widget( "ui.controlgroup", { 6164 version: "1.14.1", 6165 defaultElement: "<div>", 6166 options: { 6167 direction: "horizontal", 6168 disabled: null, 6169 onlyVisible: true, 6170 items: { 6171 "button": "input[type=button], input[type=submit], input[type=reset], button, a", 6172 "controlgroupLabel": ".ui-controlgroup-label", 6173 "checkboxradio": "input[type='checkbox'], input[type='radio']", 6174 "selectmenu": "select", 6175 "spinner": ".ui-spinner-input" 6176 } 6177 }, 6178 6179 _create: function() { 6180 this._enhance(); 6181 }, 6182 6183 // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation 6184 _enhance: function() { 6185 this.element.attr( "role", "toolbar" ); 6186 this.refresh(); 6187 }, 6188 6189 _destroy: function() { 6190 this._callChildMethod( "destroy" ); 6191 this.childWidgets.removeData( "ui-controlgroup-data" ); 6192 this.element.removeAttr( "role" ); 6193 if ( this.options.items.controlgroupLabel ) { 6194 this.element 6195 .find( this.options.items.controlgroupLabel ) 6196 .find( ".ui-controlgroup-label-contents" ) 6197 .contents().unwrap(); 6198 } 6199 }, 6200 6201 _initWidgets: function() { 6202 var that = this, 6203 childWidgets = []; 6204 6205 // First we iterate over each of the items options 6206 $.each( this.options.items, function( widget, selector ) { 6207 var labels; 6208 var options = {}; 6209 6210 // Make sure the widget has a selector set 6211 if ( !selector ) { 6212 return; 6213 } 6214 6215 if ( widget === "controlgroupLabel" ) { 6216 labels = that.element.find( selector ); 6217 labels.each( function() { 6218 var element = $( this ); 6219 6220 if ( element.children( ".ui-controlgroup-label-contents" ).length ) { 6221 return; 6222 } 6223 element.contents() 6224 .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" ); 6225 } ); 6226 that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" ); 6227 childWidgets = childWidgets.concat( labels.get() ); 6228 return; 6229 } 6230 6231 // Make sure the widget actually exists 6232 if ( !$.fn[ widget ] ) { 6233 return; 6234 } 6235 6236 // We assume everything is in the middle to start because we can't determine 6237 // first / last elements until all enhancments are done. 6238 if ( that[ "_" + widget + "Options" ] ) { 6239 options = that[ "_" + widget + "Options" ]( "middle" ); 6240 } else { 6241 options = { classes: {} }; 6242 } 6243 6244 // Find instances of this widget inside controlgroup and init them 6245 that.element 6246 .find( selector ) 6247 .each( function() { 6248 var element = $( this ); 6249 var instance = element[ widget ]( "instance" ); 6250 6251 // We need to clone the default options for this type of widget to avoid 6252 // polluting the variable options which has a wider scope than a single widget. 6253 var instanceOptions = $.widget.extend( {}, options ); 6254 6255 // If the button is the child of a spinner ignore it 6256 // TODO: Find a more generic solution 6257 if ( widget === "button" && element.parent( ".ui-spinner" ).length ) { 6258 return; 6259 } 6260 6261 // Create the widget if it doesn't exist 6262 if ( !instance ) { 6263 instance = element[ widget ]()[ widget ]( "instance" ); 6264 } 6265 if ( instance ) { 6266 instanceOptions.classes = 6267 that._resolveClassesValues( instanceOptions.classes, instance ); 6268 } 6269 element[ widget ]( instanceOptions ); 6270 6271 // Store an instance of the controlgroup to be able to reference 6272 // from the outermost element for changing options and refresh 6273 var widgetElement = element[ widget ]( "widget" ); 6274 $.data( widgetElement[ 0 ], "ui-controlgroup-data", 6275 instance ? instance : element[ widget ]( "instance" ) ); 6276 6277 childWidgets.push( widgetElement[ 0 ] ); 6278 } ); 6279 } ); 6280 6281 this.childWidgets = $( $.uniqueSort( childWidgets ) ); 6282 this._addClass( this.childWidgets, "ui-controlgroup-item" ); 6283 }, 6284 6285 _callChildMethod: function( method ) { 6286 this.childWidgets.each( function() { 6287 var element = $( this ), 6288 data = element.data( "ui-controlgroup-data" ); 6289 if ( data && data[ method ] ) { 6290 data[ method ](); 6291 } 6292 } ); 6293 }, 6294 6295 _updateCornerClass: function( element, position ) { 6296 var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all"; 6297 var add = this._buildSimpleOptions( position, "label" ).classes.label; 6298 6299 this._removeClass( element, null, remove ); 6300 this._addClass( element, null, add ); 6301 }, 6302 6303 _buildSimpleOptions: function( position, key ) { 6304 var direction = this.options.direction === "vertical"; 6305 var result = { 6306 classes: {} 6307 }; 6308 result.classes[ key ] = { 6309 "middle": "", 6310 "first": "ui-corner-" + ( direction ? "top" : "left" ), 6311 "last": "ui-corner-" + ( direction ? "bottom" : "right" ), 6312 "only": "ui-corner-all" 6313 }[ position ]; 6314 6315 return result; 6316 }, 6317 6318 _spinnerOptions: function( position ) { 6319 var options = this._buildSimpleOptions( position, "ui-spinner" ); 6320 6321 options.classes[ "ui-spinner-up" ] = ""; 6322 options.classes[ "ui-spinner-down" ] = ""; 6323 6324 return options; 6325 }, 6326 6327 _buttonOptions: function( position ) { 6328 return this._buildSimpleOptions( position, "ui-button" ); 6329 }, 6330 6331 _checkboxradioOptions: function( position ) { 6332 return this._buildSimpleOptions( position, "ui-checkboxradio-label" ); 6333 }, 6334 6335 _selectmenuOptions: function( position ) { 6336 var direction = this.options.direction === "vertical"; 6337 return { 6338 width: direction ? "auto" : false, 6339 classes: { 6340 middle: { 6341 "ui-selectmenu-button-open": "", 6342 "ui-selectmenu-button-closed": "" 6343 }, 6344 first: { 6345 "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ), 6346 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" ) 6347 }, 6348 last: { 6349 "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr", 6350 "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" ) 6351 }, 6352 only: { 6353 "ui-selectmenu-button-open": "ui-corner-top", 6354 "ui-selectmenu-button-closed": "ui-corner-all" 6355 } 6356 6357 }[ position ] 6358 }; 6359 }, 6360 6361 _resolveClassesValues: function( classes, instance ) { 6362 var result = {}; 6363 $.each( classes, function( key ) { 6364 var current = instance.options.classes[ key ] || ""; 6365 current = String.prototype.trim.call( current.replace( controlgroupCornerRegex, "" ) ); 6366 result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " ); 6367 } ); 6368 return result; 6369 }, 6370 6371 _setOption: function( key, value ) { 6372 if ( key === "direction" ) { 6373 this._removeClass( "ui-controlgroup-" + this.options.direction ); 6374 } 6375 6376 this._super( key, value ); 6377 if ( key === "disabled" ) { 6378 this._callChildMethod( value ? "disable" : "enable" ); 6379 return; 6380 } 6381 6382 this.refresh(); 6383 }, 6384 6385 refresh: function() { 6386 var children, 6387 that = this; 6388 6389 this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); 6390 6391 if ( this.options.direction === "horizontal" ) { 6392 this._addClass( null, "ui-helper-clearfix" ); 6393 } 6394 this._initWidgets(); 6395 6396 children = this.childWidgets; 6397 6398 // We filter here because we need to track all childWidgets not just the visible ones 6399 if ( this.options.onlyVisible ) { 6400 children = children.filter( ":visible" ); 6401 } 6402 6403 if ( children.length ) { 6404 6405 // We do this last because we need to make sure all enhancment is done 6406 // before determining first and last 6407 $.each( [ "first", "last" ], function( index, value ) { 6408 var instance = children[ value ]().data( "ui-controlgroup-data" ); 6409 6410 if ( instance && that[ "_" + instance.widgetName + "Options" ] ) { 6411 var options = that[ "_" + instance.widgetName + "Options" ]( 6412 children.length === 1 ? "only" : value 6413 ); 6414 options.classes = that._resolveClassesValues( options.classes, instance ); 6415 instance.element[ instance.widgetName ]( options ); 6416 } else { 6417 that._updateCornerClass( children[ value ](), value ); 6418 } 6419 } ); 6420 6421 // Finally call the refresh method on each of the child widgets. 6422 this._callChildMethod( "refresh" ); 6423 } 6424 } 6425 } ); 6426 6427 /*! 6428 * jQuery UI Checkboxradio 1.14.1 6429 * https://jqueryui.com 6430 * 6431 * Copyright OpenJS Foundation and other contributors 6432 * Released under the MIT license. 6433 * https://jquery.org/license 6434 */ 6435 6436//>>label: Checkboxradio 6437//>>group: Widgets 6438//>>description: Enhances a form with multiple themeable checkboxes or radio buttons. 6439//>>docs: https://api.jqueryui.com/checkboxradio/ 6440//>>demos: https://jqueryui.com/checkboxradio/ 6441//>>css.structure: ../../themes/base/core.css 6442//>>css.structure: ../../themes/base/button.css 6443//>>css.structure: ../../themes/base/checkboxradio.css 6444//>>css.theme: ../../themes/base/theme.css 6445 6446 6447 $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, { 6448 version: "1.14.1", 6449 options: { 6450 disabled: null, 6451 label: null, 6452 icon: true, 6453 classes: { 6454 "ui-checkboxradio-label": "ui-corner-all", 6455 "ui-checkboxradio-icon": "ui-corner-all" 6456 } 6457 }, 6458 6459 _getCreateOptions: function() { 6460 var disabled, labels, labelContents; 6461 var options = this._super() || {}; 6462 6463 // We read the type here, because it makes more sense to throw a element type error first, 6464 // rather then the error for lack of a label. Often if its the wrong type, it 6465 // won't have a label (e.g. calling on a div, btn, etc) 6466 this._readType(); 6467 6468 labels = this.element.labels(); 6469 6470 // If there are multiple labels, use the last one 6471 this.label = $( labels[ labels.length - 1 ] ); 6472 if ( !this.label.length ) { 6473 $.error( "No label found for checkboxradio widget" ); 6474 } 6475 6476 this.originalLabel = ""; 6477 6478 // We need to get the label text but this may also need to make sure it does not contain the 6479 // input itself. 6480 // The label contents could be text, html, or a mix. We wrap all elements 6481 // and read the wrapper's `innerHTML` to get a string representation of 6482 // the label, without the input as part of it. 6483 labelContents = this.label.contents().not( this.element[ 0 ] ); 6484 6485 if ( labelContents.length ) { 6486 this.originalLabel += labelContents 6487 .clone() 6488 .wrapAll( "<div></div>" ) 6489 .parent() 6490 .html(); 6491 } 6492 6493 // Set the label option if we found label text 6494 if ( this.originalLabel ) { 6495 options.label = this.originalLabel; 6496 } 6497 6498 disabled = this.element[ 0 ].disabled; 6499 if ( disabled != null ) { 6500 options.disabled = disabled; 6501 } 6502 return options; 6503 }, 6504 6505 _create: function() { 6506 var checked = this.element[ 0 ].checked; 6507 6508 this._bindFormResetHandler(); 6509 6510 if ( this.options.disabled == null ) { 6511 this.options.disabled = this.element[ 0 ].disabled; 6512 } 6513 6514 this._setOption( "disabled", this.options.disabled ); 6515 this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); 6516 this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); 6517 6518 if ( this.type === "radio" ) { 6519 this._addClass( this.label, "ui-checkboxradio-radio-label" ); 6520 } 6521 6522 if ( this.options.label && this.options.label !== this.originalLabel ) { 6523 this._updateLabel(); 6524 } else if ( this.originalLabel ) { 6525 this.options.label = this.originalLabel; 6526 } 6527 6528 this._enhance(); 6529 6530 if ( checked ) { 6531 this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); 6532 } 6533 6534 this._on( { 6535 change: "_toggleClasses", 6536 focus: function() { 6537 this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); 6538 }, 6539 blur: function() { 6540 this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); 6541 } 6542 } ); 6543 }, 6544 6545 _readType: function() { 6546 var nodeName = this.element[ 0 ].nodeName.toLowerCase(); 6547 this.type = this.element[ 0 ].type; 6548 if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { 6549 $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + 6550 " and element.type=" + this.type ); 6551 } 6552 }, 6553 6554 // Support jQuery Mobile enhanced option 6555 _enhance: function() { 6556 this._updateIcon( this.element[ 0 ].checked ); 6557 }, 6558 6559 widget: function() { 6560 return this.label; 6561 }, 6562 6563 _getRadioGroup: function() { 6564 var group; 6565 var name = this.element[ 0 ].name; 6566 var nameSelector = "input[name='" + CSS.escape( name ) + "']"; 6567 6568 if ( !name ) { 6569 return $( [] ); 6570 } 6571 6572 if ( this.form.length ) { 6573 group = $( this.form[ 0 ].elements ).filter( nameSelector ); 6574 } else { 6575 6576 // Not inside a form, check all inputs that also are not inside a form 6577 group = $( nameSelector ).filter( function() { 6578 return $( $( this ).prop( "form" ) ).length === 0; 6579 } ); 6580 } 6581 6582 return group.not( this.element ); 6583 }, 6584 6585 _toggleClasses: function() { 6586 var checked = this.element[ 0 ].checked; 6587 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 6588 6589 if ( this.options.icon && this.type === "checkbox" ) { 6590 this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked ) 6591 ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); 6592 } 6593 6594 if ( this.type === "radio" ) { 6595 this._getRadioGroup() 6596 .each( function() { 6597 var instance = $( this ).checkboxradio( "instance" ); 6598 6599 if ( instance ) { 6600 instance._removeClass( instance.label, 6601 "ui-checkboxradio-checked", "ui-state-active" ); 6602 } 6603 } ); 6604 } 6605 }, 6606 6607 _destroy: function() { 6608 this._unbindFormResetHandler(); 6609 6610 if ( this.icon ) { 6611 this.icon.remove(); 6612 this.iconSpace.remove(); 6613 } 6614 }, 6615 6616 _setOption: function( key, value ) { 6617 6618 // We don't allow the value to be set to nothing 6619 if ( key === "label" && !value ) { 6620 return; 6621 } 6622 6623 this._super( key, value ); 6624 6625 if ( key === "disabled" ) { 6626 this._toggleClass( this.label, null, "ui-state-disabled", value ); 6627 this.element[ 0 ].disabled = value; 6628 6629 // Don't refresh when setting disabled 6630 return; 6631 } 6632 this.refresh(); 6633 }, 6634 6635 _updateIcon: function( checked ) { 6636 var toAdd = "ui-icon ui-icon-background "; 6637 6638 if ( this.options.icon ) { 6639 if ( !this.icon ) { 6640 this.icon = $( "<span>" ); 6641 this.iconSpace = $( "<span> </span>" ); 6642 this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); 6643 } 6644 6645 if ( this.type === "checkbox" ) { 6646 toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank"; 6647 this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); 6648 } else { 6649 toAdd += "ui-icon-blank"; 6650 } 6651 this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); 6652 if ( !checked ) { 6653 this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" ); 6654 } 6655 this.icon.prependTo( this.label ).after( this.iconSpace ); 6656 } else if ( this.icon !== undefined ) { 6657 this.icon.remove(); 6658 this.iconSpace.remove(); 6659 delete this.icon; 6660 } 6661 }, 6662 6663 _updateLabel: function() { 6664 6665 // Remove the contents of the label ( minus the icon, icon space, and input ) 6666 var contents = this.label.contents().not( this.element[ 0 ] ); 6667 if ( this.icon ) { 6668 contents = contents.not( this.icon[ 0 ] ); 6669 } 6670 if ( this.iconSpace ) { 6671 contents = contents.not( this.iconSpace[ 0 ] ); 6672 } 6673 contents.remove(); 6674 6675 this.label.append( this.options.label ); 6676 }, 6677 6678 refresh: function() { 6679 var checked = this.element[ 0 ].checked, 6680 isDisabled = this.element[ 0 ].disabled; 6681 6682 this._updateIcon( checked ); 6683 this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); 6684 if ( this.options.label !== null ) { 6685 this._updateLabel(); 6686 } 6687 6688 if ( isDisabled !== this.options.disabled ) { 6689 this._setOptions( { "disabled": isDisabled } ); 6690 } 6691 } 6692 6693 } ] ); 6694 6695 var widgetsCheckboxradio = $.ui.checkboxradio; 6696 6697 6698 /*! 6699 * jQuery UI Button 1.14.1 6700 * https://jqueryui.com 6701 * 6702 * Copyright OpenJS Foundation and other contributors 6703 * Released under the MIT license. 6704 * https://jquery.org/license 6705 */ 6706 6707//>>label: Button 6708//>>group: Widgets 6709//>>description: Enhances a form with themeable buttons. 6710//>>docs: https://api.jqueryui.com/button/ 6711//>>demos: https://jqueryui.com/button/ 6712//>>css.structure: ../../themes/base/core.css 6713//>>css.structure: ../../themes/base/button.css 6714//>>css.theme: ../../themes/base/theme.css 6715 6716 6717 $.widget( "ui.button", { 6718 version: "1.14.1", 6719 defaultElement: "<button>", 6720 options: { 6721 classes: { 6722 "ui-button": "ui-corner-all" 6723 }, 6724 disabled: null, 6725 icon: null, 6726 iconPosition: "beginning", 6727 label: null, 6728 showLabel: true 6729 }, 6730 6731 _getCreateOptions: function() { 6732 var disabled, 6733 6734 // This is to support cases like in jQuery Mobile where the base widget does have 6735 // an implementation of _getCreateOptions 6736 options = this._super() || {}; 6737 6738 this.isInput = this.element.is( "input" ); 6739 6740 disabled = this.element[ 0 ].disabled; 6741 if ( disabled != null ) { 6742 options.disabled = disabled; 6743 } 6744 6745 this.originalLabel = this.isInput ? this.element.val() : this.element.html(); 6746 if ( this.originalLabel ) { 6747 options.label = this.originalLabel; 6748 } 6749 6750 return options; 6751 }, 6752 6753 _create: function() { 6754 if ( !this.option.showLabel & !this.options.icon ) { 6755 this.options.showLabel = true; 6756 } 6757 6758 // We have to check the option again here even though we did in _getCreateOptions, 6759 // because null may have been passed on init which would override what was set in 6760 // _getCreateOptions 6761 if ( this.options.disabled == null ) { 6762 this.options.disabled = this.element[ 0 ].disabled || false; 6763 } 6764 6765 this.hasTitle = !!this.element.attr( "title" ); 6766 6767 // Check to see if the label needs to be set or if its already correct 6768 if ( this.options.label && this.options.label !== this.originalLabel ) { 6769 if ( this.isInput ) { 6770 this.element.val( this.options.label ); 6771 } else { 6772 this.element.html( this.options.label ); 6773 } 6774 } 6775 this._addClass( "ui-button", "ui-widget" ); 6776 this._setOption( "disabled", this.options.disabled ); 6777 this._enhance(); 6778 6779 if ( this.element.is( "a" ) ) { 6780 this._on( { 6781 "keyup": function( event ) { 6782 if ( event.keyCode === $.ui.keyCode.SPACE ) { 6783 event.preventDefault(); 6784 6785 // If a native click is available use it, so we 6786 // actually cause navigation. Otherwise, just trigger 6787 // a click event. 6788 if ( this.element[ 0 ].click ) { 6789 this.element[ 0 ].click(); 6790 } else { 6791 this.element.trigger( "click" ); 6792 } 6793 } 6794 } 6795 } ); 6796 } 6797 }, 6798 6799 _enhance: function() { 6800 if ( !this.element.is( "button" ) ) { 6801 this.element.attr( "role", "button" ); 6802 } 6803 6804 if ( this.options.icon ) { 6805 this._updateIcon( "icon", this.options.icon ); 6806 this._updateTooltip(); 6807 } 6808 }, 6809 6810 _updateTooltip: function() { 6811 this.title = this.element.attr( "title" ); 6812 6813 if ( !this.options.showLabel && !this.title ) { 6814 this.element.attr( "title", this.options.label ); 6815 } 6816 }, 6817 6818 _updateIcon: function( option, value ) { 6819 var icon = option !== "iconPosition", 6820 position = icon ? this.options.iconPosition : value, 6821 displayBlock = position === "top" || position === "bottom"; 6822 6823 // Create icon 6824 if ( !this.icon ) { 6825 this.icon = $( "<span>" ); 6826 6827 this._addClass( this.icon, "ui-button-icon", "ui-icon" ); 6828 6829 if ( !this.options.showLabel ) { 6830 this._addClass( "ui-button-icon-only" ); 6831 } 6832 } else if ( icon ) { 6833 6834 // If we are updating the icon remove the old icon class 6835 this._removeClass( this.icon, null, this.options.icon ); 6836 } 6837 6838 // If we are updating the icon add the new icon class 6839 if ( icon ) { 6840 this._addClass( this.icon, null, value ); 6841 } 6842 6843 this._attachIcon( position ); 6844 6845 // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove 6846 // the iconSpace if there is one. 6847 if ( displayBlock ) { 6848 this._addClass( this.icon, null, "ui-widget-icon-block" ); 6849 if ( this.iconSpace ) { 6850 this.iconSpace.remove(); 6851 } 6852 } else { 6853 6854 // Position is beginning or end so remove the ui-widget-icon-block class and add the 6855 // space if it does not exist 6856 if ( !this.iconSpace ) { 6857 this.iconSpace = $( "<span> </span>" ); 6858 this._addClass( this.iconSpace, "ui-button-icon-space" ); 6859 } 6860 this._removeClass( this.icon, null, "ui-wiget-icon-block" ); 6861 this._attachIconSpace( position ); 6862 } 6863 }, 6864 6865 _destroy: function() { 6866 this.element.removeAttr( "role" ); 6867 6868 if ( this.icon ) { 6869 this.icon.remove(); 6870 } 6871 if ( this.iconSpace ) { 6872 this.iconSpace.remove(); 6873 } 6874 if ( !this.hasTitle ) { 6875 this.element.removeAttr( "title" ); 6876 } 6877 }, 6878 6879 _attachIconSpace: function( iconPosition ) { 6880 this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace ); 6881 }, 6882 6883 _attachIcon: function( iconPosition ) { 6884 this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon ); 6885 }, 6886 6887 _setOptions: function( options ) { 6888 var newShowLabel = options.showLabel === undefined ? 6889 this.options.showLabel : 6890 options.showLabel, 6891 newIcon = options.icon === undefined ? this.options.icon : options.icon; 6892 6893 if ( !newShowLabel && !newIcon ) { 6894 options.showLabel = true; 6895 } 6896 this._super( options ); 6897 }, 6898 6899 _setOption: function( key, value ) { 6900 if ( key === "icon" ) { 6901 if ( value ) { 6902 this._updateIcon( key, value ); 6903 } else if ( this.icon ) { 6904 this.icon.remove(); 6905 if ( this.iconSpace ) { 6906 this.iconSpace.remove(); 6907 } 6908 } 6909 } 6910 6911 if ( key === "iconPosition" ) { 6912 this._updateIcon( key, value ); 6913 } 6914 6915 // Make sure we can't end up with a button that has neither text nor icon 6916 if ( key === "showLabel" ) { 6917 this._toggleClass( "ui-button-icon-only", null, !value ); 6918 this._updateTooltip(); 6919 } 6920 6921 if ( key === "label" ) { 6922 if ( this.isInput ) { 6923 this.element.val( value ); 6924 } else { 6925 6926 // If there is an icon, append it, else nothing then append the value 6927 // this avoids removal of the icon when setting label text 6928 this.element.html( value ); 6929 if ( this.icon ) { 6930 this._attachIcon( this.options.iconPosition ); 6931 this._attachIconSpace( this.options.iconPosition ); 6932 } 6933 } 6934 } 6935 6936 this._super( key, value ); 6937 6938 if ( key === "disabled" ) { 6939 this._toggleClass( null, "ui-state-disabled", value ); 6940 this.element[ 0 ].disabled = value; 6941 if ( value ) { 6942 this.element.trigger( "blur" ); 6943 } 6944 } 6945 }, 6946 6947 refresh: function() { 6948 6949 // Make sure to only check disabled if its an element that supports this otherwise 6950 // check for the disabled class to determine state 6951 var isDisabled = this.element.is( "input, button" ) ? 6952 this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" ); 6953 6954 if ( isDisabled !== this.options.disabled ) { 6955 this._setOptions( { disabled: isDisabled } ); 6956 } 6957 6958 this._updateTooltip(); 6959 } 6960 } ); 6961 6962// DEPRECATED 6963 if ( $.uiBackCompat === true ) { 6964 6965 // Text and Icons options 6966 $.widget( "ui.button", $.ui.button, { 6967 options: { 6968 text: true, 6969 icons: { 6970 primary: null, 6971 secondary: null 6972 } 6973 }, 6974 6975 _create: function() { 6976 if ( this.options.showLabel && !this.options.text ) { 6977 this.options.showLabel = this.options.text; 6978 } 6979 if ( !this.options.showLabel && this.options.text ) { 6980 this.options.text = this.options.showLabel; 6981 } 6982 if ( !this.options.icon && ( this.options.icons.primary || 6983 this.options.icons.secondary ) ) { 6984 if ( this.options.icons.primary ) { 6985 this.options.icon = this.options.icons.primary; 6986 } else { 6987 this.options.icon = this.options.icons.secondary; 6988 this.options.iconPosition = "end"; 6989 } 6990 } else if ( this.options.icon ) { 6991 this.options.icons.primary = this.options.icon; 6992 } 6993 this._super(); 6994 }, 6995 6996 _setOption: function( key, value ) { 6997 if ( key === "text" ) { 6998 this._super( "showLabel", value ); 6999 return; 7000 } 7001 if ( key === "showLabel" ) { 7002 this.options.text = value; 7003 } 7004 if ( key === "icon" ) { 7005 this.options.icons.primary = value; 7006 } 7007 if ( key === "icons" ) { 7008 if ( value.primary ) { 7009 this._super( "icon", value.primary ); 7010 this._super( "iconPosition", "beginning" ); 7011 } else if ( value.secondary ) { 7012 this._super( "icon", value.secondary ); 7013 this._super( "iconPosition", "end" ); 7014 } 7015 } 7016 this._superApply( arguments ); 7017 } 7018 } ); 7019 7020 $.fn.button = ( function( orig ) { 7021 return function( options ) { 7022 var isMethodCall = typeof options === "string"; 7023 var args = Array.prototype.slice.call( arguments, 1 ); 7024 var returnValue = this; 7025 7026 if ( isMethodCall ) { 7027 7028 // If this is an empty collection, we need to have the instance method 7029 // return undefined instead of the jQuery instance 7030 if ( !this.length && options === "instance" ) { 7031 returnValue = undefined; 7032 } else { 7033 this.each( function() { 7034 var methodValue; 7035 var type = $( this ).attr( "type" ); 7036 var name = type !== "checkbox" && type !== "radio" ? 7037 "button" : 7038 "checkboxradio"; 7039 var instance = $.data( this, "ui-" + name ); 7040 7041 if ( options === "instance" ) { 7042 returnValue = instance; 7043 return false; 7044 } 7045 7046 if ( !instance ) { 7047 return $.error( "cannot call methods on button" + 7048 " prior to initialization; " + 7049 "attempted to call method '" + options + "'" ); 7050 } 7051 7052 if ( typeof instance[ options ] !== "function" || 7053 options.charAt( 0 ) === "_" ) { 7054 return $.error( "no such method '" + options + "' for button" + 7055 " widget instance" ); 7056 } 7057 7058 methodValue = instance[ options ].apply( instance, args ); 7059 7060 if ( methodValue !== instance && methodValue !== undefined ) { 7061 returnValue = methodValue && methodValue.jquery ? 7062 returnValue.pushStack( methodValue.get() ) : 7063 methodValue; 7064 return false; 7065 } 7066 } ); 7067 } 7068 } else { 7069 7070 // Allow multiple hashes to be passed on init 7071 if ( args.length ) { 7072 options = $.widget.extend.apply( null, [ options ].concat( args ) ); 7073 } 7074 7075 this.each( function() { 7076 var type = $( this ).attr( "type" ); 7077 var name = type !== "checkbox" && type !== "radio" ? "button" : "checkboxradio"; 7078 var instance = $.data( this, "ui-" + name ); 7079 7080 if ( instance ) { 7081 instance.option( options || {} ); 7082 if ( instance._init ) { 7083 instance._init(); 7084 } 7085 } else { 7086 if ( name === "button" ) { 7087 orig.call( $( this ), options ); 7088 return; 7089 } 7090 7091 $( this ).checkboxradio( $.extend( { icon: false }, options ) ); 7092 } 7093 } ); 7094 } 7095 7096 return returnValue; 7097 }; 7098 } )( $.fn.button ); 7099 7100 $.fn.buttonset = function() { 7101 if ( !$.ui.controlgroup ) { 7102 $.error( "Controlgroup widget missing" ); 7103 } 7104 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) { 7105 return this.controlgroup.apply( this, 7106 [ arguments[ 0 ], "items.button", arguments[ 2 ] ] ); 7107 } 7108 if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) { 7109 return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] ); 7110 } 7111 if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) { 7112 arguments[ 0 ].items = { 7113 button: arguments[ 0 ].items 7114 }; 7115 } 7116 return this.controlgroup.apply( this, arguments ); 7117 }; 7118 } 7119 7120 var widgetsButton = $.ui.button; 7121 7122 7123 /* eslint-disable max-len, camelcase */ 7124 /*! 7125 * jQuery UI Datepicker 1.14.1 7126 * https://jqueryui.com 7127 * 7128 * Copyright OpenJS Foundation and other contributors 7129 * Released under the MIT license. 7130 * https://jquery.org/license 7131 */ 7132 7133//>>label: Datepicker 7134//>>group: Widgets 7135//>>description: Displays a calendar from an input or inline for selecting dates. 7136//>>docs: https://api.jqueryui.com/datepicker/ 7137//>>demos: https://jqueryui.com/datepicker/ 7138//>>css.structure: ../../themes/base/core.css 7139//>>css.structure: ../../themes/base/datepicker.css 7140//>>css.theme: ../../themes/base/theme.css 7141 7142 7143 $.extend( $.ui, { datepicker: { version: "1.14.1" } } ); 7144 7145 var datepicker_instActive; 7146 7147 function datepicker_getZindex( elem ) { 7148 var position, value; 7149 while ( elem.length && elem[ 0 ] !== document ) { 7150 7151 // Ignore z-index if position is set to a value where z-index is ignored by the browser 7152 // This makes behavior of this function consistent across browsers 7153 // WebKit always returns auto if the element is positioned 7154 position = elem.css( "position" ); 7155 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 7156 7157 // IE returns 0 when zIndex is not specified 7158 // other browsers return a string 7159 // we ignore the case of nested elements with an explicit value of 0 7160 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 7161 value = parseInt( elem.css( "zIndex" ), 10 ); 7162 if ( !isNaN( value ) && value !== 0 ) { 7163 return value; 7164 } 7165 } 7166 elem = elem.parent(); 7167 } 7168 7169 return 0; 7170 } 7171 7172 /* Date picker manager. 7173 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 7174 Settings for (groups of) date pickers are maintained in an instance object, 7175 allowing multiple different settings on the same page. */ 7176 7177 function Datepicker() { 7178 this._curInst = null; // The current instance in use 7179 this._keyEvent = false; // If the last event was a key event 7180 this._disabledInputs = []; // List of date picker inputs that have been disabled 7181 this._datepickerShowing = false; // True if the popup picker is showing , false if not 7182 this._inDialog = false; // True if showing within a "dialog", false if not 7183 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 7184 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 7185 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 7186 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 7187 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 7188 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 7189 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 7190 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 7191 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 7192 this.regional = []; // Available regional settings, indexed by language code 7193 this.regional[ "" ] = { // Default regional settings 7194 closeText: "Done", // Display text for close link 7195 prevText: "Prev", // Display text for previous month link 7196 nextText: "Next", // Display text for next month link 7197 currentText: "Today", // Display text for current month link 7198 monthNames: [ "January", "February", "March", "April", "May", "June", 7199 "July", "August", "September", "October", "November", "December" ], // Names of months for drop-down and formatting 7200 monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting 7201 dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting 7202 dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting 7203 dayNamesMin: [ "Su", "Mo", "Tu", "We", "Th", "Fr", "Sa" ], // Column headings for days starting at Sunday 7204 weekHeader: "Wk", // Column header for week of the year 7205 dateFormat: "mm/dd/yy", // See format options on parseDate 7206 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 7207 isRTL: false, // True if right-to-left language, false if left-to-right 7208 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 7209 yearSuffix: "", // Additional text to append to the year in the month headers, 7210 selectMonthLabel: "Select month", // Invisible label for month selector 7211 selectYearLabel: "Select year" // Invisible label for year selector 7212 }; 7213 this._defaults = { // Global defaults for all the date picker instances 7214 showOn: "focus", // "focus" for popup on focus, 7215 // "button" for trigger button, or "both" for either 7216 showAnim: "fadeIn", // Name of jQuery animation for popup 7217 showOptions: {}, // Options for enhanced animations 7218 defaultDate: null, // Used when field is blank: actual date, 7219 // +/-number for offset from today, null for today 7220 appendText: "", // Display text following the input box, e.g. showing the format 7221 buttonText: "...", // Text for trigger button 7222 buttonImage: "", // URL for trigger button image 7223 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 7224 hideIfNoPrevNext: false, // True to hide next/previous month links 7225 // if not applicable, false to just disable them 7226 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 7227 gotoCurrent: false, // True if today link goes back to current selection instead 7228 changeMonth: false, // True if month can be selected directly, false if only prev/next 7229 changeYear: false, // True if year can be selected directly, false if only prev/next 7230 yearRange: "c-10:c+10", // Range of years to display in drop-down, 7231 // either relative to today's year (-nn:+nn), relative to currently displayed year 7232 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 7233 showOtherMonths: false, // True to show dates in other months, false to leave blank 7234 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 7235 showWeek: false, // True to show week of the year, false to not show it 7236 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 7237 // takes a Date and returns the number of the week for it 7238 shortYearCutoff: "+10", // Short year values < this are in the current century, 7239 // > this are in the previous century, 7240 // string value starting with "+" for current year + value 7241 minDate: null, // The earliest selectable date, or null for no limit 7242 maxDate: null, // The latest selectable date, or null for no limit 7243 duration: "fast", // Duration of display/closure 7244 beforeShowDay: null, // Function that takes a date and returns an array with 7245 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 7246 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 7247 beforeShow: null, // Function that takes an input field and 7248 // returns a set of custom settings for the date picker 7249 onSelect: null, // Define a callback function when a date is selected 7250 onChangeMonthYear: null, // Define a callback function when the month or year is changed 7251 onClose: null, // Define a callback function when the datepicker is closed 7252 onUpdateDatepicker: null, // Define a callback function when the datepicker is updated 7253 numberOfMonths: 1, // Number of months to show at a time 7254 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 7255 stepMonths: 1, // Number of months to step back/forward 7256 stepBigMonths: 12, // Number of months to step back/forward for the big links 7257 altField: "", // Selector for an alternate field to store selected dates into 7258 altFormat: "", // The date format to use for the alternate field 7259 constrainInput: true, // The input is constrained by the current date format 7260 showButtonPanel: false, // True to show button panel, false to not show it 7261 autoSize: false, // True to size the input for the date format, false to leave as is 7262 disabled: false // The initial disabled state 7263 }; 7264 $.extend( this._defaults, this.regional[ "" ] ); 7265 this.regional.en = $.extend( true, {}, this.regional[ "" ] ); 7266 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 7267 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 7268 } 7269 7270 $.extend( Datepicker.prototype, { 7271 7272 /* Class name added to elements to indicate already configured with a date picker. */ 7273 markerClassName: "hasDatepicker", 7274 7275 //Keep track of the maximum number of rows displayed (see #7043) 7276 maxRows: 4, 7277 7278 // TODO rename to "widget" when switching to widget factory 7279 _widgetDatepicker: function() { 7280 return this.dpDiv; 7281 }, 7282 7283 /* Override the default settings for all instances of the date picker. 7284 * @param settings object - the new settings to use as defaults (anonymous object) 7285 * @return the manager object 7286 */ 7287 setDefaults: function( settings ) { 7288 datepicker_extendRemove( this._defaults, settings || {} ); 7289 return this; 7290 }, 7291 7292 /* Attach the date picker to a jQuery selection. 7293 * @param target element - the target input field or division or span 7294 * @param settings object - the new settings to use for this date picker instance (anonymous) 7295 */ 7296 _attachDatepicker: function( target, settings ) { 7297 var nodeName, inline, inst; 7298 nodeName = target.nodeName.toLowerCase(); 7299 inline = ( nodeName === "div" || nodeName === "span" ); 7300 if ( !target.id ) { 7301 this.uuid += 1; 7302 target.id = "dp" + this.uuid; 7303 } 7304 inst = this._newInst( $( target ), inline ); 7305 inst.settings = $.extend( {}, settings || {} ); 7306 if ( nodeName === "input" ) { 7307 this._connectDatepicker( target, inst ); 7308 } else if ( inline ) { 7309 this._inlineDatepicker( target, inst ); 7310 } 7311 }, 7312 7313 /* Create a new instance object. */ 7314 _newInst: function( target, inline ) { 7315 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars 7316 return { id: id, input: target, // associated target 7317 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 7318 drawMonth: 0, drawYear: 0, // month being drawn 7319 inline: inline, // is datepicker inline or not 7320 dpDiv: ( !inline ? this.dpDiv : // presentation div 7321 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) }; 7322 }, 7323 7324 /* Attach the date picker to an input field. */ 7325 _connectDatepicker: function( target, inst ) { 7326 var input = $( target ); 7327 inst.append = $( [] ); 7328 inst.trigger = $( [] ); 7329 if ( input.hasClass( this.markerClassName ) ) { 7330 return; 7331 } 7332 this._attachments( input, inst ); 7333 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ). 7334 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp ); 7335 this._autoSize( inst ); 7336 $.data( target, "datepicker", inst ); 7337 7338 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 7339 if ( inst.settings.disabled ) { 7340 this._disableDatepicker( target ); 7341 } 7342 }, 7343 7344 /* Make attachments based on settings. */ 7345 _attachments: function( input, inst ) { 7346 var showOn, buttonText, buttonImage, 7347 appendText = this._get( inst, "appendText" ), 7348 isRTL = this._get( inst, "isRTL" ); 7349 7350 if ( inst.append ) { 7351 inst.append.remove(); 7352 } 7353 if ( appendText ) { 7354 inst.append = $( "<span>" ) 7355 .addClass( this._appendClass ) 7356 .text( appendText ); 7357 input[ isRTL ? "before" : "after" ]( inst.append ); 7358 } 7359 7360 input.off( "focus", this._showDatepicker ); 7361 7362 if ( inst.trigger ) { 7363 inst.trigger.remove(); 7364 } 7365 7366 showOn = this._get( inst, "showOn" ); 7367 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field 7368 input.on( "focus", this._showDatepicker ); 7369 } 7370 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked 7371 buttonText = this._get( inst, "buttonText" ); 7372 buttonImage = this._get( inst, "buttonImage" ); 7373 7374 if ( this._get( inst, "buttonImageOnly" ) ) { 7375 inst.trigger = $( "<img>" ) 7376 .addClass( this._triggerClass ) 7377 .attr( { 7378 src: buttonImage, 7379 alt: buttonText, 7380 title: buttonText 7381 } ); 7382 } else { 7383 inst.trigger = $( "<button type='button'>" ) 7384 .addClass( this._triggerClass ); 7385 if ( buttonImage ) { 7386 inst.trigger.html( 7387 $( "<img>" ) 7388 .attr( { 7389 src: buttonImage, 7390 alt: buttonText, 7391 title: buttonText 7392 } ) 7393 ); 7394 } else { 7395 inst.trigger.text( buttonText ); 7396 } 7397 } 7398 7399 input[ isRTL ? "before" : "after" ]( inst.trigger ); 7400 inst.trigger.on( "click", function() { 7401 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) { 7402 $.datepicker._hideDatepicker(); 7403 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) { 7404 $.datepicker._hideDatepicker(); 7405 $.datepicker._showDatepicker( input[ 0 ] ); 7406 } else { 7407 $.datepicker._showDatepicker( input[ 0 ] ); 7408 } 7409 return false; 7410 } ); 7411 } 7412 }, 7413 7414 /* Apply the maximum length for the date format. */ 7415 _autoSize: function( inst ) { 7416 if ( this._get( inst, "autoSize" ) && !inst.inline ) { 7417 var findMax, max, maxI, i, 7418 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits 7419 dateFormat = this._get( inst, "dateFormat" ); 7420 7421 if ( dateFormat.match( /[DM]/ ) ) { 7422 findMax = function( names ) { 7423 max = 0; 7424 maxI = 0; 7425 for ( i = 0; i < names.length; i++ ) { 7426 if ( names[ i ].length > max ) { 7427 max = names[ i ].length; 7428 maxI = i; 7429 } 7430 } 7431 return maxI; 7432 }; 7433 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ? 7434 "monthNames" : "monthNamesShort" ) ) ) ); 7435 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ? 7436 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() ); 7437 } 7438 inst.input.attr( "size", this._formatDate( inst, date ).length ); 7439 } 7440 }, 7441 7442 /* Attach an inline date picker to a div. */ 7443 _inlineDatepicker: function( target, inst ) { 7444 var divSpan = $( target ); 7445 if ( divSpan.hasClass( this.markerClassName ) ) { 7446 return; 7447 } 7448 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 7449 $.data( target, "datepicker", inst ); 7450 this._setDate( inst, this._getDefaultDate( inst ), true ); 7451 this._updateDatepicker( inst ); 7452 this._updateAlternate( inst ); 7453 7454 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 7455 if ( inst.settings.disabled ) { 7456 this._disableDatepicker( target ); 7457 } 7458 7459 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 7460 // https://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 7461 inst.dpDiv.css( "display", "block" ); 7462 }, 7463 7464 /* Pop-up the date picker in a "dialog" box. 7465 * @param input element - ignored 7466 * @param date string or Date - the initial date to display 7467 * @param onSelect function - the function to call when a date is selected 7468 * @param settings object - update the dialog date picker instance's settings (anonymous object) 7469 * @param pos int[2] - coordinates for the dialog's position within the screen or 7470 * event - with x/y coordinates or 7471 * leave empty for default (screen centre) 7472 * @return the manager object 7473 */ 7474 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 7475 var id, browserWidth, browserHeight, scrollX, scrollY, 7476 inst = this._dialogInst; // internal instance 7477 7478 if ( !inst ) { 7479 this.uuid += 1; 7480 id = "dp" + this.uuid; 7481 this._dialogInput = $( "<input type='text' id='" + id + 7482 "' style='position: absolute; top: -100px; width: 0px;'/>" ); 7483 this._dialogInput.on( "keydown", this._doKeyDown ); 7484 $( "body" ).append( this._dialogInput ); 7485 inst = this._dialogInst = this._newInst( this._dialogInput, false ); 7486 inst.settings = {}; 7487 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7488 } 7489 datepicker_extendRemove( inst.settings, settings || {} ); 7490 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date ); 7491 this._dialogInput.val( date ); 7492 7493 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null ); 7494 if ( !this._pos ) { 7495 browserWidth = document.documentElement.clientWidth; 7496 browserHeight = document.documentElement.clientHeight; 7497 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 7498 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 7499 this._pos = // should use actual width/height below 7500 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 7501 } 7502 7503 // Move input on screen for focus, but hidden behind dialog 7504 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" ); 7505 inst.settings.onSelect = onSelect; 7506 this._inDialog = true; 7507 this.dpDiv.addClass( this._dialogClass ); 7508 this._showDatepicker( this._dialogInput[ 0 ] ); 7509 if ( $.blockUI ) { 7510 $.blockUI( this.dpDiv ); 7511 } 7512 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7513 return this; 7514 }, 7515 7516 /* Detach a datepicker from its control. 7517 * @param target element - the target input field or division or span 7518 */ 7519 _destroyDatepicker: function( target ) { 7520 var nodeName, 7521 $target = $( target ), 7522 inst = $.data( target, "datepicker" ); 7523 7524 if ( !$target.hasClass( this.markerClassName ) ) { 7525 return; 7526 } 7527 7528 nodeName = target.nodeName.toLowerCase(); 7529 $.removeData( target, "datepicker" ); 7530 if ( nodeName === "input" ) { 7531 inst.append.remove(); 7532 inst.trigger.remove(); 7533 $target.removeClass( this.markerClassName ). 7534 off( "focus", this._showDatepicker ). 7535 off( "keydown", this._doKeyDown ). 7536 off( "keypress", this._doKeyPress ). 7537 off( "keyup", this._doKeyUp ); 7538 } else if ( nodeName === "div" || nodeName === "span" ) { 7539 $target.removeClass( this.markerClassName ).empty(); 7540 } 7541 7542 $.datepicker._hideDatepicker(); 7543 if ( datepicker_instActive === inst ) { 7544 datepicker_instActive = null; 7545 this._curInst = null; 7546 } 7547 }, 7548 7549 /* Enable the date picker to a jQuery selection. 7550 * @param target element - the target input field or division or span 7551 */ 7552 _enableDatepicker: function( target ) { 7553 var nodeName, inline, 7554 $target = $( target ), 7555 inst = $.data( target, "datepicker" ); 7556 7557 if ( !$target.hasClass( this.markerClassName ) ) { 7558 return; 7559 } 7560 7561 nodeName = target.nodeName.toLowerCase(); 7562 if ( nodeName === "input" ) { 7563 target.disabled = false; 7564 inst.trigger.filter( "button" ). 7565 each( function() { 7566 this.disabled = false; 7567 } ).end(). 7568 filter( "img" ).css( { opacity: "1.0", cursor: "" } ); 7569 } else if ( nodeName === "div" || nodeName === "span" ) { 7570 inline = $target.children( "." + this._inlineClass ); 7571 inline.children().removeClass( "ui-state-disabled" ); 7572 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7573 prop( "disabled", false ); 7574 } 7575 this._disabledInputs = $.map( this._disabledInputs, 7576 7577 // Delete entry 7578 function( value ) { 7579 return ( value === target ? null : value ); 7580 } ); 7581 }, 7582 7583 /* Disable the date picker to a jQuery selection. 7584 * @param target element - the target input field or division or span 7585 */ 7586 _disableDatepicker: function( target ) { 7587 var nodeName, inline, 7588 $target = $( target ), 7589 inst = $.data( target, "datepicker" ); 7590 7591 if ( !$target.hasClass( this.markerClassName ) ) { 7592 return; 7593 } 7594 7595 nodeName = target.nodeName.toLowerCase(); 7596 if ( nodeName === "input" ) { 7597 target.disabled = true; 7598 inst.trigger.filter( "button" ). 7599 each( function() { 7600 this.disabled = true; 7601 } ).end(). 7602 filter( "img" ).css( { opacity: "0.5", cursor: "default" } ); 7603 } else if ( nodeName === "div" || nodeName === "span" ) { 7604 inline = $target.children( "." + this._inlineClass ); 7605 inline.children().addClass( "ui-state-disabled" ); 7606 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7607 prop( "disabled", true ); 7608 } 7609 this._disabledInputs = $.map( this._disabledInputs, 7610 7611 // Delete entry 7612 function( value ) { 7613 return ( value === target ? null : value ); 7614 } ); 7615 this._disabledInputs[ this._disabledInputs.length ] = target; 7616 }, 7617 7618 /* Is the first field in a jQuery collection disabled as a datepicker? 7619 * @param target element - the target input field or division or span 7620 * @return boolean - true if disabled, false if enabled 7621 */ 7622 _isDisabledDatepicker: function( target ) { 7623 if ( !target ) { 7624 return false; 7625 } 7626 for ( var i = 0; i < this._disabledInputs.length; i++ ) { 7627 if ( this._disabledInputs[ i ] === target ) { 7628 return true; 7629 } 7630 } 7631 return false; 7632 }, 7633 7634 /* Retrieve the instance data for the target control. 7635 * @param target element - the target input field or division or span 7636 * @return object - the associated instance data 7637 * @throws error if a jQuery problem getting data 7638 */ 7639 _getInst: function( target ) { 7640 try { 7641 return $.data( target, "datepicker" ); 7642 } catch ( err ) { 7643 throw "Missing instance data for this datepicker"; 7644 } 7645 }, 7646 7647 /* Update or retrieve the settings for a date picker attached to an input field or division. 7648 * @param target element - the target input field or division or span 7649 * @param name object - the new settings to update or 7650 * string - the name of the setting to change or retrieve, 7651 * when retrieving also "all" for all instance settings or 7652 * "defaults" for all global defaults 7653 * @param value any - the new value for the setting 7654 * (omit if above is an object or to retrieve a value) 7655 */ 7656 _optionDatepicker: function( target, name, value ) { 7657 var settings, date, minDate, maxDate, 7658 inst = this._getInst( target ); 7659 7660 if ( arguments.length === 2 && typeof name === "string" ) { 7661 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) : 7662 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) : 7663 this._get( inst, name ) ) : null ) ); 7664 } 7665 7666 settings = name || {}; 7667 if ( typeof name === "string" ) { 7668 settings = {}; 7669 settings[ name ] = value; 7670 } 7671 7672 if ( inst ) { 7673 if ( this._curInst === inst ) { 7674 this._hideDatepicker(); 7675 } 7676 7677 date = this._getDateDatepicker( target, true ); 7678 minDate = this._getMinMaxDate( inst, "min" ); 7679 maxDate = this._getMinMaxDate( inst, "max" ); 7680 datepicker_extendRemove( inst.settings, settings ); 7681 7682 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 7683 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 7684 inst.settings.minDate = this._formatDate( inst, minDate ); 7685 } 7686 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 7687 inst.settings.maxDate = this._formatDate( inst, maxDate ); 7688 } 7689 if ( "disabled" in settings ) { 7690 if ( settings.disabled ) { 7691 this._disableDatepicker( target ); 7692 } else { 7693 this._enableDatepicker( target ); 7694 } 7695 } 7696 this._attachments( $( target ), inst ); 7697 this._autoSize( inst ); 7698 this._setDate( inst, date ); 7699 this._updateAlternate( inst ); 7700 this._updateDatepicker( inst ); 7701 } 7702 }, 7703 7704 // Change method deprecated 7705 _changeDatepicker: function( target, name, value ) { 7706 this._optionDatepicker( target, name, value ); 7707 }, 7708 7709 /* Redraw the date picker attached to an input field or division. 7710 * @param target element - the target input field or division or span 7711 */ 7712 _refreshDatepicker: function( target ) { 7713 var inst = this._getInst( target ); 7714 if ( inst ) { 7715 this._updateDatepicker( inst ); 7716 } 7717 }, 7718 7719 /* Set the dates for a jQuery selection. 7720 * @param target element - the target input field or division or span 7721 * @param date Date - the new date 7722 */ 7723 _setDateDatepicker: function( target, date ) { 7724 var inst = this._getInst( target ); 7725 if ( inst ) { 7726 this._setDate( inst, date ); 7727 this._updateDatepicker( inst ); 7728 this._updateAlternate( inst ); 7729 } 7730 }, 7731 7732 /* Get the date(s) for the first entry in a jQuery selection. 7733 * @param target element - the target input field or division or span 7734 * @param noDefault boolean - true if no default date is to be used 7735 * @return Date - the current date 7736 */ 7737 _getDateDatepicker: function( target, noDefault ) { 7738 var inst = this._getInst( target ); 7739 if ( inst && !inst.inline ) { 7740 this._setDateFromField( inst, noDefault ); 7741 } 7742 return ( inst ? this._getDate( inst ) : null ); 7743 }, 7744 7745 /* Handle keystrokes. */ 7746 _doKeyDown: function( event ) { 7747 var onSelect, dateStr, sel, 7748 inst = $.datepicker._getInst( event.target ), 7749 handled = true, 7750 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" ); 7751 7752 inst._keyEvent = true; 7753 if ( $.datepicker._datepickerShowing ) { 7754 switch ( event.keyCode ) { 7755 case 9: $.datepicker._hideDatepicker(); 7756 handled = false; 7757 break; // hide on tab out 7758 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." + 7759 $.datepicker._currentClass + ")", inst.dpDiv ); 7760 if ( sel[ 0 ] ) { 7761 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 7762 } 7763 7764 onSelect = $.datepicker._get( inst, "onSelect" ); 7765 if ( onSelect ) { 7766 dateStr = $.datepicker._formatDate( inst ); 7767 7768 // Trigger custom callback 7769 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); 7770 } else { 7771 $.datepicker._hideDatepicker(); 7772 } 7773 7774 return false; // don't submit the form 7775 case 27: $.datepicker._hideDatepicker(); 7776 break; // hide on escape 7777 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7778 -$.datepicker._get( inst, "stepBigMonths" ) : 7779 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7780 break; // previous month/year on page up/+ ctrl 7781 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7782 +$.datepicker._get( inst, "stepBigMonths" ) : 7783 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7784 break; // next month/year on page down/+ ctrl 7785 case 35: if ( event.ctrlKey || event.metaKey ) { 7786 $.datepicker._clearDate( event.target ); 7787 } 7788 handled = event.ctrlKey || event.metaKey; 7789 break; // clear on ctrl or command +end 7790 case 36: if ( event.ctrlKey || event.metaKey ) { 7791 $.datepicker._gotoToday( event.target ); 7792 } 7793 handled = event.ctrlKey || event.metaKey; 7794 break; // current on ctrl or command +home 7795 case 37: if ( event.ctrlKey || event.metaKey ) { 7796 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" ); 7797 } 7798 handled = event.ctrlKey || event.metaKey; 7799 7800 // -1 day on ctrl or command +left 7801 if ( event.originalEvent.altKey ) { 7802 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7803 -$.datepicker._get( inst, "stepBigMonths" ) : 7804 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7805 } 7806 7807 // next month/year on alt +left on Mac 7808 break; 7809 case 38: if ( event.ctrlKey || event.metaKey ) { 7810 $.datepicker._adjustDate( event.target, -7, "D" ); 7811 } 7812 handled = event.ctrlKey || event.metaKey; 7813 break; // -1 week on ctrl or command +up 7814 case 39: if ( event.ctrlKey || event.metaKey ) { 7815 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" ); 7816 } 7817 handled = event.ctrlKey || event.metaKey; 7818 7819 // +1 day on ctrl or command +right 7820 if ( event.originalEvent.altKey ) { 7821 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7822 +$.datepicker._get( inst, "stepBigMonths" ) : 7823 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7824 } 7825 7826 // next month/year on alt +right 7827 break; 7828 case 40: if ( event.ctrlKey || event.metaKey ) { 7829 $.datepicker._adjustDate( event.target, +7, "D" ); 7830 } 7831 handled = event.ctrlKey || event.metaKey; 7832 break; // +1 week on ctrl or command +down 7833 default: handled = false; 7834 } 7835 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home 7836 $.datepicker._showDatepicker( this ); 7837 } else { 7838 handled = false; 7839 } 7840 7841 if ( handled ) { 7842 event.preventDefault(); 7843 event.stopPropagation(); 7844 } 7845 }, 7846 7847 /* Filter entered characters - based on date format. */ 7848 _doKeyPress: function( event ) { 7849 var chars, chr, 7850 inst = $.datepicker._getInst( event.target ); 7851 7852 if ( $.datepicker._get( inst, "constrainInput" ) ) { 7853 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) ); 7854 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode ); 7855 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 ); 7856 } 7857 }, 7858 7859 /* Synchronise manual entry and field/alternate field. */ 7860 _doKeyUp: function( event ) { 7861 var date, 7862 inst = $.datepicker._getInst( event.target ); 7863 7864 if ( inst.input.val() !== inst.lastVal ) { 7865 try { 7866 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 7867 ( inst.input ? inst.input.val() : null ), 7868 $.datepicker._getFormatConfig( inst ) ); 7869 7870 if ( date ) { // only if valid 7871 $.datepicker._setDateFromField( inst ); 7872 $.datepicker._updateAlternate( inst ); 7873 $.datepicker._updateDatepicker( inst ); 7874 } 7875 } catch ( err ) { 7876 } 7877 } 7878 return true; 7879 }, 7880 7881 /* Pop-up the date picker for a given input field. 7882 * If false returned from beforeShow event handler do not show. 7883 * @param input element - the input field attached to the date picker or 7884 * event - if triggered by focus 7885 */ 7886 _showDatepicker: function( input ) { 7887 input = input.target || input; 7888 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger 7889 input = $( "input", input.parentNode )[ 0 ]; 7890 } 7891 7892 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here 7893 return; 7894 } 7895 7896 var inst, beforeShow, beforeShowSettings, isFixed, 7897 offset, showAnim, duration; 7898 7899 inst = $.datepicker._getInst( input ); 7900 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) { 7901 $.datepicker._curInst.dpDiv.stop( true, true ); 7902 if ( inst && $.datepicker._datepickerShowing ) { 7903 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] ); 7904 } 7905 } 7906 7907 beforeShow = $.datepicker._get( inst, "beforeShow" ); 7908 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 7909 if ( beforeShowSettings === false ) { 7910 return; 7911 } 7912 datepicker_extendRemove( inst.settings, beforeShowSettings ); 7913 7914 inst.lastVal = null; 7915 $.datepicker._lastInput = input; 7916 $.datepicker._setDateFromField( inst ); 7917 7918 if ( $.datepicker._inDialog ) { // hide cursor 7919 input.value = ""; 7920 } 7921 if ( !$.datepicker._pos ) { // position below input 7922 $.datepicker._pos = $.datepicker._findPos( input ); 7923 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height 7924 } 7925 7926 isFixed = false; 7927 $( input ).parents().each( function() { 7928 isFixed |= $( this ).css( "position" ) === "fixed"; 7929 return !isFixed; 7930 } ); 7931 7932 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] }; 7933 $.datepicker._pos = null; 7934 7935 //to avoid flashes on Firefox 7936 inst.dpDiv.empty(); 7937 7938 // determine sizing offscreen 7939 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } ); 7940 $.datepicker._updateDatepicker( inst ); 7941 7942 // fix width for dynamic number of date pickers 7943 // and adjust position before showing 7944 offset = $.datepicker._checkOffset( inst, offset, isFixed ); 7945 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ? 7946 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none", 7947 left: offset.left + "px", top: offset.top + "px" } ); 7948 7949 if ( !inst.inline ) { 7950 showAnim = $.datepicker._get( inst, "showAnim" ); 7951 duration = $.datepicker._get( inst, "duration" ); 7952 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 7953 $.datepicker._datepickerShowing = true; 7954 7955 if ( $.effects && $.effects.effect[ showAnim ] ) { 7956 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration ); 7957 } else { 7958 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null ); 7959 } 7960 7961 if ( $.datepicker._shouldFocusInput( inst ) ) { 7962 inst.input.trigger( "focus" ); 7963 } 7964 7965 $.datepicker._curInst = inst; 7966 } 7967 }, 7968 7969 /* Generate the date picker content. */ 7970 _updateDatepicker: function( inst ) { 7971 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 7972 datepicker_instActive = inst; // for delegate hover events 7973 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 7974 this._attachHandlers( inst ); 7975 7976 var origyearshtml, 7977 numMonths = this._getNumberOfMonths( inst ), 7978 cols = numMonths[ 1 ], 7979 width = 17, 7980 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ), 7981 onUpdateDatepicker = $.datepicker._get( inst, "onUpdateDatepicker" ); 7982 7983 if ( activeCell.length > 0 ) { 7984 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 7985 } 7986 7987 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" ); 7988 if ( cols > 1 ) { 7989 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" ); 7990 } 7991 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) + 7992 "Class" ]( "ui-datepicker-multi" ); 7993 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) + 7994 "Class" ]( "ui-datepicker-rtl" ); 7995 7996 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 7997 inst.input.trigger( "focus" ); 7998 } 7999 8000 // Deffered render of the years select (to avoid flashes on Firefox) 8001 if ( inst.yearshtml ) { 8002 origyearshtml = inst.yearshtml; 8003 setTimeout( function() { 8004 8005 //assure that inst.yearshtml didn't change. 8006 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) { 8007 inst.dpDiv.find( "select.ui-datepicker-year" ).first().replaceWith( inst.yearshtml ); 8008 } 8009 origyearshtml = inst.yearshtml = null; 8010 }, 0 ); 8011 } 8012 8013 if ( onUpdateDatepicker ) { 8014 onUpdateDatepicker.apply( ( inst.input ? inst.input[ 0 ] : null ), [ inst ] ); 8015 } 8016 }, 8017 8018 _shouldFocusInput: function( inst ) { 8019 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ); 8020 }, 8021 8022 /* Check positioning to remain on screen. */ 8023 _checkOffset: function( inst, offset, isFixed ) { 8024 var dpWidth = inst.dpDiv.outerWidth(), 8025 dpHeight = inst.dpDiv.outerHeight(), 8026 inputWidth = inst.input ? inst.input.outerWidth() : 0, 8027 inputHeight = inst.input ? inst.input.outerHeight() : 0, 8028 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 8029 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 8030 8031 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 ); 8032 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0; 8033 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0; 8034 8035 // Now check if datepicker is showing outside window viewport - move to a better place if so. 8036 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ? 8037 Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 8038 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ? 8039 Math.abs( dpHeight + inputHeight ) : 0 ); 8040 8041 return offset; 8042 }, 8043 8044 /* Find an object's position on the screen. */ 8045 _findPos: function( obj ) { 8046 var position, 8047 inst = this._getInst( obj ), 8048 isRTL = this._get( inst, "isRTL" ); 8049 8050 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.pseudos.hidden( obj ) ) ) { 8051 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ]; 8052 } 8053 8054 position = $( obj ).offset(); 8055 return [ position.left, position.top ]; 8056 }, 8057 8058 /* Hide the date picker from view. 8059 * @param input element - the input field attached to the date picker 8060 */ 8061 _hideDatepicker: function( input ) { 8062 var showAnim, duration, postProcess, onClose, 8063 inst = this._curInst; 8064 8065 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) { 8066 return; 8067 } 8068 8069 if ( this._datepickerShowing ) { 8070 showAnim = this._get( inst, "showAnim" ); 8071 duration = this._get( inst, "duration" ); 8072 postProcess = function() { 8073 $.datepicker._tidyDialog( inst ); 8074 }; 8075 8076 if ( $.effects && ( $.effects.effect[ showAnim ] ) ) { 8077 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess ); 8078 } else { 8079 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" : 8080 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess ); 8081 } 8082 8083 if ( !showAnim ) { 8084 postProcess(); 8085 } 8086 this._datepickerShowing = false; 8087 8088 onClose = this._get( inst, "onClose" ); 8089 if ( onClose ) { 8090 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] ); 8091 } 8092 8093 this._lastInput = null; 8094 if ( this._inDialog ) { 8095 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } ); 8096 if ( $.blockUI ) { 8097 $.unblockUI(); 8098 $( "body" ).append( this.dpDiv ); 8099 } 8100 } 8101 this._inDialog = false; 8102 } 8103 }, 8104 8105 /* Tidy up after a dialog display. */ 8106 _tidyDialog: function( inst ) { 8107 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" ); 8108 }, 8109 8110 /* Close date picker if clicked elsewhere. */ 8111 _checkExternalClick: function( event ) { 8112 if ( !$.datepicker._curInst ) { 8113 return; 8114 } 8115 8116 var $target = $( event.target ), 8117 inst = $.datepicker._getInst( $target[ 0 ] ); 8118 8119 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId && 8120 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 && 8121 !$target.hasClass( $.datepicker.markerClassName ) && 8122 !$target.closest( "." + $.datepicker._triggerClass ).length && 8123 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) || 8124 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) { 8125 $.datepicker._hideDatepicker(); 8126 } 8127 }, 8128 8129 /* Adjust one of the date sub-fields. */ 8130 _adjustDate: function( id, offset, period ) { 8131 var target = $( id ), 8132 inst = this._getInst( target[ 0 ] ); 8133 8134 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 8135 return; 8136 } 8137 this._adjustInstDate( inst, offset, period ); 8138 this._updateDatepicker( inst ); 8139 }, 8140 8141 /* Action for current link. */ 8142 _gotoToday: function( id ) { 8143 var date, 8144 target = $( id ), 8145 inst = this._getInst( target[ 0 ] ); 8146 8147 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) { 8148 inst.selectedDay = inst.currentDay; 8149 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 8150 inst.drawYear = inst.selectedYear = inst.currentYear; 8151 } else { 8152 date = new Date(); 8153 inst.selectedDay = date.getDate(); 8154 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8155 inst.drawYear = inst.selectedYear = date.getFullYear(); 8156 } 8157 this._notifyChange( inst ); 8158 this._adjustDate( target ); 8159 }, 8160 8161 /* Action for selecting a new month/year. */ 8162 _selectMonthYear: function( id, select, period ) { 8163 var target = $( id ), 8164 inst = this._getInst( target[ 0 ] ); 8165 8166 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] = 8167 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] = 8168 parseInt( select.options[ select.selectedIndex ].value, 10 ); 8169 8170 this._notifyChange( inst ); 8171 this._adjustDate( target ); 8172 }, 8173 8174 /* Action for selecting a day. */ 8175 _selectDay: function( id, month, year, td ) { 8176 var inst, 8177 target = $( id ); 8178 8179 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 8180 return; 8181 } 8182 8183 inst = this._getInst( target[ 0 ] ); 8184 inst.selectedDay = inst.currentDay = parseInt( $( "a", td ).attr( "data-date" ) ); 8185 inst.selectedMonth = inst.currentMonth = month; 8186 inst.selectedYear = inst.currentYear = year; 8187 this._selectDate( id, this._formatDate( inst, 8188 inst.currentDay, inst.currentMonth, inst.currentYear ) ); 8189 }, 8190 8191 /* Erase the input field and hide the date picker. */ 8192 _clearDate: function( id ) { 8193 var target = $( id ); 8194 this._selectDate( target, "" ); 8195 }, 8196 8197 /* Update the input field with the selected date. */ 8198 _selectDate: function( id, dateStr ) { 8199 var onSelect, 8200 target = $( id ), 8201 inst = this._getInst( target[ 0 ] ); 8202 8203 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) ); 8204 if ( inst.input ) { 8205 inst.input.val( dateStr ); 8206 } 8207 this._updateAlternate( inst ); 8208 8209 onSelect = this._get( inst, "onSelect" ); 8210 if ( onSelect ) { 8211 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback 8212 } else if ( inst.input ) { 8213 inst.input.trigger( "change" ); // fire the change event 8214 } 8215 8216 if ( inst.inline ) { 8217 this._updateDatepicker( inst ); 8218 } else { 8219 this._hideDatepicker(); 8220 this._lastInput = inst.input[ 0 ]; 8221 if ( typeof( inst.input[ 0 ] ) !== "object" ) { 8222 inst.input.trigger( "focus" ); // restore focus 8223 } 8224 this._lastInput = null; 8225 } 8226 }, 8227 8228 /* Update any alternate field to synchronise with the main field. */ 8229 _updateAlternate: function( inst ) { 8230 var altFormat, date, dateStr, 8231 altField = this._get( inst, "altField" ); 8232 8233 if ( altField ) { // update alternate field too 8234 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" ); 8235 date = this._getDate( inst ); 8236 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 8237 $( document ).find( altField ).val( dateStr ); 8238 } 8239 }, 8240 8241 /* Set as beforeShowDay function to prevent selection of weekends. 8242 * @param date Date - the date to customise 8243 * @return [boolean, string] - is this date selectable?, what is its CSS class? 8244 */ 8245 noWeekends: function( date ) { 8246 var day = date.getDay(); 8247 return [ ( day > 0 && day < 6 ), "" ]; 8248 }, 8249 8250 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 8251 * @param date Date - the date to get the week for 8252 * @return number - the number of the week within the year that contains this date 8253 */ 8254 iso8601Week: function( date ) { 8255 var time, 8256 checkDate = new Date( date.getTime() ); 8257 8258 // Find Thursday of this week starting on Monday 8259 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 8260 8261 time = checkDate.getTime(); 8262 checkDate.setMonth( 0 ); // Compare with Jan 1 8263 checkDate.setDate( 1 ); 8264 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 8265 }, 8266 8267 /* Parse a string value into a date object. 8268 * See formatDate below for the possible formats. 8269 * 8270 * @param format string - the expected format of the date 8271 * @param value string - the date in the above format 8272 * @param settings Object - attributes include: 8273 * shortYearCutoff number - the cutoff year for determining the century (optional) 8274 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8275 * dayNames string[7] - names of the days from Sunday (optional) 8276 * monthNamesShort string[12] - abbreviated names of the months (optional) 8277 * monthNames string[12] - names of the months (optional) 8278 * @return Date - the extracted date value or null if value is blank 8279 */ 8280 parseDate: function( format, value, settings ) { 8281 if ( format == null || value == null ) { 8282 throw "Invalid arguments"; 8283 } 8284 8285 value = ( typeof value === "object" ? value.toString() : value + "" ); 8286 if ( value === "" ) { 8287 return null; 8288 } 8289 8290 var iFormat, dim, extra, 8291 iValue = 0, 8292 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff, 8293 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 8294 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ), 8295 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8296 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8297 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8298 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8299 year = -1, 8300 month = -1, 8301 day = -1, 8302 doy = -1, 8303 literal = false, 8304 date, 8305 8306 // Check whether a format character is doubled 8307 lookAhead = function( match ) { 8308 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8309 if ( matches ) { 8310 iFormat++; 8311 } 8312 return matches; 8313 }, 8314 8315 // Extract a number from the string value 8316 getNumber = function( match ) { 8317 var isDoubled = lookAhead( match ), 8318 size = ( match === "@" ? 14 : ( match === "!" ? 20 : 8319 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ), 8320 minSize = ( match === "y" ? size : 1 ), 8321 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ), 8322 num = value.substring( iValue ).match( digits ); 8323 if ( !num ) { 8324 throw "Missing number at position " + iValue; 8325 } 8326 iValue += num[ 0 ].length; 8327 return parseInt( num[ 0 ], 10 ); 8328 }, 8329 8330 // Extract a name from the string value and convert to an index 8331 getName = function( match, shortNames, longNames ) { 8332 var index = -1, 8333 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 8334 return [ [ k, v ] ]; 8335 } ).sort( function( a, b ) { 8336 return -( a[ 1 ].length - b[ 1 ].length ); 8337 } ); 8338 8339 $.each( names, function( i, pair ) { 8340 var name = pair[ 1 ]; 8341 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) { 8342 index = pair[ 0 ]; 8343 iValue += name.length; 8344 return false; 8345 } 8346 } ); 8347 if ( index !== -1 ) { 8348 return index + 1; 8349 } else { 8350 throw "Unknown name at position " + iValue; 8351 } 8352 }, 8353 8354 // Confirm that a literal character matches the string value 8355 checkLiteral = function() { 8356 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 8357 throw "Unexpected literal at position " + iValue; 8358 } 8359 iValue++; 8360 }; 8361 8362 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8363 if ( literal ) { 8364 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8365 literal = false; 8366 } else { 8367 checkLiteral(); 8368 } 8369 } else { 8370 switch ( format.charAt( iFormat ) ) { 8371 case "d": 8372 day = getNumber( "d" ); 8373 break; 8374 case "D": 8375 getName( "D", dayNamesShort, dayNames ); 8376 break; 8377 case "o": 8378 doy = getNumber( "o" ); 8379 break; 8380 case "m": 8381 month = getNumber( "m" ); 8382 break; 8383 case "M": 8384 month = getName( "M", monthNamesShort, monthNames ); 8385 break; 8386 case "y": 8387 year = getNumber( "y" ); 8388 break; 8389 case "@": 8390 date = new Date( getNumber( "@" ) ); 8391 year = date.getFullYear(); 8392 month = date.getMonth() + 1; 8393 day = date.getDate(); 8394 break; 8395 case "!": 8396 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 ); 8397 year = date.getFullYear(); 8398 month = date.getMonth() + 1; 8399 day = date.getDate(); 8400 break; 8401 case "'": 8402 if ( lookAhead( "'" ) ) { 8403 checkLiteral(); 8404 } else { 8405 literal = true; 8406 } 8407 break; 8408 default: 8409 checkLiteral(); 8410 } 8411 } 8412 } 8413 8414 if ( iValue < value.length ) { 8415 extra = value.substr( iValue ); 8416 if ( !/^\s+/.test( extra ) ) { 8417 throw "Extra/unparsed characters found in date: " + extra; 8418 } 8419 } 8420 8421 if ( year === -1 ) { 8422 year = new Date().getFullYear(); 8423 } else if ( year < 100 ) { 8424 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 8425 ( year <= shortYearCutoff ? 0 : -100 ); 8426 } 8427 8428 if ( doy > -1 ) { 8429 month = 1; 8430 day = doy; 8431 do { 8432 dim = this._getDaysInMonth( year, month - 1 ); 8433 if ( day <= dim ) { 8434 break; 8435 } 8436 month++; 8437 day -= dim; 8438 } while ( true ); 8439 } 8440 8441 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 8442 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 8443 throw "Invalid date"; // E.g. 31/02/00 8444 } 8445 return date; 8446 }, 8447 8448 /* Standard date formats. */ 8449 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 8450 COOKIE: "D, dd M yy", 8451 ISO_8601: "yy-mm-dd", 8452 RFC_822: "D, d M y", 8453 RFC_850: "DD, dd-M-y", 8454 RFC_1036: "D, d M y", 8455 RFC_1123: "D, d M yy", 8456 RFC_2822: "D, d M yy", 8457 RSS: "D, d M y", // RFC 822 8458 TICKS: "!", 8459 TIMESTAMP: "@", 8460 W3C: "yy-mm-dd", // ISO 8601 8461 8462 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + 8463 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ), 8464 8465 /* Format a date object into a string value. 8466 * The format can be combinations of the following: 8467 * d - day of month (no leading zero) 8468 * dd - day of month (two digit) 8469 * o - day of year (no leading zeros) 8470 * oo - day of year (three digit) 8471 * D - day name short 8472 * DD - day name long 8473 * m - month of year (no leading zero) 8474 * mm - month of year (two digit) 8475 * M - month name short 8476 * MM - month name long 8477 * y - year (two digit) 8478 * yy - year (four digit) 8479 * @ - Unix timestamp (ms since 01/01/1970) 8480 * ! - Windows ticks (100ns since 01/01/0001) 8481 * "..." - literal text 8482 * '' - single quote 8483 * 8484 * @param format string - the desired format of the date 8485 * @param date Date - the date value to format 8486 * @param settings Object - attributes include: 8487 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8488 * dayNames string[7] - names of the days from Sunday (optional) 8489 * monthNamesShort string[12] - abbreviated names of the months (optional) 8490 * monthNames string[12] - names of the months (optional) 8491 * @return string - the date in the above format 8492 */ 8493 formatDate: function( format, date, settings ) { 8494 if ( !date ) { 8495 return ""; 8496 } 8497 8498 var iFormat, 8499 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8500 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8501 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8502 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8503 8504 // Check whether a format character is doubled 8505 lookAhead = function( match ) { 8506 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8507 if ( matches ) { 8508 iFormat++; 8509 } 8510 return matches; 8511 }, 8512 8513 // Format a number, with leading zero if necessary 8514 formatNumber = function( match, value, len ) { 8515 var num = "" + value; 8516 if ( lookAhead( match ) ) { 8517 while ( num.length < len ) { 8518 num = "0" + num; 8519 } 8520 } 8521 return num; 8522 }, 8523 8524 // Format a name, short or long as requested 8525 formatName = function( match, value, shortNames, longNames ) { 8526 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] ); 8527 }, 8528 output = "", 8529 literal = false; 8530 8531 if ( date ) { 8532 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8533 if ( literal ) { 8534 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8535 literal = false; 8536 } else { 8537 output += format.charAt( iFormat ); 8538 } 8539 } else { 8540 switch ( format.charAt( iFormat ) ) { 8541 case "d": 8542 output += formatNumber( "d", date.getDate(), 2 ); 8543 break; 8544 case "D": 8545 output += formatName( "D", date.getDay(), dayNamesShort, dayNames ); 8546 break; 8547 case "o": 8548 output += formatNumber( "o", 8549 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 8550 break; 8551 case "m": 8552 output += formatNumber( "m", date.getMonth() + 1, 2 ); 8553 break; 8554 case "M": 8555 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames ); 8556 break; 8557 case "y": 8558 output += ( lookAhead( "y" ) ? date.getFullYear() : 8559 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 ); 8560 break; 8561 case "@": 8562 output += date.getTime(); 8563 break; 8564 case "!": 8565 output += date.getTime() * 10000 + this._ticksTo1970; 8566 break; 8567 case "'": 8568 if ( lookAhead( "'" ) ) { 8569 output += "'"; 8570 } else { 8571 literal = true; 8572 } 8573 break; 8574 default: 8575 output += format.charAt( iFormat ); 8576 } 8577 } 8578 } 8579 } 8580 return output; 8581 }, 8582 8583 /* Extract all possible characters from the date format. */ 8584 _possibleChars: function( format ) { 8585 var iFormat, 8586 chars = "", 8587 literal = false, 8588 8589 // Check whether a format character is doubled 8590 lookAhead = function( match ) { 8591 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8592 if ( matches ) { 8593 iFormat++; 8594 } 8595 return matches; 8596 }; 8597 8598 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8599 if ( literal ) { 8600 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8601 literal = false; 8602 } else { 8603 chars += format.charAt( iFormat ); 8604 } 8605 } else { 8606 switch ( format.charAt( iFormat ) ) { 8607 case "d": case "m": case "y": case "@": 8608 chars += "0123456789"; 8609 break; 8610 case "D": case "M": 8611 return null; // Accept anything 8612 case "'": 8613 if ( lookAhead( "'" ) ) { 8614 chars += "'"; 8615 } else { 8616 literal = true; 8617 } 8618 break; 8619 default: 8620 chars += format.charAt( iFormat ); 8621 } 8622 } 8623 } 8624 return chars; 8625 }, 8626 8627 /* Get a setting value, defaulting if necessary. */ 8628 _get: function( inst, name ) { 8629 return inst.settings[ name ] !== undefined ? 8630 inst.settings[ name ] : this._defaults[ name ]; 8631 }, 8632 8633 /* Parse existing date and initialise date picker. */ 8634 _setDateFromField: function( inst, noDefault ) { 8635 if ( inst.input.val() === inst.lastVal ) { 8636 return; 8637 } 8638 8639 var dateFormat = this._get( inst, "dateFormat" ), 8640 dates = inst.lastVal = inst.input ? inst.input.val() : null, 8641 defaultDate = this._getDefaultDate( inst ), 8642 date = defaultDate, 8643 settings = this._getFormatConfig( inst ); 8644 8645 try { 8646 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 8647 } catch ( event ) { 8648 dates = ( noDefault ? "" : dates ); 8649 } 8650 inst.selectedDay = date.getDate(); 8651 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8652 inst.drawYear = inst.selectedYear = date.getFullYear(); 8653 inst.currentDay = ( dates ? date.getDate() : 0 ); 8654 inst.currentMonth = ( dates ? date.getMonth() : 0 ); 8655 inst.currentYear = ( dates ? date.getFullYear() : 0 ); 8656 this._adjustInstDate( inst ); 8657 }, 8658 8659 /* Retrieve the default date shown on opening. */ 8660 _getDefaultDate: function( inst ) { 8661 return this._restrictMinMax( inst, 8662 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) ); 8663 }, 8664 8665 /* A date may be specified as an exact value or a relative one. */ 8666 _determineDate: function( inst, date, defaultDate ) { 8667 var offsetNumeric = function( offset ) { 8668 var date = new Date(); 8669 date.setDate( date.getDate() + offset ); 8670 return date; 8671 }, 8672 offsetString = function( offset ) { 8673 try { 8674 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 8675 offset, $.datepicker._getFormatConfig( inst ) ); 8676 } catch ( e ) { 8677 8678 // Ignore 8679 } 8680 8681 var date = ( offset.toLowerCase().match( /^c/ ) ? 8682 $.datepicker._getDate( inst ) : null ) || new Date(), 8683 year = date.getFullYear(), 8684 month = date.getMonth(), 8685 day = date.getDate(), 8686 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 8687 matches = pattern.exec( offset ); 8688 8689 while ( matches ) { 8690 switch ( matches[ 2 ] || "d" ) { 8691 case "d" : case "D" : 8692 day += parseInt( matches[ 1 ], 10 ); break; 8693 case "w" : case "W" : 8694 day += parseInt( matches[ 1 ], 10 ) * 7; break; 8695 case "m" : case "M" : 8696 month += parseInt( matches[ 1 ], 10 ); 8697 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8698 break; 8699 case "y": case "Y" : 8700 year += parseInt( matches[ 1 ], 10 ); 8701 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8702 break; 8703 } 8704 matches = pattern.exec( offset ); 8705 } 8706 return new Date( year, month, day ); 8707 }, 8708 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) : 8709 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) ); 8710 8711 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate ); 8712 if ( newDate ) { 8713 newDate.setHours( 0 ); 8714 newDate.setMinutes( 0 ); 8715 newDate.setSeconds( 0 ); 8716 newDate.setMilliseconds( 0 ); 8717 } 8718 return this._daylightSavingAdjust( newDate ); 8719 }, 8720 8721 /* Handle switch to/from daylight saving. 8722 * Hours may be non-zero on daylight saving cut-over: 8723 * > 12 when midnight changeover, but then cannot generate 8724 * midnight datetime, so jump to 1AM, otherwise reset. 8725 * @param date (Date) the date to check 8726 * @return (Date) the corrected date 8727 */ 8728 _daylightSavingAdjust: function( date ) { 8729 if ( !date ) { 8730 return null; 8731 } 8732 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 8733 return date; 8734 }, 8735 8736 /* Set the date(s) directly. */ 8737 _setDate: function( inst, date, noChange ) { 8738 var clear = !date, 8739 origMonth = inst.selectedMonth, 8740 origYear = inst.selectedYear, 8741 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 8742 8743 inst.selectedDay = inst.currentDay = newDate.getDate(); 8744 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 8745 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 8746 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) { 8747 this._notifyChange( inst ); 8748 } 8749 this._adjustInstDate( inst ); 8750 if ( inst.input ) { 8751 inst.input.val( clear ? "" : this._formatDate( inst ) ); 8752 } 8753 }, 8754 8755 /* Retrieve the date(s) directly. */ 8756 _getDate: function( inst ) { 8757 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null : 8758 this._daylightSavingAdjust( new Date( 8759 inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 8760 return startDate; 8761 }, 8762 8763 /* Attach the onxxx handlers. These are declared statically so 8764 * they work with static code transformers like Caja. 8765 */ 8766 _attachHandlers: function( inst ) { 8767 var stepMonths = this._get( inst, "stepMonths" ), 8768 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 8769 inst.dpDiv.find( "[data-handler]" ).map( function() { 8770 var handler = { 8771 prev: function() { 8772 $.datepicker._adjustDate( id, -stepMonths, "M" ); 8773 }, 8774 next: function() { 8775 $.datepicker._adjustDate( id, +stepMonths, "M" ); 8776 }, 8777 hide: function() { 8778 $.datepicker._hideDatepicker(); 8779 }, 8780 today: function() { 8781 $.datepicker._gotoToday( id ); 8782 }, 8783 selectDay: function() { 8784 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this ); 8785 return false; 8786 }, 8787 selectMonth: function() { 8788 $.datepicker._selectMonthYear( id, this, "M" ); 8789 return false; 8790 }, 8791 selectYear: function() { 8792 $.datepicker._selectMonthYear( id, this, "Y" ); 8793 return false; 8794 } 8795 }; 8796 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] ); 8797 } ); 8798 }, 8799 8800 /* Generate the HTML for the current state of the date picker. */ 8801 _generateHTML: function( inst ) { 8802 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 8803 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 8804 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 8805 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 8806 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 8807 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 8808 tempDate = new Date(), 8809 today = this._daylightSavingAdjust( 8810 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 8811 isRTL = this._get( inst, "isRTL" ), 8812 showButtonPanel = this._get( inst, "showButtonPanel" ), 8813 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ), 8814 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ), 8815 numMonths = this._getNumberOfMonths( inst ), 8816 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ), 8817 stepMonths = this._get( inst, "stepMonths" ), 8818 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ), 8819 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) : 8820 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ), 8821 minDate = this._getMinMaxDate( inst, "min" ), 8822 maxDate = this._getMinMaxDate( inst, "max" ), 8823 drawMonth = inst.drawMonth - showCurrentAtPos, 8824 drawYear = inst.drawYear; 8825 8826 if ( drawMonth < 0 ) { 8827 drawMonth += 12; 8828 drawYear--; 8829 } 8830 if ( maxDate ) { 8831 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), 8832 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 8833 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw ); 8834 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 8835 drawMonth--; 8836 if ( drawMonth < 0 ) { 8837 drawMonth = 11; 8838 drawYear--; 8839 } 8840 } 8841 } 8842 inst.drawMonth = drawMonth; 8843 inst.drawYear = drawYear; 8844 8845 prevText = this._get( inst, "prevText" ); 8846 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText, 8847 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), 8848 this._getFormatConfig( inst ) ) ); 8849 8850 if ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ) { 8851 prev = $( "<a>" ) 8852 .attr( { 8853 "class": "ui-datepicker-prev ui-corner-all", 8854 "data-handler": "prev", 8855 "data-event": "click", 8856 title: prevText 8857 } ) 8858 .append( 8859 $( "<span>" ) 8860 .addClass( "ui-icon ui-icon-circle-triangle-" + 8861 ( isRTL ? "e" : "w" ) ) 8862 .text( prevText ) 8863 )[ 0 ].outerHTML; 8864 } else if ( hideIfNoPrevNext ) { 8865 prev = ""; 8866 } else { 8867 prev = $( "<a>" ) 8868 .attr( { 8869 "class": "ui-datepicker-prev ui-corner-all ui-state-disabled", 8870 title: prevText 8871 } ) 8872 .append( 8873 $( "<span>" ) 8874 .addClass( "ui-icon ui-icon-circle-triangle-" + 8875 ( isRTL ? "e" : "w" ) ) 8876 .text( prevText ) 8877 )[ 0 ].outerHTML; 8878 } 8879 8880 nextText = this._get( inst, "nextText" ); 8881 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText, 8882 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), 8883 this._getFormatConfig( inst ) ) ); 8884 8885 if ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ) { 8886 next = $( "<a>" ) 8887 .attr( { 8888 "class": "ui-datepicker-next ui-corner-all", 8889 "data-handler": "next", 8890 "data-event": "click", 8891 title: nextText 8892 } ) 8893 .append( 8894 $( "<span>" ) 8895 .addClass( "ui-icon ui-icon-circle-triangle-" + 8896 ( isRTL ? "w" : "e" ) ) 8897 .text( nextText ) 8898 )[ 0 ].outerHTML; 8899 } else if ( hideIfNoPrevNext ) { 8900 next = ""; 8901 } else { 8902 next = $( "<a>" ) 8903 .attr( { 8904 "class": "ui-datepicker-next ui-corner-all ui-state-disabled", 8905 title: nextText 8906 } ) 8907 .append( 8908 $( "<span>" ) 8909 .attr( "class", "ui-icon ui-icon-circle-triangle-" + 8910 ( isRTL ? "w" : "e" ) ) 8911 .text( nextText ) 8912 )[ 0 ].outerHTML; 8913 } 8914 8915 currentText = this._get( inst, "currentText" ); 8916 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today ); 8917 currentText = ( !navigationAsDateFormat ? currentText : 8918 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) ); 8919 8920 controls = ""; 8921 if ( !inst.inline ) { 8922 controls = $( "<button>" ) 8923 .attr( { 8924 type: "button", 8925 "class": "ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all", 8926 "data-handler": "hide", 8927 "data-event": "click" 8928 } ) 8929 .text( this._get( inst, "closeText" ) )[ 0 ].outerHTML; 8930 } 8931 8932 buttonPanel = ""; 8933 if ( showButtonPanel ) { 8934 buttonPanel = $( "<div class='ui-datepicker-buttonpane ui-widget-content'>" ) 8935 .append( isRTL ? controls : "" ) 8936 .append( this._isInRange( inst, gotoDate ) ? 8937 $( "<button>" ) 8938 .attr( { 8939 type: "button", 8940 "class": "ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all", 8941 "data-handler": "today", 8942 "data-event": "click" 8943 } ) 8944 .text( currentText ) : 8945 "" ) 8946 .append( isRTL ? "" : controls )[ 0 ].outerHTML; 8947 } 8948 8949 firstDay = parseInt( this._get( inst, "firstDay" ), 10 ); 8950 firstDay = ( isNaN( firstDay ) ? 0 : firstDay ); 8951 8952 showWeek = this._get( inst, "showWeek" ); 8953 dayNames = this._get( inst, "dayNames" ); 8954 dayNamesMin = this._get( inst, "dayNamesMin" ); 8955 monthNames = this._get( inst, "monthNames" ); 8956 monthNamesShort = this._get( inst, "monthNamesShort" ); 8957 beforeShowDay = this._get( inst, "beforeShowDay" ); 8958 showOtherMonths = this._get( inst, "showOtherMonths" ); 8959 selectOtherMonths = this._get( inst, "selectOtherMonths" ); 8960 defaultDate = this._getDefaultDate( inst ); 8961 html = ""; 8962 8963 for ( row = 0; row < numMonths[ 0 ]; row++ ) { 8964 group = ""; 8965 this.maxRows = 4; 8966 for ( col = 0; col < numMonths[ 1 ]; col++ ) { 8967 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 8968 cornerClass = " ui-corner-all"; 8969 calender = ""; 8970 if ( isMultiMonth ) { 8971 calender += "<div class='ui-datepicker-group"; 8972 if ( numMonths[ 1 ] > 1 ) { 8973 switch ( col ) { 8974 case 0: calender += " ui-datepicker-group-first"; 8975 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break; 8976 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last"; 8977 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break; 8978 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 8979 } 8980 } 8981 calender += "'>"; 8982 } 8983 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 8984 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) + 8985 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) + 8986 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate, 8987 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers 8988 "</div><table class='ui-datepicker-calendar'><thead>" + 8989 "<tr>"; 8990 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" ); 8991 for ( dow = 0; dow < 7; dow++ ) { // days of the week 8992 day = ( dow + firstDay ) % 7; 8993 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" + 8994 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>"; 8995 } 8996 calender += thead + "</tr></thead><tbody>"; 8997 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 8998 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 8999 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 9000 } 9001 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 9002 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate 9003 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043) 9004 this.maxRows = numRows; 9005 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 9006 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows 9007 calender += "<tr>"; 9008 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 9009 this._get( inst, "calculateWeek" )( printDate ) + "</td>" ); 9010 for ( dow = 0; dow < 7; dow++ ) { // create date picker days 9011 daySettings = ( beforeShowDay ? 9012 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] ); 9013 otherMonth = ( printDate.getMonth() !== drawMonth ); 9014 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] || 9015 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 9016 tbody += "<td class='" + 9017 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends 9018 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months 9019 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key 9020 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? 9021 9022 // or defaultDate is current printedDate and defaultDate is selectedDate 9023 " " + this._dayOverClass : "" ) + // highlight selected day 9024 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days 9025 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates 9026 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day 9027 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different) 9028 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title 9029 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions 9030 ( otherMonth && !showOtherMonths ? " " : // display for other months 9031 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 9032 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) + 9033 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day 9034 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months 9035 "' href='#' aria-current='" + ( printDate.getTime() === currentDate.getTime() ? "true" : "false" ) + // mark date as selected for screen reader 9036 "' data-date='" + printDate.getDate() + // store date as data 9037 "'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date 9038 printDate.setDate( printDate.getDate() + 1 ); 9039 printDate = this._daylightSavingAdjust( printDate ); 9040 } 9041 calender += tbody + "</tr>"; 9042 } 9043 drawMonth++; 9044 if ( drawMonth > 11 ) { 9045 drawMonth = 0; 9046 drawYear++; 9047 } 9048 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" + 9049 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" ); 9050 group += calender; 9051 } 9052 html += group; 9053 } 9054 html += buttonPanel; 9055 inst._keyEvent = false; 9056 return html; 9057 }, 9058 9059 /* Generate the month and year header. */ 9060 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, 9061 secondary, monthNames, monthNamesShort ) { 9062 9063 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 9064 changeMonth = this._get( inst, "changeMonth" ), 9065 changeYear = this._get( inst, "changeYear" ), 9066 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ), 9067 selectMonthLabel = this._get( inst, "selectMonthLabel" ), 9068 selectYearLabel = this._get( inst, "selectYearLabel" ), 9069 html = "<div class='ui-datepicker-title'>", 9070 monthHtml = ""; 9071 9072 // Month selection 9073 if ( secondary || !changeMonth ) { 9074 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>"; 9075 } else { 9076 inMinYear = ( minDate && minDate.getFullYear() === drawYear ); 9077 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear ); 9078 monthHtml += "<select class='ui-datepicker-month' aria-label='" + selectMonthLabel + "' data-handler='selectMonth' data-event='change'>"; 9079 for ( month = 0; month < 12; month++ ) { 9080 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) { 9081 monthHtml += "<option value='" + month + "'" + 9082 ( month === drawMonth ? " selected='selected'" : "" ) + 9083 ">" + monthNamesShort[ month ] + "</option>"; 9084 } 9085 } 9086 monthHtml += "</select>"; 9087 } 9088 9089 if ( !showMonthAfterYear ) { 9090 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" ); 9091 } 9092 9093 // Year selection 9094 if ( !inst.yearshtml ) { 9095 inst.yearshtml = ""; 9096 if ( secondary || !changeYear ) { 9097 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 9098 } else { 9099 9100 // determine range of years to display 9101 years = this._get( inst, "yearRange" ).split( ":" ); 9102 thisYear = new Date().getFullYear(); 9103 determineYear = function( value ) { 9104 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : 9105 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) : 9106 parseInt( value, 10 ) ) ); 9107 return ( isNaN( year ) ? thisYear : year ); 9108 }; 9109 year = determineYear( years[ 0 ] ); 9110 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) ); 9111 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year ); 9112 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear ); 9113 inst.yearshtml += "<select class='ui-datepicker-year' aria-label='" + selectYearLabel + "' data-handler='selectYear' data-event='change'>"; 9114 for ( ; year <= endYear; year++ ) { 9115 inst.yearshtml += "<option value='" + year + "'" + 9116 ( year === drawYear ? " selected='selected'" : "" ) + 9117 ">" + year + "</option>"; 9118 } 9119 inst.yearshtml += "</select>"; 9120 9121 html += inst.yearshtml; 9122 inst.yearshtml = null; 9123 } 9124 } 9125 9126 html += this._get( inst, "yearSuffix" ); 9127 if ( showMonthAfterYear ) { 9128 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml; 9129 } 9130 html += "</div>"; // Close datepicker_header 9131 return html; 9132 }, 9133 9134 /* Adjust one of the date sub-fields. */ 9135 _adjustInstDate: function( inst, offset, period ) { 9136 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ), 9137 month = inst.selectedMonth + ( period === "M" ? offset : 0 ), 9138 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ), 9139 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 9140 9141 inst.selectedDay = date.getDate(); 9142 inst.drawMonth = inst.selectedMonth = date.getMonth(); 9143 inst.drawYear = inst.selectedYear = date.getFullYear(); 9144 if ( period === "M" || period === "Y" ) { 9145 this._notifyChange( inst ); 9146 } 9147 }, 9148 9149 /* Ensure a date is within any min/max bounds. */ 9150 _restrictMinMax: function( inst, date ) { 9151 var minDate = this._getMinMaxDate( inst, "min" ), 9152 maxDate = this._getMinMaxDate( inst, "max" ), 9153 newDate = ( minDate && date < minDate ? minDate : date ); 9154 return ( maxDate && newDate > maxDate ? maxDate : newDate ); 9155 }, 9156 9157 /* Notify change of month/year. */ 9158 _notifyChange: function( inst ) { 9159 var onChange = this._get( inst, "onChangeMonthYear" ); 9160 if ( onChange ) { 9161 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ), 9162 [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 9163 } 9164 }, 9165 9166 /* Determine the number of months to show. */ 9167 _getNumberOfMonths: function( inst ) { 9168 var numMonths = this._get( inst, "numberOfMonths" ); 9169 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) ); 9170 }, 9171 9172 /* Determine the current maximum date - ensure no time components are set. */ 9173 _getMinMaxDate: function( inst, minMax ) { 9174 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null ); 9175 }, 9176 9177 /* Find the number of days in a given month. */ 9178 _getDaysInMonth: function( year, month ) { 9179 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 9180 }, 9181 9182 /* Find the day of the week of the first of a month. */ 9183 _getFirstDayOfMonth: function( year, month ) { 9184 return new Date( year, month, 1 ).getDay(); 9185 }, 9186 9187 /* Determines if we should allow a "next/prev" month display change. */ 9188 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 9189 var numMonths = this._getNumberOfMonths( inst ), 9190 date = this._daylightSavingAdjust( new Date( curYear, 9191 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 9192 9193 if ( offset < 0 ) { 9194 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 9195 } 9196 return this._isInRange( inst, date ); 9197 }, 9198 9199 /* Is the given date in the accepted range? */ 9200 _isInRange: function( inst, date ) { 9201 var yearSplit, currentYear, 9202 minDate = this._getMinMaxDate( inst, "min" ), 9203 maxDate = this._getMinMaxDate( inst, "max" ), 9204 minYear = null, 9205 maxYear = null, 9206 years = this._get( inst, "yearRange" ); 9207 if ( years ) { 9208 yearSplit = years.split( ":" ); 9209 currentYear = new Date().getFullYear(); 9210 minYear = parseInt( yearSplit[ 0 ], 10 ); 9211 maxYear = parseInt( yearSplit[ 1 ], 10 ); 9212 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) { 9213 minYear += currentYear; 9214 } 9215 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) { 9216 maxYear += currentYear; 9217 } 9218 } 9219 9220 return ( ( !minDate || date.getTime() >= minDate.getTime() ) && 9221 ( !maxDate || date.getTime() <= maxDate.getTime() ) && 9222 ( !minYear || date.getFullYear() >= minYear ) && 9223 ( !maxYear || date.getFullYear() <= maxYear ) ); 9224 }, 9225 9226 /* Provide the configuration settings for formatting/parsing. */ 9227 _getFormatConfig: function( inst ) { 9228 var shortYearCutoff = this._get( inst, "shortYearCutoff" ); 9229 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff : 9230 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) ); 9231 return { shortYearCutoff: shortYearCutoff, 9232 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ), 9233 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) }; 9234 }, 9235 9236 /* Format the given date for display. */ 9237 _formatDate: function( inst, day, month, year ) { 9238 if ( !day ) { 9239 inst.currentDay = inst.selectedDay; 9240 inst.currentMonth = inst.selectedMonth; 9241 inst.currentYear = inst.selectedYear; 9242 } 9243 var date = ( day ? ( typeof day === "object" ? day : 9244 this._daylightSavingAdjust( new Date( year, month, day ) ) ) : 9245 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 9246 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) ); 9247 } 9248 } ); 9249 9250 /* 9251 * Bind hover events for datepicker elements. 9252 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 9253 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 9254 */ 9255 function datepicker_bindHover( dpDiv ) { 9256 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 9257 return dpDiv.on( "mouseout", selector, function() { 9258 $( this ).removeClass( "ui-state-hover" ); 9259 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9260 $( this ).removeClass( "ui-datepicker-prev-hover" ); 9261 } 9262 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9263 $( this ).removeClass( "ui-datepicker-next-hover" ); 9264 } 9265 } ) 9266 .on( "mouseover", selector, datepicker_handleMouseover ); 9267 } 9268 9269 function datepicker_handleMouseover() { 9270 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 9271 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" ); 9272 $( this ).addClass( "ui-state-hover" ); 9273 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9274 $( this ).addClass( "ui-datepicker-prev-hover" ); 9275 } 9276 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9277 $( this ).addClass( "ui-datepicker-next-hover" ); 9278 } 9279 } 9280 } 9281 9282 /* jQuery extend now ignores nulls! */ 9283 function datepicker_extendRemove( target, props ) { 9284 $.extend( target, props ); 9285 for ( var name in props ) { 9286 if ( props[ name ] == null ) { 9287 target[ name ] = props[ name ]; 9288 } 9289 } 9290 return target; 9291 } 9292 9293 /* Invoke the datepicker functionality. 9294 @param options string - a command, optionally followed by additional parameters or 9295 Object - settings for attaching new datepicker functionality 9296 @return jQuery object */ 9297 $.fn.datepicker = function( options ) { 9298 9299 /* Verify an empty collection wasn't passed - Fixes #6976 */ 9300 if ( !this.length ) { 9301 return this; 9302 } 9303 9304 /* Initialise the date picker. */ 9305 if ( !$.datepicker.initialized ) { 9306 $( document ).on( "mousedown", $.datepicker._checkExternalClick ); 9307 $.datepicker.initialized = true; 9308 } 9309 9310 /* Append datepicker main container to body if not exist. */ 9311 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) { 9312 $( "body" ).append( $.datepicker.dpDiv ); 9313 } 9314 9315 var otherArgs = Array.prototype.slice.call( arguments, 1 ); 9316 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) { 9317 return $.datepicker[ "_" + options + "Datepicker" ]. 9318 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9319 } 9320 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) { 9321 return $.datepicker[ "_" + options + "Datepicker" ]. 9322 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9323 } 9324 return this.each( function() { 9325 if ( typeof options === "string" ) { 9326 $.datepicker[ "_" + options + "Datepicker" ] 9327 .apply( $.datepicker, [ this ].concat( otherArgs ) ); 9328 } else { 9329 $.datepicker._attachDatepicker( this, options ); 9330 } 9331 } ); 9332 }; 9333 9334 $.datepicker = new Datepicker(); // singleton instance 9335 $.datepicker.initialized = false; 9336 $.datepicker.uuid = new Date().getTime(); 9337 $.datepicker.version = "1.14.1"; 9338 9339 var widgetsDatepicker = $.datepicker; 9340 9341 9342 /*! 9343 * jQuery UI Mouse 1.14.1 9344 * https://jqueryui.com 9345 * 9346 * Copyright OpenJS Foundation and other contributors 9347 * Released under the MIT license. 9348 * https://jquery.org/license 9349 */ 9350 9351//>>label: Mouse 9352//>>group: Widgets 9353//>>description: Abstracts mouse-based interactions to assist in creating certain widgets. 9354//>>docs: https://api.jqueryui.com/mouse/ 9355 9356 9357 var mouseHandled = false; 9358 $( document ).on( "mouseup", function() { 9359 mouseHandled = false; 9360 } ); 9361 9362 var widgetsMouse = $.widget( "ui.mouse", { 9363 version: "1.14.1", 9364 options: { 9365 cancel: "input, textarea, button, select, option", 9366 distance: 1, 9367 delay: 0 9368 }, 9369 _mouseInit: function() { 9370 var that = this; 9371 9372 this.element 9373 .on( "mousedown." + this.widgetName, function( event ) { 9374 return that._mouseDown( event ); 9375 } ) 9376 .on( "click." + this.widgetName, function( event ) { 9377 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { 9378 $.removeData( event.target, that.widgetName + ".preventClickEvent" ); 9379 event.stopImmediatePropagation(); 9380 return false; 9381 } 9382 } ); 9383 9384 this.started = false; 9385 }, 9386 9387 // TODO: make sure destroying one instance of mouse doesn't mess with 9388 // other instances of mouse 9389 _mouseDestroy: function() { 9390 this.element.off( "." + this.widgetName ); 9391 if ( this._mouseMoveDelegate ) { 9392 this.document 9393 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9394 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9395 } 9396 }, 9397 9398 _mouseDown: function( event ) { 9399 9400 // don't let more than one widget handle mouseStart 9401 if ( mouseHandled ) { 9402 return; 9403 } 9404 9405 this._mouseMoved = false; 9406 9407 // We may have missed mouseup (out of window) 9408 if ( this._mouseStarted ) { 9409 this._mouseUp( event ); 9410 } 9411 9412 this._mouseDownEvent = event; 9413 9414 var that = this, 9415 btnIsLeft = event.which === 1, 9416 elIsCancel = typeof this.options.cancel === "string" ? 9417 $( event.target ).closest( this.options.cancel ).length : 9418 false; 9419 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { 9420 return true; 9421 } 9422 9423 this.mouseDelayMet = !this.options.delay; 9424 if ( !this.mouseDelayMet ) { 9425 this._mouseDelayTimer = setTimeout( function() { 9426 that.mouseDelayMet = true; 9427 }, this.options.delay ); 9428 } 9429 9430 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9431 this._mouseStarted = ( this._mouseStart( event ) !== false ); 9432 if ( !this._mouseStarted ) { 9433 event.preventDefault(); 9434 return true; 9435 } 9436 } 9437 9438 // Click event may never have fired (Gecko & Opera) 9439 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { 9440 $.removeData( event.target, this.widgetName + ".preventClickEvent" ); 9441 } 9442 9443 // These delegates are required to keep context 9444 this._mouseMoveDelegate = function( event ) { 9445 return that._mouseMove( event ); 9446 }; 9447 this._mouseUpDelegate = function( event ) { 9448 return that._mouseUp( event ); 9449 }; 9450 9451 this.document 9452 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9453 .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9454 9455 event.preventDefault(); 9456 9457 mouseHandled = true; 9458 return true; 9459 }, 9460 9461 _mouseMove: function( event ) { 9462 9463 // Only check for mouseups outside the document if you've moved inside the document 9464 // at least once. 9465 if ( this._mouseMoved && !event.which ) { 9466 9467 // Support: Safari <=8 - 9 9468 // Safari sets which to 0 if you press any of the following keys 9469 // during a drag (#14461) 9470 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || 9471 event.originalEvent.metaKey || event.originalEvent.shiftKey ) { 9472 this.ignoreMissingWhich = true; 9473 } else if ( !this.ignoreMissingWhich ) { 9474 return this._mouseUp( event ); 9475 } 9476 } 9477 9478 if ( event.which || event.button ) { 9479 this._mouseMoved = true; 9480 } 9481 9482 if ( this._mouseStarted ) { 9483 this._mouseDrag( event ); 9484 return event.preventDefault(); 9485 } 9486 9487 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9488 this._mouseStarted = 9489 ( this._mouseStart( this._mouseDownEvent, event ) !== false ); 9490 if ( this._mouseStarted ) { 9491 this._mouseDrag( event ); 9492 } else { 9493 this._mouseUp( event ); 9494 } 9495 } 9496 9497 return !this._mouseStarted; 9498 }, 9499 9500 _mouseUp: function( event ) { 9501 this.document 9502 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9503 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9504 9505 if ( this._mouseStarted ) { 9506 this._mouseStarted = false; 9507 9508 if ( event.target === this._mouseDownEvent.target ) { 9509 $.data( event.target, this.widgetName + ".preventClickEvent", true ); 9510 } 9511 9512 this._mouseStop( event ); 9513 } 9514 9515 if ( this._mouseDelayTimer ) { 9516 clearTimeout( this._mouseDelayTimer ); 9517 delete this._mouseDelayTimer; 9518 } 9519 9520 this.ignoreMissingWhich = false; 9521 mouseHandled = false; 9522 event.preventDefault(); 9523 }, 9524 9525 _mouseDistanceMet: function( event ) { 9526 return ( Math.max( 9527 Math.abs( this._mouseDownEvent.pageX - event.pageX ), 9528 Math.abs( this._mouseDownEvent.pageY - event.pageY ) 9529 ) >= this.options.distance 9530 ); 9531 }, 9532 9533 _mouseDelayMet: function( /* event */ ) { 9534 return this.mouseDelayMet; 9535 }, 9536 9537 // These are placeholder methods, to be overriden by extending plugin 9538 _mouseStart: function( /* event */ ) {}, 9539 _mouseDrag: function( /* event */ ) {}, 9540 _mouseStop: function( /* event */ ) {}, 9541 _mouseCapture: function( /* event */ ) { 9542 return true; 9543 } 9544 } ); 9545 9546 9547 9548// $.ui.plugin is deprecated. Use $.widget() extensions instead. 9549 var plugin = $.ui.plugin = { 9550 add: function( module, option, set ) { 9551 var i, 9552 proto = $.ui[ module ].prototype; 9553 for ( i in set ) { 9554 proto.plugins[ i ] = proto.plugins[ i ] || []; 9555 proto.plugins[ i ].push( [ option, set[ i ] ] ); 9556 } 9557 }, 9558 call: function( instance, name, args, allowDisconnected ) { 9559 var i, 9560 set = instance.plugins[ name ]; 9561 9562 if ( !set ) { 9563 return; 9564 } 9565 9566 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || 9567 instance.element[ 0 ].parentNode.nodeType === 11 ) ) { 9568 return; 9569 } 9570 9571 for ( i = 0; i < set.length; i++ ) { 9572 if ( instance.options[ set[ i ][ 0 ] ] ) { 9573 set[ i ][ 1 ].apply( instance.element, args ); 9574 } 9575 } 9576 } 9577 }; 9578 9579 9580 /*! 9581 * jQuery UI Draggable 1.14.1 9582 * https://jqueryui.com 9583 * 9584 * Copyright OpenJS Foundation and other contributors 9585 * Released under the MIT license. 9586 * https://jquery.org/license 9587 */ 9588 9589//>>label: Draggable 9590//>>group: Interactions 9591//>>description: Enables dragging functionality for any element. 9592//>>docs: https://api.jqueryui.com/draggable/ 9593//>>demos: https://jqueryui.com/draggable/ 9594//>>css.structure: ../../themes/base/draggable.css 9595 9596 9597 $.widget( "ui.draggable", $.ui.mouse, { 9598 version: "1.14.1", 9599 widgetEventPrefix: "drag", 9600 options: { 9601 addClasses: true, 9602 appendTo: "parent", 9603 axis: false, 9604 connectToSortable: false, 9605 containment: false, 9606 cursor: "auto", 9607 cursorAt: false, 9608 grid: false, 9609 handle: false, 9610 helper: "original", 9611 iframeFix: false, 9612 opacity: false, 9613 refreshPositions: false, 9614 revert: false, 9615 revertDuration: 500, 9616 scope: "default", 9617 scroll: true, 9618 scrollSensitivity: 20, 9619 scrollSpeed: 20, 9620 snap: false, 9621 snapMode: "both", 9622 snapTolerance: 20, 9623 stack: false, 9624 zIndex: false, 9625 9626 // Callbacks 9627 drag: null, 9628 start: null, 9629 stop: null 9630 }, 9631 _create: function() { 9632 9633 if ( this.options.helper === "original" ) { 9634 this._setPositionRelative(); 9635 } 9636 if ( this.options.addClasses ) { 9637 this._addClass( "ui-draggable" ); 9638 } 9639 this._setHandleClassName(); 9640 9641 this._mouseInit(); 9642 }, 9643 9644 _setOption: function( key, value ) { 9645 this._super( key, value ); 9646 if ( key === "handle" ) { 9647 this._removeHandleClassName(); 9648 this._setHandleClassName(); 9649 } 9650 }, 9651 9652 _destroy: function() { 9653 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { 9654 this.destroyOnClear = true; 9655 return; 9656 } 9657 this._removeHandleClassName(); 9658 this._mouseDestroy(); 9659 }, 9660 9661 _mouseCapture: function( event ) { 9662 var o = this.options; 9663 9664 // Among others, prevent a drag on a resizable-handle 9665 if ( this.helper || o.disabled || 9666 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) { 9667 return false; 9668 } 9669 9670 //Quit if we're not on a valid handle 9671 this.handle = this._getHandle( event ); 9672 if ( !this.handle ) { 9673 return false; 9674 } 9675 9676 this._blurActiveElement( event ); 9677 9678 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); 9679 9680 return true; 9681 9682 }, 9683 9684 _blockFrames: function( selector ) { 9685 this.iframeBlocks = this.document.find( selector ).map( function() { 9686 var iframe = $( this ); 9687 9688 return $( "<div>" ) 9689 .css( "position", "absolute" ) 9690 .appendTo( iframe.parent() ) 9691 .outerWidth( iframe.outerWidth() ) 9692 .outerHeight( iframe.outerHeight() ) 9693 .offset( iframe.offset() )[ 0 ]; 9694 } ); 9695 }, 9696 9697 _unblockFrames: function() { 9698 if ( this.iframeBlocks ) { 9699 this.iframeBlocks.remove(); 9700 delete this.iframeBlocks; 9701 } 9702 }, 9703 9704 _blurActiveElement: function( event ) { 9705 var activeElement = this.document[ 0 ].activeElement, 9706 target = $( event.target ); 9707 9708 // Don't blur if the event occurred on an element that is within 9709 // the currently focused element 9710 // See #10527, #12472 9711 if ( target.closest( activeElement ).length ) { 9712 return; 9713 } 9714 9715 // Blur any element that currently has focus, see #4261 9716 $( activeElement ).trigger( "blur" ); 9717 }, 9718 9719 _mouseStart: function( event ) { 9720 9721 var o = this.options; 9722 9723 //Create and append the visible helper 9724 this.helper = this._createHelper( event ); 9725 9726 this._addClass( this.helper, "ui-draggable-dragging" ); 9727 9728 //Cache the helper size 9729 this._cacheHelperProportions(); 9730 9731 //If ddmanager is used for droppables, set the global draggable 9732 if ( $.ui.ddmanager ) { 9733 $.ui.ddmanager.current = this; 9734 } 9735 9736 /* 9737 * - Position generation - 9738 * This block generates everything position related - it's the core of draggables. 9739 */ 9740 9741 //Cache the margins of the original element 9742 this._cacheMargins(); 9743 9744 //Store the helper's css position 9745 this.cssPosition = this.helper.css( "position" ); 9746 this.scrollParent = this.helper.scrollParent( true ); 9747 this.offsetParent = this.helper.offsetParent(); 9748 this.hasFixedAncestor = this.helper.parents().filter( function() { 9749 return $( this ).css( "position" ) === "fixed"; 9750 } ).length > 0; 9751 9752 //The element's absolute position on the page minus margins 9753 this.positionAbs = this.element.offset(); 9754 this._refreshOffsets( event ); 9755 9756 //Generate the original position 9757 this.originalPosition = this.position = this._generatePosition( event, false ); 9758 this.originalPageX = event.pageX; 9759 this.originalPageY = event.pageY; 9760 9761 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 9762 if ( o.cursorAt ) { 9763 this._adjustOffsetFromHelper( o.cursorAt ); 9764 } 9765 9766 //Set a containment if given in the options 9767 this._setContainment(); 9768 9769 //Trigger event + callbacks 9770 if ( this._trigger( "start", event ) === false ) { 9771 this._clear(); 9772 return false; 9773 } 9774 9775 //Recache the helper size 9776 this._cacheHelperProportions(); 9777 9778 //Prepare the droppable offsets 9779 if ( $.ui.ddmanager && !o.dropBehaviour ) { 9780 $.ui.ddmanager.prepareOffsets( this, event ); 9781 } 9782 9783 // Execute the drag once - this causes the helper not to be visible before getting its 9784 // correct position 9785 this._mouseDrag( event, true ); 9786 9787 // If the ddmanager is used for droppables, inform the manager that dragging has started 9788 // (see #5003) 9789 if ( $.ui.ddmanager ) { 9790 $.ui.ddmanager.dragStart( this, event ); 9791 } 9792 9793 return true; 9794 }, 9795 9796 _refreshOffsets: function( event ) { 9797 this.offset = { 9798 top: this.positionAbs.top - this.margins.top, 9799 left: this.positionAbs.left - this.margins.left, 9800 scroll: false, 9801 parent: this._getParentOffset(), 9802 relative: this._getRelativeOffset() 9803 }; 9804 9805 this.offset.click = { 9806 left: event.pageX - this.offset.left, 9807 top: event.pageY - this.offset.top 9808 }; 9809 }, 9810 9811 _mouseDrag: function( event, noPropagation ) { 9812 9813 // reset any necessary cached properties (see #5009) 9814 if ( this.hasFixedAncestor ) { 9815 this.offset.parent = this._getParentOffset(); 9816 } 9817 9818 //Compute the helpers position 9819 this.position = this._generatePosition( event, true ); 9820 this.positionAbs = this._convertPositionTo( "absolute" ); 9821 9822 //Call plugins and callbacks and use the resulting position if something is returned 9823 if ( !noPropagation ) { 9824 var ui = this._uiHash(); 9825 if ( this._trigger( "drag", event, ui ) === false ) { 9826 this._mouseUp( new $.Event( "mouseup", event ) ); 9827 return false; 9828 } 9829 this.position = ui.position; 9830 } 9831 9832 this.helper[ 0 ].style.left = this.position.left + "px"; 9833 this.helper[ 0 ].style.top = this.position.top + "px"; 9834 9835 if ( $.ui.ddmanager ) { 9836 $.ui.ddmanager.drag( this, event ); 9837 } 9838 9839 return false; 9840 }, 9841 9842 _mouseStop: function( event ) { 9843 9844 //If we are using droppables, inform the manager about the drop 9845 var that = this, 9846 dropped = false; 9847 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 9848 dropped = $.ui.ddmanager.drop( this, event ); 9849 } 9850 9851 //if a drop comes from outside (a sortable) 9852 if ( this.dropped ) { 9853 dropped = this.dropped; 9854 this.dropped = false; 9855 } 9856 9857 if ( ( this.options.revert === "invalid" && !dropped ) || 9858 ( this.options.revert === "valid" && dropped ) || 9859 this.options.revert === true || ( typeof this.options.revert === "function" && 9860 this.options.revert.call( this.element, dropped ) ) 9861 ) { 9862 $( this.helper ).animate( 9863 this.originalPosition, 9864 parseInt( this.options.revertDuration, 10 ), 9865 function() { 9866 if ( that._trigger( "stop", event ) !== false ) { 9867 that._clear(); 9868 } 9869 } 9870 ); 9871 } else { 9872 if ( this._trigger( "stop", event ) !== false ) { 9873 this._clear(); 9874 } 9875 } 9876 9877 return false; 9878 }, 9879 9880 _mouseUp: function( event ) { 9881 this._unblockFrames(); 9882 9883 // If the ddmanager is used for droppables, inform the manager that dragging has stopped 9884 // (see #5003) 9885 if ( $.ui.ddmanager ) { 9886 $.ui.ddmanager.dragStop( this, event ); 9887 } 9888 9889 // Only need to focus if the event occurred on the draggable itself, see #10527 9890 if ( this.handleElement.is( event.target ) ) { 9891 9892 // The interaction is over; whether or not the click resulted in a drag, 9893 // focus the element 9894 this.element.trigger( "focus" ); 9895 } 9896 9897 return $.ui.mouse.prototype._mouseUp.call( this, event ); 9898 }, 9899 9900 cancel: function() { 9901 9902 if ( this.helper.is( ".ui-draggable-dragging" ) ) { 9903 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) ); 9904 } else { 9905 this._clear(); 9906 } 9907 9908 return this; 9909 9910 }, 9911 9912 _getHandle: function( event ) { 9913 return this.options.handle ? 9914 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : 9915 true; 9916 }, 9917 9918 _setHandleClassName: function() { 9919 this.handleElement = this.options.handle ? 9920 this.element.find( this.options.handle ) : this.element; 9921 this._addClass( this.handleElement, "ui-draggable-handle" ); 9922 }, 9923 9924 _removeHandleClassName: function() { 9925 this._removeClass( this.handleElement, "ui-draggable-handle" ); 9926 }, 9927 9928 _createHelper: function( event ) { 9929 9930 var o = this.options, 9931 helperIsFunction = typeof o.helper === "function", 9932 helper = helperIsFunction ? 9933 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : 9934 ( o.helper === "clone" ? 9935 this.element.clone().removeAttr( "id" ) : 9936 this.element ); 9937 9938 if ( !helper.parents( "body" ).length ) { 9939 helper.appendTo( ( o.appendTo === "parent" ? 9940 this.element[ 0 ].parentNode : 9941 o.appendTo ) ); 9942 } 9943 9944 // https://bugs.jqueryui.com/ticket/9446 9945 // a helper function can return the original element 9946 // which wouldn't have been set to relative in _create 9947 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { 9948 this._setPositionRelative(); 9949 } 9950 9951 if ( helper[ 0 ] !== this.element[ 0 ] && 9952 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) { 9953 helper.css( "position", "absolute" ); 9954 } 9955 9956 return helper; 9957 9958 }, 9959 9960 _setPositionRelative: function() { 9961 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { 9962 this.element[ 0 ].style.position = "relative"; 9963 } 9964 }, 9965 9966 _adjustOffsetFromHelper: function( obj ) { 9967 if ( typeof obj === "string" ) { 9968 obj = obj.split( " " ); 9969 } 9970 if ( Array.isArray( obj ) ) { 9971 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 9972 } 9973 if ( "left" in obj ) { 9974 this.offset.click.left = obj.left + this.margins.left; 9975 } 9976 if ( "right" in obj ) { 9977 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 9978 } 9979 if ( "top" in obj ) { 9980 this.offset.click.top = obj.top + this.margins.top; 9981 } 9982 if ( "bottom" in obj ) { 9983 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 9984 } 9985 }, 9986 9987 _isRootNode: function( element ) { 9988 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; 9989 }, 9990 9991 _getParentOffset: function() { 9992 9993 //Get the offsetParent and cache its position 9994 var po = this.offsetParent.offset(), 9995 document = this.document[ 0 ]; 9996 9997 // This is a special case where we need to modify a offset calculated on start, since the 9998 // following happened: 9999 // 1. The position of the helper is absolute, so it's position is calculated based on the 10000 // next positioned parent 10001 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 10002 // the document, which means that the scroll is included in the initial calculation of the 10003 // offset of the parent, and never recalculated upon drag 10004 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document && 10005 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 10006 po.left += this.scrollParent.scrollLeft(); 10007 po.top += this.scrollParent.scrollTop(); 10008 } 10009 10010 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { 10011 po = { top: 0, left: 0 }; 10012 } 10013 10014 return { 10015 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 10016 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 10017 }; 10018 10019 }, 10020 10021 _getRelativeOffset: function() { 10022 if ( this.cssPosition !== "relative" ) { 10023 return { top: 0, left: 0 }; 10024 } 10025 10026 var p = this.element.position(), 10027 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 10028 10029 return { 10030 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 10031 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), 10032 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 10033 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) 10034 }; 10035 10036 }, 10037 10038 _cacheMargins: function() { 10039 this.margins = { 10040 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ), 10041 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ), 10042 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ), 10043 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 ) 10044 }; 10045 }, 10046 10047 _cacheHelperProportions: function() { 10048 this.helperProportions = { 10049 width: this.helper.outerWidth(), 10050 height: this.helper.outerHeight() 10051 }; 10052 }, 10053 10054 _setContainment: function() { 10055 10056 var isUserScrollable, c, ce, 10057 o = this.options, 10058 document = this.document[ 0 ]; 10059 10060 this.relativeContainer = null; 10061 10062 if ( !o.containment ) { 10063 this.containment = null; 10064 return; 10065 } 10066 10067 if ( o.containment === "window" ) { 10068 this.containment = [ 10069 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 10070 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, 10071 $( window ).scrollLeft() + $( window ).width() - 10072 this.helperProportions.width - this.margins.left, 10073 $( window ).scrollTop() + 10074 ( $( window ).height() || document.body.parentNode.scrollHeight ) - 10075 this.helperProportions.height - this.margins.top 10076 ]; 10077 return; 10078 } 10079 10080 if ( o.containment === "document" ) { 10081 this.containment = [ 10082 0, 10083 0, 10084 $( document ).width() - this.helperProportions.width - this.margins.left, 10085 ( $( document ).height() || document.body.parentNode.scrollHeight ) - 10086 this.helperProportions.height - this.margins.top 10087 ]; 10088 return; 10089 } 10090 10091 if ( o.containment.constructor === Array ) { 10092 this.containment = o.containment; 10093 return; 10094 } 10095 10096 if ( o.containment === "parent" ) { 10097 o.containment = this.helper[ 0 ].parentNode; 10098 } 10099 10100 c = $( o.containment ); 10101 ce = c[ 0 ]; 10102 10103 if ( !ce ) { 10104 return; 10105 } 10106 10107 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); 10108 10109 this.containment = [ 10110 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + 10111 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), 10112 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + 10113 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), 10114 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 10115 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - 10116 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - 10117 this.helperProportions.width - 10118 this.margins.left - 10119 this.margins.right, 10120 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 10121 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - 10122 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - 10123 this.helperProportions.height - 10124 this.margins.top - 10125 this.margins.bottom 10126 ]; 10127 this.relativeContainer = c; 10128 }, 10129 10130 _convertPositionTo: function( d, pos ) { 10131 10132 if ( !pos ) { 10133 pos = this.position; 10134 } 10135 10136 var mod = d === "absolute" ? 1 : -1, 10137 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 10138 10139 return { 10140 top: ( 10141 10142 // The absolute mouse position 10143 pos.top + 10144 10145 // Only for relative positioned nodes: Relative offset from element to offset parent 10146 this.offset.relative.top * mod + 10147 10148 // The offsetParent's offset without borders (offset + border) 10149 this.offset.parent.top * mod - 10150 ( ( this.cssPosition === "fixed" ? 10151 -this.offset.scroll.top : 10152 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod ) 10153 ), 10154 left: ( 10155 10156 // The absolute mouse position 10157 pos.left + 10158 10159 // Only for relative positioned nodes: Relative offset from element to offset parent 10160 this.offset.relative.left * mod + 10161 10162 // The offsetParent's offset without borders (offset + border) 10163 this.offset.parent.left * mod - 10164 ( ( this.cssPosition === "fixed" ? 10165 -this.offset.scroll.left : 10166 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod ) 10167 ) 10168 }; 10169 10170 }, 10171 10172 _generatePosition: function( event, constrainPosition ) { 10173 10174 var containment, co, top, left, 10175 o = this.options, 10176 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), 10177 pageX = event.pageX, 10178 pageY = event.pageY; 10179 10180 // Cache the scroll 10181 if ( !scrollIsRootNode || !this.offset.scroll ) { 10182 this.offset.scroll = { 10183 top: this.scrollParent.scrollTop(), 10184 left: this.scrollParent.scrollLeft() 10185 }; 10186 } 10187 10188 /* 10189 * - Position constraining - 10190 * Constrain the position to a mix of grid, containment. 10191 */ 10192 10193 // If we are not dragging yet, we won't check for options 10194 if ( constrainPosition ) { 10195 if ( this.containment ) { 10196 if ( this.relativeContainer ) { 10197 co = this.relativeContainer.offset(); 10198 containment = [ 10199 this.containment[ 0 ] + co.left, 10200 this.containment[ 1 ] + co.top, 10201 this.containment[ 2 ] + co.left, 10202 this.containment[ 3 ] + co.top 10203 ]; 10204 } else { 10205 containment = this.containment; 10206 } 10207 10208 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) { 10209 pageX = containment[ 0 ] + this.offset.click.left; 10210 } 10211 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) { 10212 pageY = containment[ 1 ] + this.offset.click.top; 10213 } 10214 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) { 10215 pageX = containment[ 2 ] + this.offset.click.left; 10216 } 10217 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) { 10218 pageY = containment[ 3 ] + this.offset.click.top; 10219 } 10220 } 10221 10222 if ( o.grid ) { 10223 10224 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid 10225 // argument errors in IE (see ticket #6950) 10226 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY - 10227 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY; 10228 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] || 10229 top - this.offset.click.top > containment[ 3 ] ) ? 10230 top : 10231 ( ( top - this.offset.click.top >= containment[ 1 ] ) ? 10232 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top; 10233 10234 left = o.grid[ 0 ] ? this.originalPageX + 10235 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] : 10236 this.originalPageX; 10237 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] || 10238 left - this.offset.click.left > containment[ 2 ] ) ? 10239 left : 10240 ( ( left - this.offset.click.left >= containment[ 0 ] ) ? 10241 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left; 10242 } 10243 10244 if ( o.axis === "y" ) { 10245 pageX = this.originalPageX; 10246 } 10247 10248 if ( o.axis === "x" ) { 10249 pageY = this.originalPageY; 10250 } 10251 } 10252 10253 return { 10254 top: ( 10255 10256 // The absolute mouse position 10257 pageY - 10258 10259 // Click offset (relative to the element) 10260 this.offset.click.top - 10261 10262 // Only for relative positioned nodes: Relative offset from element to offset parent 10263 this.offset.relative.top - 10264 10265 // The offsetParent's offset without borders (offset + border) 10266 this.offset.parent.top + 10267 ( this.cssPosition === "fixed" ? 10268 -this.offset.scroll.top : 10269 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) 10270 ), 10271 left: ( 10272 10273 // The absolute mouse position 10274 pageX - 10275 10276 // Click offset (relative to the element) 10277 this.offset.click.left - 10278 10279 // Only for relative positioned nodes: Relative offset from element to offset parent 10280 this.offset.relative.left - 10281 10282 // The offsetParent's offset without borders (offset + border) 10283 this.offset.parent.left + 10284 ( this.cssPosition === "fixed" ? 10285 -this.offset.scroll.left : 10286 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) 10287 ) 10288 }; 10289 10290 }, 10291 10292 _clear: function() { 10293 this._removeClass( this.helper, "ui-draggable-dragging" ); 10294 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) { 10295 this.helper.remove(); 10296 } 10297 this.helper = null; 10298 this.cancelHelperRemoval = false; 10299 if ( this.destroyOnClear ) { 10300 this.destroy(); 10301 } 10302 }, 10303 10304 // From now on bulk stuff - mainly helpers 10305 10306 _trigger: function( type, event, ui ) { 10307 ui = ui || this._uiHash(); 10308 $.ui.plugin.call( this, type, [ event, ui, this ], true ); 10309 10310 // Absolute position and offset (see #6884 ) have to be recalculated after plugins 10311 if ( /^(drag|start|stop)/.test( type ) ) { 10312 this.positionAbs = this._convertPositionTo( "absolute" ); 10313 ui.offset = this.positionAbs; 10314 } 10315 return $.Widget.prototype._trigger.call( this, type, event, ui ); 10316 }, 10317 10318 plugins: {}, 10319 10320 _uiHash: function() { 10321 return { 10322 helper: this.helper, 10323 position: this.position, 10324 originalPosition: this.originalPosition, 10325 offset: this.positionAbs 10326 }; 10327 } 10328 10329 } ); 10330 10331 $.ui.plugin.add( "draggable", "connectToSortable", { 10332 start: function( event, ui, draggable ) { 10333 var uiSortable = $.extend( {}, ui, { 10334 item: draggable.element 10335 } ); 10336 10337 draggable.sortables = []; 10338 $( draggable.options.connectToSortable ).each( function() { 10339 var sortable = $( this ).sortable( "instance" ); 10340 10341 if ( sortable && !sortable.options.disabled ) { 10342 draggable.sortables.push( sortable ); 10343 10344 // RefreshPositions is called at drag start to refresh the containerCache 10345 // which is used in drag. This ensures it's initialized and synchronized 10346 // with any changes that might have happened on the page since initialization. 10347 sortable.refreshPositions(); 10348 sortable._trigger( "activate", event, uiSortable ); 10349 } 10350 } ); 10351 }, 10352 stop: function( event, ui, draggable ) { 10353 var uiSortable = $.extend( {}, ui, { 10354 item: draggable.element 10355 } ); 10356 10357 draggable.cancelHelperRemoval = false; 10358 10359 $.each( draggable.sortables, function() { 10360 var sortable = this; 10361 10362 if ( sortable.isOver ) { 10363 sortable.isOver = 0; 10364 10365 // Allow this sortable to handle removing the helper 10366 draggable.cancelHelperRemoval = true; 10367 sortable.cancelHelperRemoval = false; 10368 10369 // Use _storedCSS To restore properties in the sortable, 10370 // as this also handles revert (#9675) since the draggable 10371 // may have modified them in unexpected ways (#8809) 10372 sortable._storedCSS = { 10373 position: sortable.placeholder.css( "position" ), 10374 top: sortable.placeholder.css( "top" ), 10375 left: sortable.placeholder.css( "left" ) 10376 }; 10377 10378 sortable._mouseStop( event ); 10379 10380 // Once drag has ended, the sortable should return to using 10381 // its original helper, not the shared helper from draggable 10382 sortable.options.helper = sortable.options._helper; 10383 } else { 10384 10385 // Prevent this Sortable from removing the helper. 10386 // However, don't set the draggable to remove the helper 10387 // either as another connected Sortable may yet handle the removal. 10388 sortable.cancelHelperRemoval = true; 10389 10390 sortable._trigger( "deactivate", event, uiSortable ); 10391 } 10392 } ); 10393 }, 10394 drag: function( event, ui, draggable ) { 10395 $.each( draggable.sortables, function() { 10396 var innermostIntersecting = false, 10397 sortable = this; 10398 10399 // Copy over variables that sortable's _intersectsWith uses 10400 sortable.positionAbs = draggable.positionAbs; 10401 sortable.helperProportions = draggable.helperProportions; 10402 sortable.offset.click = draggable.offset.click; 10403 10404 if ( sortable._intersectsWith( sortable.containerCache ) ) { 10405 innermostIntersecting = true; 10406 10407 $.each( draggable.sortables, function() { 10408 10409 // Copy over variables that sortable's _intersectsWith uses 10410 this.positionAbs = draggable.positionAbs; 10411 this.helperProportions = draggable.helperProportions; 10412 this.offset.click = draggable.offset.click; 10413 10414 if ( this !== sortable && 10415 this._intersectsWith( this.containerCache ) && 10416 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { 10417 innermostIntersecting = false; 10418 } 10419 10420 return innermostIntersecting; 10421 } ); 10422 } 10423 10424 if ( innermostIntersecting ) { 10425 10426 // If it intersects, we use a little isOver variable and set it once, 10427 // so that the move-in stuff gets fired only once. 10428 if ( !sortable.isOver ) { 10429 sortable.isOver = 1; 10430 10431 // Store draggable's parent in case we need to reappend to it later. 10432 draggable._parent = ui.helper.parent(); 10433 10434 sortable.currentItem = ui.helper 10435 .appendTo( sortable.element ) 10436 .data( "ui-sortable-item", true ); 10437 10438 // Store helper option to later restore it 10439 sortable.options._helper = sortable.options.helper; 10440 10441 sortable.options.helper = function() { 10442 return ui.helper[ 0 ]; 10443 }; 10444 10445 // Fire the start events of the sortable with our passed browser event, 10446 // and our own helper (so it doesn't create a new one) 10447 event.target = sortable.currentItem[ 0 ]; 10448 sortable._mouseCapture( event, true ); 10449 sortable._mouseStart( event, true, true ); 10450 10451 // Because the browser event is way off the new appended portlet, 10452 // modify necessary variables to reflect the changes 10453 sortable.offset.click.top = draggable.offset.click.top; 10454 sortable.offset.click.left = draggable.offset.click.left; 10455 sortable.offset.parent.left -= draggable.offset.parent.left - 10456 sortable.offset.parent.left; 10457 sortable.offset.parent.top -= draggable.offset.parent.top - 10458 sortable.offset.parent.top; 10459 10460 draggable._trigger( "toSortable", event ); 10461 10462 // Inform draggable that the helper is in a valid drop zone, 10463 // used solely in the revert option to handle "valid/invalid". 10464 draggable.dropped = sortable.element; 10465 10466 // Need to refreshPositions of all sortables in the case that 10467 // adding to one sortable changes the location of the other sortables (#9675) 10468 $.each( draggable.sortables, function() { 10469 this.refreshPositions(); 10470 } ); 10471 10472 // Hack so receive/update callbacks work (mostly) 10473 draggable.currentItem = draggable.element; 10474 sortable.fromOutside = draggable; 10475 } 10476 10477 if ( sortable.currentItem ) { 10478 sortable._mouseDrag( event ); 10479 10480 // Copy the sortable's position because the draggable's can potentially reflect 10481 // a relative position, while sortable is always absolute, which the dragged 10482 // element has now become. (#8809) 10483 ui.position = sortable.position; 10484 } 10485 } else { 10486 10487 // If it doesn't intersect with the sortable, and it intersected before, 10488 // we fake the drag stop of the sortable, but make sure it doesn't remove 10489 // the helper by using cancelHelperRemoval. 10490 if ( sortable.isOver ) { 10491 10492 sortable.isOver = 0; 10493 sortable.cancelHelperRemoval = true; 10494 10495 // Calling sortable's mouseStop would trigger a revert, 10496 // so revert must be temporarily false until after mouseStop is called. 10497 sortable.options._revert = sortable.options.revert; 10498 sortable.options.revert = false; 10499 10500 sortable._trigger( "out", event, sortable._uiHash( sortable ) ); 10501 sortable._mouseStop( event, true ); 10502 10503 // Restore sortable behaviors that were modfied 10504 // when the draggable entered the sortable area (#9481) 10505 sortable.options.revert = sortable.options._revert; 10506 sortable.options.helper = sortable.options._helper; 10507 10508 if ( sortable.placeholder ) { 10509 sortable.placeholder.remove(); 10510 } 10511 10512 // Restore and recalculate the draggable's offset considering the sortable 10513 // may have modified them in unexpected ways. (#8809, #10669) 10514 ui.helper.appendTo( draggable._parent ); 10515 draggable._refreshOffsets( event ); 10516 ui.position = draggable._generatePosition( event, true ); 10517 10518 draggable._trigger( "fromSortable", event ); 10519 10520 // Inform draggable that the helper is no longer in a valid drop zone 10521 draggable.dropped = false; 10522 10523 // Need to refreshPositions of all sortables just in case removing 10524 // from one sortable changes the location of other sortables (#9675) 10525 $.each( draggable.sortables, function() { 10526 this.refreshPositions(); 10527 } ); 10528 } 10529 } 10530 } ); 10531 } 10532 } ); 10533 10534 $.ui.plugin.add( "draggable", "cursor", { 10535 start: function( event, ui, instance ) { 10536 var t = $( "body" ), 10537 o = instance.options; 10538 10539 if ( t.css( "cursor" ) ) { 10540 o._cursor = t.css( "cursor" ); 10541 } 10542 t.css( "cursor", o.cursor ); 10543 }, 10544 stop: function( event, ui, instance ) { 10545 var o = instance.options; 10546 if ( o._cursor ) { 10547 $( "body" ).css( "cursor", o._cursor ); 10548 } 10549 } 10550 } ); 10551 10552 $.ui.plugin.add( "draggable", "opacity", { 10553 start: function( event, ui, instance ) { 10554 var t = $( ui.helper ), 10555 o = instance.options; 10556 if ( t.css( "opacity" ) ) { 10557 o._opacity = t.css( "opacity" ); 10558 } 10559 t.css( "opacity", o.opacity ); 10560 }, 10561 stop: function( event, ui, instance ) { 10562 var o = instance.options; 10563 if ( o._opacity ) { 10564 $( ui.helper ).css( "opacity", o._opacity ); 10565 } 10566 } 10567 } ); 10568 10569 $.ui.plugin.add( "draggable", "scroll", { 10570 start: function( event, ui, i ) { 10571 if ( !i.scrollParentNotHidden ) { 10572 i.scrollParentNotHidden = i.helper.scrollParent( false ); 10573 } 10574 10575 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && 10576 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { 10577 i.overflowOffset = i.scrollParentNotHidden.offset(); 10578 } 10579 }, 10580 drag: function( event, ui, i ) { 10581 10582 var o = i.options, 10583 scrolled = false, 10584 scrollParent = i.scrollParentNotHidden[ 0 ], 10585 document = i.document[ 0 ]; 10586 10587 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { 10588 if ( !o.axis || o.axis !== "x" ) { 10589 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < 10590 o.scrollSensitivity ) { 10591 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; 10592 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { 10593 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; 10594 } 10595 } 10596 10597 if ( !o.axis || o.axis !== "y" ) { 10598 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < 10599 o.scrollSensitivity ) { 10600 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; 10601 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { 10602 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; 10603 } 10604 } 10605 10606 } else { 10607 10608 if ( !o.axis || o.axis !== "x" ) { 10609 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) { 10610 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed ); 10611 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) < 10612 o.scrollSensitivity ) { 10613 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed ); 10614 } 10615 } 10616 10617 if ( !o.axis || o.axis !== "y" ) { 10618 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) { 10619 scrolled = $( document ).scrollLeft( 10620 $( document ).scrollLeft() - o.scrollSpeed 10621 ); 10622 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) < 10623 o.scrollSensitivity ) { 10624 scrolled = $( document ).scrollLeft( 10625 $( document ).scrollLeft() + o.scrollSpeed 10626 ); 10627 } 10628 } 10629 10630 } 10631 10632 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 10633 $.ui.ddmanager.prepareOffsets( i, event ); 10634 } 10635 10636 } 10637 } ); 10638 10639 $.ui.plugin.add( "draggable", "snap", { 10640 start: function( event, ui, i ) { 10641 10642 var o = i.options; 10643 10644 i.snapElements = []; 10645 10646 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap ) 10647 .each( function() { 10648 var $t = $( this ), 10649 $o = $t.offset(); 10650 if ( this !== i.element[ 0 ] ) { 10651 i.snapElements.push( { 10652 item: this, 10653 width: $t.outerWidth(), height: $t.outerHeight(), 10654 top: $o.top, left: $o.left 10655 } ); 10656 } 10657 } ); 10658 10659 }, 10660 drag: function( event, ui, inst ) { 10661 10662 var ts, bs, ls, rs, l, r, t, b, i, first, 10663 o = inst.options, 10664 d = o.snapTolerance, 10665 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 10666 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 10667 10668 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) { 10669 10670 l = inst.snapElements[ i ].left - inst.margins.left; 10671 r = l + inst.snapElements[ i ].width; 10672 t = inst.snapElements[ i ].top - inst.margins.top; 10673 b = t + inst.snapElements[ i ].height; 10674 10675 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || 10676 !$.contains( inst.snapElements[ i ].item.ownerDocument, 10677 inst.snapElements[ i ].item ) ) { 10678 if ( inst.snapElements[ i ].snapping ) { 10679 if ( inst.options.snap.release ) { 10680 inst.options.snap.release.call( 10681 inst.element, 10682 event, 10683 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } ) 10684 ); 10685 } 10686 } 10687 inst.snapElements[ i ].snapping = false; 10688 continue; 10689 } 10690 10691 if ( o.snapMode !== "inner" ) { 10692 ts = Math.abs( t - y2 ) <= d; 10693 bs = Math.abs( b - y1 ) <= d; 10694 ls = Math.abs( l - x2 ) <= d; 10695 rs = Math.abs( r - x1 ) <= d; 10696 if ( ts ) { 10697 ui.position.top = inst._convertPositionTo( "relative", { 10698 top: t - inst.helperProportions.height, 10699 left: 0 10700 } ).top; 10701 } 10702 if ( bs ) { 10703 ui.position.top = inst._convertPositionTo( "relative", { 10704 top: b, 10705 left: 0 10706 } ).top; 10707 } 10708 if ( ls ) { 10709 ui.position.left = inst._convertPositionTo( "relative", { 10710 top: 0, 10711 left: l - inst.helperProportions.width 10712 } ).left; 10713 } 10714 if ( rs ) { 10715 ui.position.left = inst._convertPositionTo( "relative", { 10716 top: 0, 10717 left: r 10718 } ).left; 10719 } 10720 } 10721 10722 first = ( ts || bs || ls || rs ); 10723 10724 if ( o.snapMode !== "outer" ) { 10725 ts = Math.abs( t - y1 ) <= d; 10726 bs = Math.abs( b - y2 ) <= d; 10727 ls = Math.abs( l - x1 ) <= d; 10728 rs = Math.abs( r - x2 ) <= d; 10729 if ( ts ) { 10730 ui.position.top = inst._convertPositionTo( "relative", { 10731 top: t, 10732 left: 0 10733 } ).top; 10734 } 10735 if ( bs ) { 10736 ui.position.top = inst._convertPositionTo( "relative", { 10737 top: b - inst.helperProportions.height, 10738 left: 0 10739 } ).top; 10740 } 10741 if ( ls ) { 10742 ui.position.left = inst._convertPositionTo( "relative", { 10743 top: 0, 10744 left: l 10745 } ).left; 10746 } 10747 if ( rs ) { 10748 ui.position.left = inst._convertPositionTo( "relative", { 10749 top: 0, 10750 left: r - inst.helperProportions.width 10751 } ).left; 10752 } 10753 } 10754 10755 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) { 10756 if ( inst.options.snap.snap ) { 10757 inst.options.snap.snap.call( 10758 inst.element, 10759 event, 10760 $.extend( inst._uiHash(), { 10761 snapItem: inst.snapElements[ i ].item 10762 } ) ); 10763 } 10764 } 10765 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first ); 10766 10767 } 10768 10769 } 10770 } ); 10771 10772 $.ui.plugin.add( "draggable", "stack", { 10773 start: function( event, ui, instance ) { 10774 var min, 10775 o = instance.options, 10776 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) { 10777 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) - 10778 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 ); 10779 } ); 10780 10781 if ( !group.length ) { 10782 return; 10783 } 10784 10785 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0; 10786 $( group ).each( function( i ) { 10787 $( this ).css( "zIndex", min + i ); 10788 } ); 10789 this.css( "zIndex", ( min + group.length ) ); 10790 } 10791 } ); 10792 10793 $.ui.plugin.add( "draggable", "zIndex", { 10794 start: function( event, ui, instance ) { 10795 var t = $( ui.helper ), 10796 o = instance.options; 10797 10798 if ( t.css( "zIndex" ) ) { 10799 o._zIndex = t.css( "zIndex" ); 10800 } 10801 t.css( "zIndex", o.zIndex ); 10802 }, 10803 stop: function( event, ui, instance ) { 10804 var o = instance.options; 10805 10806 if ( o._zIndex ) { 10807 $( ui.helper ).css( "zIndex", o._zIndex ); 10808 } 10809 } 10810 } ); 10811 10812 var widgetsDraggable = $.ui.draggable; 10813 10814 10815 /*! 10816 * jQuery UI Resizable 1.14.1 10817 * https://jqueryui.com 10818 * 10819 * Copyright OpenJS Foundation and other contributors 10820 * Released under the MIT license. 10821 * https://jquery.org/license 10822 */ 10823 10824//>>label: Resizable 10825//>>group: Interactions 10826//>>description: Enables resize functionality for any element. 10827//>>docs: https://api.jqueryui.com/resizable/ 10828//>>demos: https://jqueryui.com/resizable/ 10829//>>css.structure: ../../themes/base/core.css 10830//>>css.structure: ../../themes/base/resizable.css 10831//>>css.theme: ../../themes/base/theme.css 10832 10833 10834 $.widget( "ui.resizable", $.ui.mouse, { 10835 version: "1.14.1", 10836 widgetEventPrefix: "resize", 10837 options: { 10838 alsoResize: false, 10839 animate: false, 10840 animateDuration: "slow", 10841 animateEasing: "swing", 10842 aspectRatio: false, 10843 autoHide: false, 10844 classes: { 10845 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se" 10846 }, 10847 containment: false, 10848 ghost: false, 10849 grid: false, 10850 handles: "e,s,se", 10851 helper: false, 10852 maxHeight: null, 10853 maxWidth: null, 10854 minHeight: 10, 10855 minWidth: 10, 10856 10857 // See #7960 10858 zIndex: 90, 10859 10860 // Callbacks 10861 resize: null, 10862 start: null, 10863 stop: null 10864 }, 10865 10866 _num: function( value ) { 10867 return parseFloat( value ) || 0; 10868 }, 10869 10870 _isNumber: function( value ) { 10871 return !isNaN( parseFloat( value ) ); 10872 }, 10873 10874 _hasScroll: function( el, a ) { 10875 10876 var scroll, 10877 has = false, 10878 overflow = $( el ).css( "overflow" ); 10879 10880 if ( overflow === "hidden" ) { 10881 return false; 10882 } 10883 if ( overflow === "scroll" ) { 10884 return true; 10885 } 10886 10887 scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop"; 10888 10889 if ( el[ scroll ] > 0 ) { 10890 return true; 10891 } 10892 10893 // TODO: determine which cases actually cause this to happen 10894 // if the element doesn't have the scroll set, see if it's possible to 10895 // set the scroll 10896 try { 10897 el[ scroll ] = 1; 10898 has = ( el[ scroll ] > 0 ); 10899 el[ scroll ] = 0; 10900 } catch ( e ) { 10901 10902 // `el` might be a string, then setting `scroll` will throw 10903 // an error in strict mode; ignore it. 10904 } 10905 return has; 10906 }, 10907 10908 _create: function() { 10909 10910 var margins, 10911 o = this.options, 10912 that = this; 10913 this._addClass( "ui-resizable" ); 10914 10915 $.extend( this, { 10916 _aspectRatio: !!( o.aspectRatio ), 10917 aspectRatio: o.aspectRatio, 10918 originalElement: this.element, 10919 _proportionallyResizeElements: [], 10920 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null 10921 } ); 10922 10923 // Wrap the element if it cannot hold child nodes 10924 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) { 10925 10926 this.element.wrap( 10927 $( "<div class='ui-wrapper'></div>" ).css( { 10928 overflow: "hidden", 10929 position: this.element.css( "position" ), 10930 width: this.element.outerWidth(), 10931 height: this.element.outerHeight(), 10932 top: this.element.css( "top" ), 10933 left: this.element.css( "left" ) 10934 } ) 10935 ); 10936 10937 this.element = this.element.parent().data( 10938 "ui-resizable", this.element.resizable( "instance" ) 10939 ); 10940 10941 this.elementIsWrapper = true; 10942 10943 margins = { 10944 marginTop: this.originalElement.css( "marginTop" ), 10945 marginRight: this.originalElement.css( "marginRight" ), 10946 marginBottom: this.originalElement.css( "marginBottom" ), 10947 marginLeft: this.originalElement.css( "marginLeft" ) 10948 }; 10949 10950 this.element.css( margins ); 10951 10952 // Support: Safari 10953 // Prevent Safari textarea resize 10954 this.originalResizeStyle = this.originalElement.css( "resize" ); 10955 this.originalElement.css( "resize", "none" ); 10956 10957 this._proportionallyResizeElements.push( this.originalElement.css( { 10958 position: "static", 10959 zoom: 1, 10960 display: "block" 10961 } ) ); 10962 10963 this._proportionallyResize(); 10964 } 10965 10966 this._setupHandles(); 10967 10968 if ( o.autoHide ) { 10969 $( this.element ) 10970 .on( "mouseenter", function() { 10971 if ( o.disabled ) { 10972 return; 10973 } 10974 that._removeClass( "ui-resizable-autohide" ); 10975 that._handles.show(); 10976 } ) 10977 .on( "mouseleave", function() { 10978 if ( o.disabled ) { 10979 return; 10980 } 10981 if ( !that.resizing ) { 10982 that._addClass( "ui-resizable-autohide" ); 10983 that._handles.hide(); 10984 } 10985 } ); 10986 } 10987 10988 this._mouseInit(); 10989 }, 10990 10991 _destroy: function() { 10992 10993 this._mouseDestroy(); 10994 this._addedHandles.remove(); 10995 10996 var wrapper, 10997 _destroy = function( exp ) { 10998 $( exp ) 10999 .removeData( "resizable" ) 11000 .removeData( "ui-resizable" ) 11001 .off( ".resizable" ); 11002 }; 11003 11004 // TODO: Unwrap at same DOM position 11005 if ( this.elementIsWrapper ) { 11006 _destroy( this.element ); 11007 wrapper = this.element; 11008 this.originalElement.css( { 11009 position: wrapper.css( "position" ), 11010 width: wrapper.outerWidth(), 11011 height: wrapper.outerHeight(), 11012 top: wrapper.css( "top" ), 11013 left: wrapper.css( "left" ) 11014 } ).insertAfter( wrapper ); 11015 wrapper.remove(); 11016 } 11017 11018 this.originalElement.css( "resize", this.originalResizeStyle ); 11019 _destroy( this.originalElement ); 11020 11021 return this; 11022 }, 11023 11024 _setOption: function( key, value ) { 11025 this._super( key, value ); 11026 11027 switch ( key ) { 11028 case "handles": 11029 this._removeHandles(); 11030 this._setupHandles(); 11031 break; 11032 case "aspectRatio": 11033 this._aspectRatio = !!value; 11034 break; 11035 default: 11036 break; 11037 } 11038 }, 11039 11040 _setupHandles: function() { 11041 var o = this.options, handle, i, n, hname, axis, that = this; 11042 this.handles = o.handles || 11043 ( !$( ".ui-resizable-handle", this.element ).length ? 11044 "e,s,se" : { 11045 n: ".ui-resizable-n", 11046 e: ".ui-resizable-e", 11047 s: ".ui-resizable-s", 11048 w: ".ui-resizable-w", 11049 se: ".ui-resizable-se", 11050 sw: ".ui-resizable-sw", 11051 ne: ".ui-resizable-ne", 11052 nw: ".ui-resizable-nw" 11053 } ); 11054 11055 this._handles = $(); 11056 this._addedHandles = $(); 11057 if ( this.handles.constructor === String ) { 11058 11059 if ( this.handles === "all" ) { 11060 this.handles = "n,e,s,w,se,sw,ne,nw"; 11061 } 11062 11063 n = this.handles.split( "," ); 11064 this.handles = {}; 11065 11066 for ( i = 0; i < n.length; i++ ) { 11067 11068 handle = String.prototype.trim.call( n[ i ] ); 11069 hname = "ui-resizable-" + handle; 11070 axis = $( "<div>" ); 11071 this._addClass( axis, "ui-resizable-handle " + hname ); 11072 11073 axis.css( { zIndex: o.zIndex } ); 11074 11075 this.handles[ handle ] = ".ui-resizable-" + handle; 11076 if ( !this.element.children( this.handles[ handle ] ).length ) { 11077 this.element.append( axis ); 11078 this._addedHandles = this._addedHandles.add( axis ); 11079 } 11080 } 11081 11082 } 11083 11084 this._renderAxis = function( target ) { 11085 11086 var i, axis, padPos, padWrapper; 11087 11088 target = target || this.element; 11089 11090 for ( i in this.handles ) { 11091 11092 if ( this.handles[ i ].constructor === String ) { 11093 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show(); 11094 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { 11095 this.handles[ i ] = $( this.handles[ i ] ); 11096 this._on( this.handles[ i ], { "mousedown": that._mouseDown } ); 11097 } 11098 11099 if ( this.elementIsWrapper && 11100 this.originalElement[ 0 ] 11101 .nodeName 11102 .match( /^(textarea|input|select|button)$/i ) ) { 11103 axis = $( this.handles[ i ], this.element ); 11104 11105 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ? 11106 axis.outerHeight() : 11107 axis.outerWidth(); 11108 11109 padPos = [ "padding", 11110 /ne|nw|n/.test( i ) ? "Top" : 11111 /se|sw|s/.test( i ) ? "Bottom" : 11112 /^e$/.test( i ) ? "Right" : "Left" ].join( "" ); 11113 11114 target.css( padPos, padWrapper ); 11115 11116 this._proportionallyResize(); 11117 } 11118 11119 this._handles = this._handles.add( this.handles[ i ] ); 11120 } 11121 }; 11122 11123 // TODO: make renderAxis a prototype function 11124 this._renderAxis( this.element ); 11125 11126 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); 11127 this._handles.disableSelection(); 11128 11129 this._handles.on( "mouseover", function() { 11130 if ( !that.resizing ) { 11131 if ( this.className ) { 11132 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i ); 11133 } 11134 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se"; 11135 } 11136 } ); 11137 11138 if ( o.autoHide ) { 11139 this._handles.hide(); 11140 this._addClass( "ui-resizable-autohide" ); 11141 } 11142 }, 11143 11144 _removeHandles: function() { 11145 this._addedHandles.remove(); 11146 }, 11147 11148 _mouseCapture: function( event ) { 11149 var i, handle, 11150 capture = false; 11151 11152 for ( i in this.handles ) { 11153 handle = $( this.handles[ i ] )[ 0 ]; 11154 if ( handle === event.target || $.contains( handle, event.target ) ) { 11155 capture = true; 11156 } 11157 } 11158 11159 return !this.options.disabled && capture; 11160 }, 11161 11162 _mouseStart: function( event ) { 11163 11164 var curleft, curtop, cursor, calculatedSize, 11165 o = this.options, 11166 el = this.element; 11167 11168 this.resizing = true; 11169 11170 this._renderProxy(); 11171 11172 curleft = this._num( this.helper.css( "left" ) ); 11173 curtop = this._num( this.helper.css( "top" ) ); 11174 11175 if ( o.containment ) { 11176 curleft += $( o.containment ).scrollLeft() || 0; 11177 curtop += $( o.containment ).scrollTop() || 0; 11178 } 11179 11180 this.offset = this.helper.offset(); 11181 this.position = { left: curleft, top: curtop }; 11182 11183 if ( !this._helper ) { 11184 calculatedSize = this._calculateAdjustedElementDimensions( el ); 11185 } 11186 11187 this.size = this._helper ? { 11188 width: this.helper.width(), 11189 height: this.helper.height() 11190 } : { 11191 width: calculatedSize.width, 11192 height: calculatedSize.height 11193 }; 11194 11195 this.originalSize = this._helper ? { 11196 width: el.outerWidth(), 11197 height: el.outerHeight() 11198 } : { 11199 width: calculatedSize.width, 11200 height: calculatedSize.height 11201 }; 11202 11203 this.sizeDiff = { 11204 width: el.outerWidth() - el.width(), 11205 height: el.outerHeight() - el.height() 11206 }; 11207 11208 this.originalPosition = { left: curleft, top: curtop }; 11209 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 11210 11211 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ? 11212 o.aspectRatio : 11213 ( ( this.originalSize.width / this.originalSize.height ) || 1 ); 11214 11215 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" ); 11216 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor ); 11217 11218 this._addClass( "ui-resizable-resizing" ); 11219 this._propagate( "start", event ); 11220 return true; 11221 }, 11222 11223 _mouseDrag: function( event ) { 11224 11225 var data, props, 11226 smp = this.originalMousePosition, 11227 a = this.axis, 11228 dx = ( event.pageX - smp.left ) || 0, 11229 dy = ( event.pageY - smp.top ) || 0, 11230 trigger = this._change[ a ]; 11231 11232 this._updatePrevProperties(); 11233 11234 if ( !trigger ) { 11235 return false; 11236 } 11237 11238 data = trigger.apply( this, [ event, dx, dy ] ); 11239 11240 this._updateVirtualBoundaries( event.shiftKey ); 11241 if ( this._aspectRatio || event.shiftKey ) { 11242 data = this._updateRatio( data, event ); 11243 } 11244 11245 data = this._respectSize( data, event ); 11246 11247 this._updateCache( data ); 11248 11249 this._propagate( "resize", event ); 11250 11251 props = this._applyChanges(); 11252 11253 if ( !this._helper && this._proportionallyResizeElements.length ) { 11254 this._proportionallyResize(); 11255 } 11256 11257 if ( !$.isEmptyObject( props ) ) { 11258 this._updatePrevProperties(); 11259 this._trigger( "resize", event, this.ui() ); 11260 this._applyChanges(); 11261 } 11262 11263 return false; 11264 }, 11265 11266 _mouseStop: function( event ) { 11267 11268 this.resizing = false; 11269 var pr, ista, soffseth, soffsetw, s, left, top, 11270 o = this.options, that = this; 11271 11272 if ( this._helper ) { 11273 11274 pr = this._proportionallyResizeElements; 11275 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ); 11276 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height; 11277 soffsetw = ista ? 0 : that.sizeDiff.width; 11278 11279 s = { 11280 width: ( that.helper.width() - soffsetw ), 11281 height: ( that.helper.height() - soffseth ) 11282 }; 11283 left = ( parseFloat( that.element.css( "left" ) ) + 11284 ( that.position.left - that.originalPosition.left ) ) || null; 11285 top = ( parseFloat( that.element.css( "top" ) ) + 11286 ( that.position.top - that.originalPosition.top ) ) || null; 11287 11288 if ( !o.animate ) { 11289 this.element.css( $.extend( s, { top: top, left: left } ) ); 11290 } 11291 11292 that.helper.height( that.size.height ); 11293 that.helper.width( that.size.width ); 11294 11295 if ( this._helper && !o.animate ) { 11296 this._proportionallyResize(); 11297 } 11298 } 11299 11300 $( "body" ).css( "cursor", "auto" ); 11301 11302 this._removeClass( "ui-resizable-resizing" ); 11303 11304 this._propagate( "stop", event ); 11305 11306 if ( this._helper ) { 11307 this.helper.remove(); 11308 } 11309 11310 return false; 11311 11312 }, 11313 11314 _updatePrevProperties: function() { 11315 this.prevPosition = { 11316 top: this.position.top, 11317 left: this.position.left 11318 }; 11319 this.prevSize = { 11320 width: this.size.width, 11321 height: this.size.height 11322 }; 11323 }, 11324 11325 _applyChanges: function() { 11326 var props = {}; 11327 11328 if ( this.position.top !== this.prevPosition.top ) { 11329 props.top = this.position.top + "px"; 11330 } 11331 if ( this.position.left !== this.prevPosition.left ) { 11332 props.left = this.position.left + "px"; 11333 } 11334 11335 this.helper.css( props ); 11336 11337 if ( this.size.width !== this.prevSize.width ) { 11338 props.width = this.size.width + "px"; 11339 this.helper.width( props.width ); 11340 } 11341 if ( this.size.height !== this.prevSize.height ) { 11342 props.height = this.size.height + "px"; 11343 this.helper.height( props.height ); 11344 } 11345 11346 return props; 11347 }, 11348 11349 _updateVirtualBoundaries: function( forceAspectRatio ) { 11350 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, 11351 o = this.options; 11352 11353 b = { 11354 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0, 11355 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity, 11356 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0, 11357 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity 11358 }; 11359 11360 if ( this._aspectRatio || forceAspectRatio ) { 11361 pMinWidth = b.minHeight * this.aspectRatio; 11362 pMinHeight = b.minWidth / this.aspectRatio; 11363 pMaxWidth = b.maxHeight * this.aspectRatio; 11364 pMaxHeight = b.maxWidth / this.aspectRatio; 11365 11366 if ( pMinWidth > b.minWidth ) { 11367 b.minWidth = pMinWidth; 11368 } 11369 if ( pMinHeight > b.minHeight ) { 11370 b.minHeight = pMinHeight; 11371 } 11372 if ( pMaxWidth < b.maxWidth ) { 11373 b.maxWidth = pMaxWidth; 11374 } 11375 if ( pMaxHeight < b.maxHeight ) { 11376 b.maxHeight = pMaxHeight; 11377 } 11378 } 11379 this._vBoundaries = b; 11380 }, 11381 11382 _updateCache: function( data ) { 11383 this.offset = this.helper.offset(); 11384 if ( this._isNumber( data.left ) ) { 11385 this.position.left = data.left; 11386 } 11387 if ( this._isNumber( data.top ) ) { 11388 this.position.top = data.top; 11389 } 11390 if ( this._isNumber( data.height ) ) { 11391 this.size.height = data.height; 11392 } 11393 if ( this._isNumber( data.width ) ) { 11394 this.size.width = data.width; 11395 } 11396 }, 11397 11398 _updateRatio: function( data ) { 11399 11400 var cpos = this.position, 11401 csize = this.size, 11402 a = this.axis; 11403 11404 if ( this._isNumber( data.height ) ) { 11405 data.width = ( data.height * this.aspectRatio ); 11406 } else if ( this._isNumber( data.width ) ) { 11407 data.height = ( data.width / this.aspectRatio ); 11408 } 11409 11410 if ( a === "sw" ) { 11411 data.left = cpos.left + ( csize.width - data.width ); 11412 data.top = null; 11413 } 11414 if ( a === "nw" ) { 11415 data.top = cpos.top + ( csize.height - data.height ); 11416 data.left = cpos.left + ( csize.width - data.width ); 11417 } 11418 11419 return data; 11420 }, 11421 11422 _respectSize: function( data ) { 11423 11424 var o = this._vBoundaries, 11425 a = this.axis, 11426 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ), 11427 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ), 11428 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ), 11429 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ), 11430 dw = this.originalPosition.left + this.originalSize.width, 11431 dh = this.originalPosition.top + this.originalSize.height, 11432 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a ); 11433 if ( isminw ) { 11434 data.width = o.minWidth; 11435 } 11436 if ( isminh ) { 11437 data.height = o.minHeight; 11438 } 11439 if ( ismaxw ) { 11440 data.width = o.maxWidth; 11441 } 11442 if ( ismaxh ) { 11443 data.height = o.maxHeight; 11444 } 11445 11446 if ( isminw && cw ) { 11447 data.left = dw - o.minWidth; 11448 } 11449 if ( ismaxw && cw ) { 11450 data.left = dw - o.maxWidth; 11451 } 11452 if ( isminh && ch ) { 11453 data.top = dh - o.minHeight; 11454 } 11455 if ( ismaxh && ch ) { 11456 data.top = dh - o.maxHeight; 11457 } 11458 11459 // Fixing jump error on top/left - bug #2330 11460 if ( !data.width && !data.height && !data.left && data.top ) { 11461 data.top = null; 11462 } else if ( !data.width && !data.height && !data.top && data.left ) { 11463 data.left = null; 11464 } 11465 11466 return data; 11467 }, 11468 11469 _getPaddingPlusBorderDimensions: function( element ) { 11470 var i = 0, 11471 widths = [], 11472 borders = [ 11473 element.css( "borderTopWidth" ), 11474 element.css( "borderRightWidth" ), 11475 element.css( "borderBottomWidth" ), 11476 element.css( "borderLeftWidth" ) 11477 ], 11478 paddings = [ 11479 element.css( "paddingTop" ), 11480 element.css( "paddingRight" ), 11481 element.css( "paddingBottom" ), 11482 element.css( "paddingLeft" ) 11483 ]; 11484 11485 for ( ; i < 4; i++ ) { 11486 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 ); 11487 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 ); 11488 } 11489 11490 return { 11491 height: widths[ 0 ] + widths[ 2 ], 11492 width: widths[ 1 ] + widths[ 3 ] 11493 }; 11494 }, 11495 11496 _calculateAdjustedElementDimensions: function( element ) { 11497 var elWidth, elHeight, paddingBorder, 11498 ce = element.get( 0 ); 11499 11500 if ( element.css( "box-sizing" ) !== "content-box" || 11501 ( !this._hasScroll( ce ) && !this._hasScroll( ce, "left" ) ) ) { 11502 return { 11503 height: parseFloat( element.css( "height" ) ), 11504 width: parseFloat( element.css( "width" ) ) 11505 }; 11506 } 11507 11508 // Check if CSS inline styles are set and use those (usually from previous resizes) 11509 elWidth = parseFloat( ce.style.width ); 11510 elHeight = parseFloat( ce.style.height ); 11511 11512 paddingBorder = this._getPaddingPlusBorderDimensions( element ); 11513 elWidth = isNaN( elWidth ) ? 11514 this._getElementTheoreticalSize( element, paddingBorder, "width" ) : 11515 elWidth; 11516 elHeight = isNaN( elHeight ) ? 11517 this._getElementTheoreticalSize( element, paddingBorder, "height" ) : 11518 elHeight; 11519 11520 return { 11521 height: elHeight, 11522 width: elWidth 11523 }; 11524 }, 11525 11526 _getElementTheoreticalSize: function( element, extraSize, dimension ) { 11527 11528 // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border 11529 var size = Math.max( 0, Math.ceil( 11530 element.get( 0 )[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 11531 extraSize[ dimension ] - 11532 0.5 11533 11534 // If offsetWidth/offsetHeight is unknown, then we can't determine theoretical size. 11535 // Use an explicit zero to avoid NaN. 11536 // See https://github.com/jquery/jquery/issues/3964 11537 ) ) || 0; 11538 11539 return size; 11540 }, 11541 11542 _proportionallyResize: function() { 11543 11544 if ( !this._proportionallyResizeElements.length ) { 11545 return; 11546 } 11547 11548 var prel, 11549 i = 0, 11550 element = this.helper || this.element; 11551 11552 for ( ; i < this._proportionallyResizeElements.length; i++ ) { 11553 11554 prel = this._proportionallyResizeElements[ i ]; 11555 11556 // TODO: Seems like a bug to cache this.outerDimensions 11557 // considering that we are in a loop. 11558 if ( !this.outerDimensions ) { 11559 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); 11560 } 11561 11562 prel.css( { 11563 height: ( element.height() - this.outerDimensions.height ) || 0, 11564 width: ( element.width() - this.outerDimensions.width ) || 0 11565 } ); 11566 11567 } 11568 11569 }, 11570 11571 _renderProxy: function() { 11572 11573 var el = this.element, o = this.options; 11574 this.elementOffset = el.offset(); 11575 11576 if ( this._helper ) { 11577 11578 this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } ); 11579 11580 this._addClass( this.helper, this._helper ); 11581 this.helper.css( { 11582 width: this.element.outerWidth(), 11583 height: this.element.outerHeight(), 11584 position: "absolute", 11585 left: this.elementOffset.left + "px", 11586 top: this.elementOffset.top + "px", 11587 zIndex: ++o.zIndex //TODO: Don't modify option 11588 } ); 11589 11590 this.helper 11591 .appendTo( "body" ) 11592 .disableSelection(); 11593 11594 } else { 11595 this.helper = this.element; 11596 } 11597 11598 }, 11599 11600 _change: { 11601 e: function( event, dx ) { 11602 return { width: this.originalSize.width + dx }; 11603 }, 11604 w: function( event, dx ) { 11605 var cs = this.originalSize, sp = this.originalPosition; 11606 return { left: sp.left + dx, width: cs.width - dx }; 11607 }, 11608 n: function( event, dx, dy ) { 11609 var cs = this.originalSize, sp = this.originalPosition; 11610 return { top: sp.top + dy, height: cs.height - dy }; 11611 }, 11612 s: function( event, dx, dy ) { 11613 return { height: this.originalSize.height + dy }; 11614 }, 11615 se: function( event, dx, dy ) { 11616 return $.extend( this._change.s.apply( this, arguments ), 11617 this._change.e.apply( this, [ event, dx, dy ] ) ); 11618 }, 11619 sw: function( event, dx, dy ) { 11620 return $.extend( this._change.s.apply( this, arguments ), 11621 this._change.w.apply( this, [ event, dx, dy ] ) ); 11622 }, 11623 ne: function( event, dx, dy ) { 11624 return $.extend( this._change.n.apply( this, arguments ), 11625 this._change.e.apply( this, [ event, dx, dy ] ) ); 11626 }, 11627 nw: function( event, dx, dy ) { 11628 return $.extend( this._change.n.apply( this, arguments ), 11629 this._change.w.apply( this, [ event, dx, dy ] ) ); 11630 } 11631 }, 11632 11633 _propagate: function( n, event ) { 11634 $.ui.plugin.call( this, n, [ event, this.ui() ] ); 11635 if ( n !== "resize" ) { 11636 this._trigger( n, event, this.ui() ); 11637 } 11638 }, 11639 11640 plugins: {}, 11641 11642 ui: function() { 11643 return { 11644 originalElement: this.originalElement, 11645 element: this.element, 11646 helper: this.helper, 11647 position: this.position, 11648 size: this.size, 11649 originalSize: this.originalSize, 11650 originalPosition: this.originalPosition 11651 }; 11652 } 11653 11654 } ); 11655 11656 /* 11657 * Resizable Extensions 11658 */ 11659 11660 $.ui.plugin.add( "resizable", "animate", { 11661 11662 stop: function( event ) { 11663 var that = $( this ).resizable( "instance" ), 11664 o = that.options, 11665 pr = that._proportionallyResizeElements, 11666 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ), 11667 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height, 11668 soffsetw = ista ? 0 : that.sizeDiff.width, 11669 style = { 11670 width: ( that.size.width - soffsetw ), 11671 height: ( that.size.height - soffseth ) 11672 }, 11673 left = ( parseFloat( that.element.css( "left" ) ) + 11674 ( that.position.left - that.originalPosition.left ) ) || null, 11675 top = ( parseFloat( that.element.css( "top" ) ) + 11676 ( that.position.top - that.originalPosition.top ) ) || null; 11677 11678 that.element.animate( 11679 $.extend( style, top && left ? { top: top, left: left } : {} ), { 11680 duration: o.animateDuration, 11681 easing: o.animateEasing, 11682 step: function() { 11683 11684 var data = { 11685 width: parseFloat( that.element.css( "width" ) ), 11686 height: parseFloat( that.element.css( "height" ) ), 11687 top: parseFloat( that.element.css( "top" ) ), 11688 left: parseFloat( that.element.css( "left" ) ) 11689 }; 11690 11691 if ( pr && pr.length ) { 11692 $( pr[ 0 ] ).css( { width: data.width, height: data.height } ); 11693 } 11694 11695 // Propagating resize, and updating values for each animation step 11696 that._updateCache( data ); 11697 that._propagate( "resize", event ); 11698 11699 } 11700 } 11701 ); 11702 } 11703 11704 } ); 11705 11706 $.ui.plugin.add( "resizable", "containment", { 11707 11708 start: function() { 11709 var element, p, co, ch, cw, width, height, 11710 that = $( this ).resizable( "instance" ), 11711 o = that.options, 11712 el = that.element, 11713 oc = o.containment, 11714 ce = ( oc instanceof $ ) ? 11715 oc.get( 0 ) : 11716 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; 11717 11718 if ( !ce ) { 11719 return; 11720 } 11721 11722 that.containerElement = $( ce ); 11723 11724 if ( /document/.test( oc ) || oc === document ) { 11725 that.containerOffset = { 11726 left: 0, 11727 top: 0 11728 }; 11729 that.containerPosition = { 11730 left: 0, 11731 top: 0 11732 }; 11733 11734 that.parentData = { 11735 element: $( document ), 11736 left: 0, 11737 top: 0, 11738 width: $( document ).width(), 11739 height: $( document ).height() || document.body.parentNode.scrollHeight 11740 }; 11741 } else { 11742 element = $( ce ); 11743 p = []; 11744 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) { 11745 p[ i ] = that._num( element.css( "padding" + name ) ); 11746 } ); 11747 11748 that.containerOffset = element.offset(); 11749 that.containerPosition = element.position(); 11750 that.containerSize = { 11751 height: ( element.innerHeight() - p[ 3 ] ), 11752 width: ( element.innerWidth() - p[ 1 ] ) 11753 }; 11754 11755 co = that.containerOffset; 11756 ch = that.containerSize.height; 11757 cw = that.containerSize.width; 11758 width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw ); 11759 height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch ); 11760 11761 that.parentData = { 11762 element: ce, 11763 left: co.left, 11764 top: co.top, 11765 width: width, 11766 height: height 11767 }; 11768 } 11769 }, 11770 11771 resize: function( event ) { 11772 var woset, hoset, isParent, isOffsetRelative, 11773 that = $( this ).resizable( "instance" ), 11774 o = that.options, 11775 co = that.containerOffset, 11776 cp = that.position, 11777 pRatio = that._aspectRatio || event.shiftKey, 11778 cop = { 11779 top: 0, 11780 left: 0 11781 }, 11782 ce = that.containerElement, 11783 continueResize = true; 11784 11785 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { 11786 cop = co; 11787 } 11788 11789 if ( cp.left < ( that._helper ? co.left : 0 ) ) { 11790 that.size.width = that.size.width + 11791 ( that._helper ? 11792 ( that.position.left - co.left ) : 11793 ( that.position.left - cop.left ) ); 11794 11795 if ( pRatio ) { 11796 that.size.height = that.size.width / that.aspectRatio; 11797 continueResize = false; 11798 } 11799 that.position.left = o.helper ? co.left : 0; 11800 } 11801 11802 if ( cp.top < ( that._helper ? co.top : 0 ) ) { 11803 that.size.height = that.size.height + 11804 ( that._helper ? 11805 ( that.position.top - co.top ) : 11806 that.position.top ); 11807 11808 if ( pRatio ) { 11809 that.size.width = that.size.height * that.aspectRatio; 11810 continueResize = false; 11811 } 11812 that.position.top = that._helper ? co.top : 0; 11813 } 11814 11815 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); 11816 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); 11817 11818 if ( isParent && isOffsetRelative ) { 11819 that.offset.left = that.parentData.left + that.position.left; 11820 that.offset.top = that.parentData.top + that.position.top; 11821 } else { 11822 that.offset.left = that.element.offset().left; 11823 that.offset.top = that.element.offset().top; 11824 } 11825 11826 woset = Math.abs( that.sizeDiff.width + 11827 ( that._helper ? 11828 that.offset.left - cop.left : 11829 ( that.offset.left - co.left ) ) ); 11830 11831 hoset = Math.abs( that.sizeDiff.height + 11832 ( that._helper ? 11833 that.offset.top - cop.top : 11834 ( that.offset.top - co.top ) ) ); 11835 11836 if ( woset + that.size.width >= that.parentData.width ) { 11837 that.size.width = that.parentData.width - woset; 11838 if ( pRatio ) { 11839 that.size.height = that.size.width / that.aspectRatio; 11840 continueResize = false; 11841 } 11842 } 11843 11844 if ( hoset + that.size.height >= that.parentData.height ) { 11845 that.size.height = that.parentData.height - hoset; 11846 if ( pRatio ) { 11847 that.size.width = that.size.height * that.aspectRatio; 11848 continueResize = false; 11849 } 11850 } 11851 11852 if ( !continueResize ) { 11853 that.position.left = that.prevPosition.left; 11854 that.position.top = that.prevPosition.top; 11855 that.size.width = that.prevSize.width; 11856 that.size.height = that.prevSize.height; 11857 } 11858 }, 11859 11860 stop: function() { 11861 var that = $( this ).resizable( "instance" ), 11862 o = that.options, 11863 co = that.containerOffset, 11864 cop = that.containerPosition, 11865 ce = that.containerElement, 11866 helper = $( that.helper ), 11867 ho = helper.offset(), 11868 w = helper.outerWidth() - that.sizeDiff.width, 11869 h = helper.outerHeight() - that.sizeDiff.height; 11870 11871 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { 11872 $( this ).css( { 11873 left: ho.left - cop.left - co.left, 11874 width: w, 11875 height: h 11876 } ); 11877 } 11878 11879 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { 11880 $( this ).css( { 11881 left: ho.left - cop.left - co.left, 11882 width: w, 11883 height: h 11884 } ); 11885 } 11886 } 11887 } ); 11888 11889 $.ui.plugin.add( "resizable", "alsoResize", { 11890 11891 start: function() { 11892 var that = $( this ).resizable( "instance" ), 11893 o = that.options; 11894 11895 $( o.alsoResize ).each( function() { 11896 var el = $( this ), 11897 elSize = that._calculateAdjustedElementDimensions( el ); 11898 11899 el.data( "ui-resizable-alsoresize", { 11900 width: elSize.width, height: elSize.height, 11901 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) 11902 } ); 11903 } ); 11904 }, 11905 11906 resize: function( event, ui ) { 11907 var that = $( this ).resizable( "instance" ), 11908 o = that.options, 11909 os = that.originalSize, 11910 op = that.originalPosition, 11911 delta = { 11912 height: ( that.size.height - os.height ) || 0, 11913 width: ( that.size.width - os.width ) || 0, 11914 top: ( that.position.top - op.top ) || 0, 11915 left: ( that.position.left - op.left ) || 0 11916 }; 11917 11918 $( o.alsoResize ).each( function() { 11919 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {}, 11920 css = el.parents( ui.originalElement[ 0 ] ).length ? 11921 [ "width", "height" ] : 11922 [ "width", "height", "top", "left" ]; 11923 11924 $.each( css, function( i, prop ) { 11925 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 ); 11926 if ( sum && sum >= 0 ) { 11927 style[ prop ] = sum || null; 11928 } 11929 } ); 11930 11931 el.css( style ); 11932 } ); 11933 }, 11934 11935 stop: function() { 11936 $( this ).removeData( "ui-resizable-alsoresize" ); 11937 } 11938 } ); 11939 11940 $.ui.plugin.add( "resizable", "ghost", { 11941 11942 start: function() { 11943 11944 var that = $( this ).resizable( "instance" ), cs = that.size; 11945 11946 that.ghost = that.originalElement.clone(); 11947 that.ghost.css( { 11948 opacity: 0.25, 11949 display: "block", 11950 position: "relative", 11951 height: cs.height, 11952 width: cs.width, 11953 margin: 0, 11954 left: 0, 11955 top: 0 11956 } ); 11957 11958 that._addClass( that.ghost, "ui-resizable-ghost" ); 11959 11960 // DEPRECATED 11961 // TODO: remove after 1.12 11962 if ( $.uiBackCompat === true && typeof that.options.ghost === "string" ) { 11963 11964 // Ghost option 11965 that.ghost.addClass( this.options.ghost ); 11966 } 11967 11968 that.ghost.appendTo( that.helper ); 11969 11970 }, 11971 11972 resize: function() { 11973 var that = $( this ).resizable( "instance" ); 11974 if ( that.ghost ) { 11975 that.ghost.css( { 11976 position: "relative", 11977 height: that.size.height, 11978 width: that.size.width 11979 } ); 11980 } 11981 }, 11982 11983 stop: function() { 11984 var that = $( this ).resizable( "instance" ); 11985 if ( that.ghost && that.helper ) { 11986 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) ); 11987 } 11988 } 11989 11990 } ); 11991 11992 $.ui.plugin.add( "resizable", "grid", { 11993 11994 resize: function() { 11995 var outerDimensions, 11996 that = $( this ).resizable( "instance" ), 11997 o = that.options, 11998 cs = that.size, 11999 os = that.originalSize, 12000 op = that.originalPosition, 12001 a = that.axis, 12002 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, 12003 gridX = ( grid[ 0 ] || 1 ), 12004 gridY = ( grid[ 1 ] || 1 ), 12005 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX, 12006 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY, 12007 newWidth = os.width + ox, 12008 newHeight = os.height + oy, 12009 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ), 12010 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ), 12011 isMinWidth = o.minWidth && ( o.minWidth > newWidth ), 12012 isMinHeight = o.minHeight && ( o.minHeight > newHeight ); 12013 12014 o.grid = grid; 12015 12016 if ( isMinWidth ) { 12017 newWidth += gridX; 12018 } 12019 if ( isMinHeight ) { 12020 newHeight += gridY; 12021 } 12022 if ( isMaxWidth ) { 12023 newWidth -= gridX; 12024 } 12025 if ( isMaxHeight ) { 12026 newHeight -= gridY; 12027 } 12028 12029 if ( /^(se|s|e)$/.test( a ) ) { 12030 that.size.width = newWidth; 12031 that.size.height = newHeight; 12032 } else if ( /^(ne)$/.test( a ) ) { 12033 that.size.width = newWidth; 12034 that.size.height = newHeight; 12035 that.position.top = op.top - oy; 12036 } else if ( /^(sw)$/.test( a ) ) { 12037 that.size.width = newWidth; 12038 that.size.height = newHeight; 12039 that.position.left = op.left - ox; 12040 } else { 12041 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) { 12042 outerDimensions = that._getPaddingPlusBorderDimensions( this ); 12043 } 12044 12045 if ( newHeight - gridY > 0 ) { 12046 that.size.height = newHeight; 12047 that.position.top = op.top - oy; 12048 } else { 12049 newHeight = gridY - outerDimensions.height; 12050 that.size.height = newHeight; 12051 that.position.top = op.top + os.height - newHeight; 12052 } 12053 if ( newWidth - gridX > 0 ) { 12054 that.size.width = newWidth; 12055 that.position.left = op.left - ox; 12056 } else { 12057 newWidth = gridX - outerDimensions.width; 12058 that.size.width = newWidth; 12059 that.position.left = op.left + os.width - newWidth; 12060 } 12061 } 12062 } 12063 12064 } ); 12065 12066 var widgetsResizable = $.ui.resizable; 12067 12068 12069 /*! 12070 * jQuery UI Dialog 1.14.1 12071 * https://jqueryui.com 12072 * 12073 * Copyright OpenJS Foundation and other contributors 12074 * Released under the MIT license. 12075 * https://jquery.org/license 12076 */ 12077 12078//>>label: Dialog 12079//>>group: Widgets 12080//>>description: Displays customizable dialog windows. 12081//>>docs: https://api.jqueryui.com/dialog/ 12082//>>demos: https://jqueryui.com/dialog/ 12083//>>css.structure: ../../themes/base/core.css 12084//>>css.structure: ../../themes/base/dialog.css 12085//>>css.theme: ../../themes/base/theme.css 12086 12087 12088 $.widget( "ui.dialog", { 12089 version: "1.14.1", 12090 options: { 12091 appendTo: "body", 12092 autoOpen: true, 12093 buttons: [], 12094 classes: { 12095 "ui-dialog": "ui-corner-all", 12096 "ui-dialog-titlebar": "ui-corner-all" 12097 }, 12098 closeOnEscape: true, 12099 closeText: "Close", 12100 draggable: true, 12101 hide: null, 12102 height: "auto", 12103 maxHeight: null, 12104 maxWidth: null, 12105 minHeight: 150, 12106 minWidth: 150, 12107 modal: false, 12108 position: { 12109 my: "center", 12110 at: "center", 12111 of: window, 12112 collision: "fit", 12113 12114 // Ensure the titlebar is always visible 12115 using: function( pos ) { 12116 var topOffset = $( this ).css( pos ).offset().top; 12117 if ( topOffset < 0 ) { 12118 $( this ).css( "top", pos.top - topOffset ); 12119 } 12120 } 12121 }, 12122 resizable: true, 12123 show: null, 12124 title: null, 12125 uiDialogTitleHeadingLevel: 0, 12126 width: 300, 12127 12128 // Callbacks 12129 beforeClose: null, 12130 close: null, 12131 drag: null, 12132 dragStart: null, 12133 dragStop: null, 12134 focus: null, 12135 open: null, 12136 resize: null, 12137 resizeStart: null, 12138 resizeStop: null 12139 }, 12140 12141 sizeRelatedOptions: { 12142 buttons: true, 12143 height: true, 12144 maxHeight: true, 12145 maxWidth: true, 12146 minHeight: true, 12147 minWidth: true, 12148 width: true 12149 }, 12150 12151 resizableRelatedOptions: { 12152 maxHeight: true, 12153 maxWidth: true, 12154 minHeight: true, 12155 minWidth: true 12156 }, 12157 12158 _create: function() { 12159 this.originalCss = { 12160 display: this.element[ 0 ].style.display, 12161 width: this.element[ 0 ].style.width, 12162 minHeight: this.element[ 0 ].style.minHeight, 12163 maxHeight: this.element[ 0 ].style.maxHeight, 12164 height: this.element[ 0 ].style.height 12165 }; 12166 this.originalPosition = { 12167 parent: this.element.parent(), 12168 index: this.element.parent().children().index( this.element ) 12169 }; 12170 this.originalTitle = this.element.attr( "title" ); 12171 if ( this.options.title == null && this.originalTitle != null ) { 12172 this.options.title = this.originalTitle; 12173 } 12174 12175 // Dialogs can't be disabled 12176 if ( this.options.disabled ) { 12177 this.options.disabled = false; 12178 } 12179 12180 this._createWrapper(); 12181 12182 this.element 12183 .show() 12184 .removeAttr( "title" ) 12185 .appendTo( this.uiDialog ); 12186 12187 this._addClass( "ui-dialog-content", "ui-widget-content" ); 12188 12189 this._createTitlebar(); 12190 this._createButtonPane(); 12191 12192 if ( this.options.draggable && $.fn.draggable ) { 12193 this._makeDraggable(); 12194 } 12195 if ( this.options.resizable && $.fn.resizable ) { 12196 this._makeResizable(); 12197 } 12198 12199 this._isOpen = false; 12200 12201 this._trackFocus(); 12202 }, 12203 12204 _init: function() { 12205 if ( this.options.autoOpen ) { 12206 this.open(); 12207 } 12208 }, 12209 12210 _appendTo: function() { 12211 var element = this.options.appendTo; 12212 if ( element && ( element.jquery || element.nodeType ) ) { 12213 return $( element ); 12214 } 12215 return this.document.find( element || "body" ).eq( 0 ); 12216 }, 12217 12218 _destroy: function() { 12219 var next, 12220 originalPosition = this.originalPosition; 12221 12222 this._untrackInstance(); 12223 this._destroyOverlay(); 12224 12225 this.element 12226 .removeUniqueId() 12227 .css( this.originalCss ) 12228 12229 // Without detaching first, the following becomes really slow 12230 .detach(); 12231 12232 this.uiDialog.remove(); 12233 12234 if ( this.originalTitle ) { 12235 this.element.attr( "title", this.originalTitle ); 12236 } 12237 12238 next = originalPosition.parent.children().eq( originalPosition.index ); 12239 12240 // Don't try to place the dialog next to itself (#8613) 12241 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { 12242 next.before( this.element ); 12243 } else { 12244 originalPosition.parent.append( this.element ); 12245 } 12246 }, 12247 12248 widget: function() { 12249 return this.uiDialog; 12250 }, 12251 12252 disable: $.noop, 12253 enable: $.noop, 12254 12255 close: function( event ) { 12256 var that = this; 12257 12258 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { 12259 return; 12260 } 12261 12262 this._isOpen = false; 12263 this._focusedElement = null; 12264 this._destroyOverlay(); 12265 this._untrackInstance(); 12266 12267 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) { 12268 12269 // Hiding a focused element doesn't trigger blur in WebKit 12270 // so in case we have nothing to focus on, explicitly blur the active element 12271 // https://bugs.webkit.org/show_bug.cgi?id=47182 12272 $( this.document[ 0 ].activeElement ).trigger( "blur" ); 12273 } 12274 12275 this._hide( this.uiDialog, this.options.hide, function() { 12276 that._trigger( "close", event ); 12277 } ); 12278 }, 12279 12280 isOpen: function() { 12281 return this._isOpen; 12282 }, 12283 12284 moveToTop: function() { 12285 this._moveToTop(); 12286 }, 12287 12288 _moveToTop: function( event, silent ) { 12289 var moved = false, 12290 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() { 12291 return +$( this ).css( "z-index" ); 12292 } ).get(), 12293 zIndexMax = Math.max.apply( null, zIndices ); 12294 12295 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { 12296 this.uiDialog.css( "z-index", zIndexMax + 1 ); 12297 moved = true; 12298 } 12299 12300 if ( moved && !silent ) { 12301 this._trigger( "focus", event ); 12302 } 12303 return moved; 12304 }, 12305 12306 open: function() { 12307 var that = this; 12308 if ( this._isOpen ) { 12309 if ( this._moveToTop() ) { 12310 this._focusTabbable(); 12311 } 12312 return; 12313 } 12314 12315 this._isOpen = true; 12316 this.opener = $( this.document[ 0 ].activeElement ); 12317 12318 this._size(); 12319 this._position(); 12320 this._createOverlay(); 12321 this._moveToTop( null, true ); 12322 12323 // Ensure the overlay is moved to the top with the dialog, but only when 12324 // opening. The overlay shouldn't move after the dialog is open so that 12325 // modeless dialogs opened after the modal dialog stack properly. 12326 if ( this.overlay ) { 12327 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); 12328 } 12329 12330 this._show( this.uiDialog, this.options.show, function() { 12331 that._focusTabbable(); 12332 that._trigger( "focus" ); 12333 } ); 12334 12335 // Track the dialog immediately upon opening in case a focus event 12336 // somehow occurs outside of the dialog before an element inside the 12337 // dialog is focused (#10152) 12338 this._makeFocusTarget(); 12339 12340 this._trigger( "open" ); 12341 }, 12342 12343 _focusTabbable: function() { 12344 12345 // Set focus to the first match: 12346 // 1. An element that was focused previously 12347 // 2. First element inside the dialog matching [autofocus] 12348 // 3. Tabbable element inside the content element 12349 // 4. Tabbable element inside the buttonpane 12350 // 5. The close button 12351 // 6. The dialog itself 12352 var hasFocus = this._focusedElement; 12353 if ( !hasFocus ) { 12354 hasFocus = this.element.find( "[autofocus]" ); 12355 } 12356 if ( !hasFocus.length ) { 12357 hasFocus = this.element.find( ":tabbable" ); 12358 } 12359 if ( !hasFocus.length ) { 12360 hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); 12361 } 12362 if ( !hasFocus.length ) { 12363 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); 12364 } 12365 if ( !hasFocus.length ) { 12366 hasFocus = this.uiDialog; 12367 } 12368 hasFocus.eq( 0 ).trigger( "focus" ); 12369 }, 12370 12371 _restoreTabbableFocus: function() { 12372 var activeElement = this.document[ 0 ].activeElement, 12373 isActive = this.uiDialog[ 0 ] === activeElement || 12374 $.contains( this.uiDialog[ 0 ], activeElement ); 12375 if ( !isActive ) { 12376 this._focusTabbable(); 12377 } 12378 }, 12379 12380 _keepFocus: function( event ) { 12381 event.preventDefault(); 12382 this._restoreTabbableFocus(); 12383 }, 12384 12385 _createWrapper: function() { 12386 this.uiDialog = $( "<div>" ) 12387 .hide() 12388 .attr( { 12389 12390 // Setting tabIndex makes the div focusable 12391 tabIndex: -1, 12392 role: "dialog", 12393 "aria-modal": this.options.modal ? "true" : null 12394 } ) 12395 .appendTo( this._appendTo() ); 12396 12397 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" ); 12398 this._on( this.uiDialog, { 12399 keydown: function( event ) { 12400 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 12401 event.keyCode === $.ui.keyCode.ESCAPE ) { 12402 event.preventDefault(); 12403 this.close( event ); 12404 return; 12405 } 12406 12407 // Prevent tabbing out of dialogs 12408 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { 12409 return; 12410 } 12411 var tabbables = this.uiDialog.find( ":tabbable" ), 12412 first = tabbables.first(), 12413 last = tabbables.last(); 12414 12415 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) && 12416 !event.shiftKey ) { 12417 this._delay( function() { 12418 first.trigger( "focus" ); 12419 } ); 12420 event.preventDefault(); 12421 } else if ( ( event.target === first[ 0 ] || 12422 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) { 12423 this._delay( function() { 12424 last.trigger( "focus" ); 12425 } ); 12426 event.preventDefault(); 12427 } 12428 }, 12429 mousedown: function( event ) { 12430 if ( this._moveToTop( event ) ) { 12431 this._focusTabbable(); 12432 } 12433 } 12434 } ); 12435 12436 // We assume that any existing aria-describedby attribute means 12437 // that the dialog content is marked up properly 12438 // otherwise we brute force the content as the description 12439 if ( !this.element.find( "[aria-describedby]" ).length ) { 12440 this.uiDialog.attr( { 12441 "aria-describedby": this.element.uniqueId().attr( "id" ) 12442 } ); 12443 } 12444 }, 12445 12446 _createTitlebar: function() { 12447 var uiDialogTitle; 12448 12449 this.uiDialogTitlebar = $( "<div>" ); 12450 this._addClass( this.uiDialogTitlebar, 12451 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" ); 12452 this._on( this.uiDialogTitlebar, { 12453 mousedown: function( event ) { 12454 12455 // Don't prevent click on close button (#8838) 12456 // Focusing a dialog that is partially scrolled out of view 12457 // causes the browser to scroll it into view, preventing the click event 12458 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { 12459 12460 // Dialog isn't getting focus when dragging (#8063) 12461 this.uiDialog.trigger( "focus" ); 12462 } 12463 } 12464 } ); 12465 12466 this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) 12467 .button( { 12468 label: $( "<a>" ).text( this.options.closeText ).html(), 12469 icon: "ui-icon-closethick", 12470 showLabel: false 12471 } ) 12472 .appendTo( this.uiDialogTitlebar ); 12473 12474 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" ); 12475 this._on( this.uiDialogTitlebarClose, { 12476 click: function( event ) { 12477 event.preventDefault(); 12478 this.close( event ); 12479 } 12480 } ); 12481 12482 var uiDialogHeadingLevel = Number.isInteger( this.options.uiDialogTitleHeadingLevel ) && 12483 this.options.uiDialogTitleHeadingLevel > 0 && 12484 this.options.uiDialogTitleHeadingLevel <= 6 ? 12485 "h" + this.options.uiDialogTitleHeadingLevel : "span"; 12486 12487 uiDialogTitle = $( "<" + uiDialogHeadingLevel + ">" ) 12488 .uniqueId().prependTo( this.uiDialogTitlebar ); 12489 this._addClass( uiDialogTitle, "ui-dialog-title" ); 12490 this._title( uiDialogTitle ); 12491 12492 this.uiDialogTitlebar.prependTo( this.uiDialog ); 12493 12494 this.uiDialog.attr( { 12495 "aria-labelledby": uiDialogTitle.attr( "id" ) 12496 } ); 12497 }, 12498 12499 _title: function( title ) { 12500 if ( this.options.title ) { 12501 title.text( this.options.title ); 12502 } else { 12503 title.html( " " ); 12504 } 12505 }, 12506 12507 _createButtonPane: function() { 12508 this.uiDialogButtonPane = $( "<div>" ); 12509 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane", 12510 "ui-widget-content ui-helper-clearfix" ); 12511 12512 this.uiButtonSet = $( "<div>" ) 12513 .appendTo( this.uiDialogButtonPane ); 12514 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" ); 12515 12516 this._createButtons(); 12517 }, 12518 12519 _createButtons: function() { 12520 var that = this, 12521 buttons = this.options.buttons; 12522 12523 // If we already have a button pane, remove it 12524 this.uiDialogButtonPane.remove(); 12525 this.uiButtonSet.empty(); 12526 12527 if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) { 12528 this._removeClass( this.uiDialog, "ui-dialog-buttons" ); 12529 return; 12530 } 12531 12532 $.each( buttons, function( name, props ) { 12533 var click, buttonOptions; 12534 props = typeof props === "function" ? 12535 { click: props, text: name } : 12536 props; 12537 12538 // Default to a non-submitting button 12539 props = $.extend( { type: "button" }, props ); 12540 12541 // Change the context for the click callback to be the main element 12542 click = props.click; 12543 buttonOptions = { 12544 icon: props.icon, 12545 iconPosition: props.iconPosition, 12546 showLabel: props.showLabel, 12547 12548 // Deprecated options 12549 icons: props.icons, 12550 text: props.text 12551 }; 12552 12553 delete props.click; 12554 delete props.icon; 12555 delete props.iconPosition; 12556 delete props.showLabel; 12557 12558 // Deprecated options 12559 delete props.icons; 12560 if ( typeof props.text === "boolean" ) { 12561 delete props.text; 12562 } 12563 12564 $( "<button></button>", props ) 12565 .button( buttonOptions ) 12566 .appendTo( that.uiButtonSet ) 12567 .on( "click", function() { 12568 click.apply( that.element[ 0 ], arguments ); 12569 } ); 12570 } ); 12571 this._addClass( this.uiDialog, "ui-dialog-buttons" ); 12572 this.uiDialogButtonPane.appendTo( this.uiDialog ); 12573 }, 12574 12575 _makeDraggable: function() { 12576 var that = this, 12577 options = this.options; 12578 12579 function filteredUi( ui ) { 12580 return { 12581 position: ui.position, 12582 offset: ui.offset 12583 }; 12584 } 12585 12586 this.uiDialog.draggable( { 12587 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", 12588 handle: ".ui-dialog-titlebar", 12589 containment: "document", 12590 start: function( event, ui ) { 12591 that._addClass( $( this ), "ui-dialog-dragging" ); 12592 that._blockFrames(); 12593 that._trigger( "dragStart", event, filteredUi( ui ) ); 12594 }, 12595 drag: function( event, ui ) { 12596 that._trigger( "drag", event, filteredUi( ui ) ); 12597 }, 12598 stop: function( event, ui ) { 12599 var left = ui.offset.left - that.document.scrollLeft(), 12600 top = ui.offset.top - that.document.scrollTop(); 12601 12602 options.position = { 12603 my: "left top", 12604 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12605 "top" + ( top >= 0 ? "+" : "" ) + top, 12606 of: that.window 12607 }; 12608 that._removeClass( $( this ), "ui-dialog-dragging" ); 12609 that._unblockFrames(); 12610 that._trigger( "dragStop", event, filteredUi( ui ) ); 12611 } 12612 } ); 12613 }, 12614 12615 _makeResizable: function() { 12616 var that = this, 12617 options = this.options, 12618 handles = options.resizable, 12619 12620 // .ui-resizable has position: relative defined in the stylesheet 12621 // but dialogs have to use absolute or fixed positioning 12622 position = this.uiDialog.css( "position" ), 12623 resizeHandles = typeof handles === "string" ? 12624 handles : 12625 "n,e,s,w,se,sw,ne,nw"; 12626 12627 function filteredUi( ui ) { 12628 return { 12629 originalPosition: ui.originalPosition, 12630 originalSize: ui.originalSize, 12631 position: ui.position, 12632 size: ui.size 12633 }; 12634 } 12635 12636 this.uiDialog.resizable( { 12637 cancel: ".ui-dialog-content", 12638 containment: "document", 12639 alsoResize: this.element, 12640 maxWidth: options.maxWidth, 12641 maxHeight: options.maxHeight, 12642 minWidth: options.minWidth, 12643 minHeight: this._minHeight(), 12644 handles: resizeHandles, 12645 start: function( event, ui ) { 12646 that._addClass( $( this ), "ui-dialog-resizing" ); 12647 that._blockFrames(); 12648 that._trigger( "resizeStart", event, filteredUi( ui ) ); 12649 }, 12650 resize: function( event, ui ) { 12651 that._trigger( "resize", event, filteredUi( ui ) ); 12652 }, 12653 stop: function( event, ui ) { 12654 var offset = that.uiDialog.offset(), 12655 left = offset.left - that.document.scrollLeft(), 12656 top = offset.top - that.document.scrollTop(); 12657 12658 options.height = that.uiDialog.height(); 12659 options.width = that.uiDialog.width(); 12660 options.position = { 12661 my: "left top", 12662 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12663 "top" + ( top >= 0 ? "+" : "" ) + top, 12664 of: that.window 12665 }; 12666 that._removeClass( $( this ), "ui-dialog-resizing" ); 12667 that._unblockFrames(); 12668 that._trigger( "resizeStop", event, filteredUi( ui ) ); 12669 } 12670 } ) 12671 .css( "position", position ); 12672 }, 12673 12674 _trackFocus: function() { 12675 this._on( this.widget(), { 12676 focusin: function( event ) { 12677 this._makeFocusTarget(); 12678 this._focusedElement = $( event.target ); 12679 } 12680 } ); 12681 }, 12682 12683 _makeFocusTarget: function() { 12684 this._untrackInstance(); 12685 this._trackingInstances().unshift( this ); 12686 }, 12687 12688 _untrackInstance: function() { 12689 var instances = this._trackingInstances(), 12690 exists = $.inArray( this, instances ); 12691 if ( exists !== -1 ) { 12692 instances.splice( exists, 1 ); 12693 } 12694 }, 12695 12696 _trackingInstances: function() { 12697 var instances = this.document.data( "ui-dialog-instances" ); 12698 if ( !instances ) { 12699 instances = []; 12700 this.document.data( "ui-dialog-instances", instances ); 12701 } 12702 return instances; 12703 }, 12704 12705 _minHeight: function() { 12706 var options = this.options; 12707 12708 return options.height === "auto" ? 12709 options.minHeight : 12710 Math.min( options.minHeight, options.height ); 12711 }, 12712 12713 _position: function() { 12714 12715 // Need to show the dialog to get the actual offset in the position plugin 12716 var isVisible = this.uiDialog.is( ":visible" ); 12717 if ( !isVisible ) { 12718 this.uiDialog.show(); 12719 } 12720 this.uiDialog.position( this.options.position ); 12721 if ( !isVisible ) { 12722 this.uiDialog.hide(); 12723 } 12724 }, 12725 12726 _setOptions: function( options ) { 12727 var that = this, 12728 resize = false, 12729 resizableOptions = {}; 12730 12731 $.each( options, function( key, value ) { 12732 that._setOption( key, value ); 12733 12734 if ( key in that.sizeRelatedOptions ) { 12735 resize = true; 12736 } 12737 if ( key in that.resizableRelatedOptions ) { 12738 resizableOptions[ key ] = value; 12739 } 12740 } ); 12741 12742 if ( resize ) { 12743 this._size(); 12744 this._position(); 12745 } 12746 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12747 this.uiDialog.resizable( "option", resizableOptions ); 12748 } 12749 }, 12750 12751 _setOption: function( key, value ) { 12752 var isDraggable, isResizable, 12753 uiDialog = this.uiDialog; 12754 12755 if ( key === "disabled" ) { 12756 return; 12757 } 12758 12759 this._super( key, value ); 12760 12761 if ( key === "appendTo" ) { 12762 this.uiDialog.appendTo( this._appendTo() ); 12763 } 12764 12765 if ( key === "buttons" ) { 12766 this._createButtons(); 12767 } 12768 12769 if ( key === "closeText" ) { 12770 this.uiDialogTitlebarClose.button( { 12771 12772 // Ensure that we always pass a string 12773 label: $( "<a>" ).text( "" + this.options.closeText ).html() 12774 } ); 12775 } 12776 12777 if ( key === "draggable" ) { 12778 isDraggable = uiDialog.is( ":data(ui-draggable)" ); 12779 if ( isDraggable && !value ) { 12780 uiDialog.draggable( "destroy" ); 12781 } 12782 12783 if ( !isDraggable && value ) { 12784 this._makeDraggable(); 12785 } 12786 } 12787 12788 if ( key === "position" ) { 12789 this._position(); 12790 } 12791 12792 if ( key === "resizable" ) { 12793 12794 // currently resizable, becoming non-resizable 12795 isResizable = uiDialog.is( ":data(ui-resizable)" ); 12796 if ( isResizable && !value ) { 12797 uiDialog.resizable( "destroy" ); 12798 } 12799 12800 // Currently resizable, changing handles 12801 if ( isResizable && typeof value === "string" ) { 12802 uiDialog.resizable( "option", "handles", value ); 12803 } 12804 12805 // Currently non-resizable, becoming resizable 12806 if ( !isResizable && value !== false ) { 12807 this._makeResizable(); 12808 } 12809 } 12810 12811 if ( key === "title" ) { 12812 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); 12813 } 12814 12815 if ( key === "modal" ) { 12816 uiDialog.attr( "aria-modal", value ? "true" : null ); 12817 } 12818 }, 12819 12820 _size: function() { 12821 12822 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 12823 // divs will both have width and height set, so we need to reset them 12824 var nonContentHeight, minContentHeight, maxContentHeight, 12825 options = this.options; 12826 12827 // Reset content sizing 12828 this.element.show().css( { 12829 width: "auto", 12830 minHeight: 0, 12831 maxHeight: "none", 12832 height: 0 12833 } ); 12834 12835 if ( options.minWidth > options.width ) { 12836 options.width = options.minWidth; 12837 } 12838 12839 // Reset wrapper sizing 12840 // determine the height of all the non-content elements 12841 nonContentHeight = this.uiDialog.css( { 12842 height: "auto", 12843 width: options.width 12844 } ) 12845 .outerHeight(); 12846 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 12847 maxContentHeight = typeof options.maxHeight === "number" ? 12848 Math.max( 0, options.maxHeight - nonContentHeight ) : 12849 "none"; 12850 12851 if ( options.height === "auto" ) { 12852 this.element.css( { 12853 minHeight: minContentHeight, 12854 maxHeight: maxContentHeight, 12855 height: "auto" 12856 } ); 12857 } else { 12858 this.element.height( Math.max( 0, options.height - nonContentHeight ) ); 12859 } 12860 12861 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12862 this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); 12863 } 12864 }, 12865 12866 _blockFrames: function() { 12867 this.iframeBlocks = this.document.find( "iframe" ).map( function() { 12868 var iframe = $( this ); 12869 12870 return $( "<div>" ) 12871 .css( { 12872 position: "absolute", 12873 width: iframe.outerWidth(), 12874 height: iframe.outerHeight() 12875 } ) 12876 .appendTo( iframe.parent() ) 12877 .offset( iframe.offset() )[ 0 ]; 12878 } ); 12879 }, 12880 12881 _unblockFrames: function() { 12882 if ( this.iframeBlocks ) { 12883 this.iframeBlocks.remove(); 12884 delete this.iframeBlocks; 12885 } 12886 }, 12887 12888 _allowInteraction: function( event ) { 12889 if ( $( event.target ).closest( ".ui-dialog" ).length ) { 12890 return true; 12891 } 12892 12893 // TODO: Remove hack when datepicker implements 12894 // the .ui-front logic (#8989) 12895 return !!$( event.target ).closest( ".ui-datepicker" ).length; 12896 }, 12897 12898 _createOverlay: function() { 12899 if ( !this.options.modal ) { 12900 return; 12901 } 12902 12903 // We use a delay in case the overlay is created from an 12904 // event that we're going to be cancelling (#2804) 12905 var isOpening = true; 12906 this._delay( function() { 12907 isOpening = false; 12908 } ); 12909 12910 if ( !this.document.data( "ui-dialog-overlays" ) ) { 12911 12912 // Prevent use of anchors and inputs 12913 // This doesn't use `_on()` because it is a shared event handler 12914 // across all open modal dialogs. 12915 this.document.on( "focusin.ui-dialog", function( event ) { 12916 if ( isOpening ) { 12917 return; 12918 } 12919 12920 var instance = this._trackingInstances()[ 0 ]; 12921 if ( !instance._allowInteraction( event ) ) { 12922 event.preventDefault(); 12923 instance._focusTabbable(); 12924 } 12925 }.bind( this ) ); 12926 } 12927 12928 this.overlay = $( "<div>" ) 12929 .appendTo( this._appendTo() ); 12930 12931 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" ); 12932 this._on( this.overlay, { 12933 mousedown: "_keepFocus" 12934 } ); 12935 this.document.data( "ui-dialog-overlays", 12936 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 ); 12937 }, 12938 12939 _destroyOverlay: function() { 12940 if ( !this.options.modal ) { 12941 return; 12942 } 12943 12944 if ( this.overlay ) { 12945 var overlays = this.document.data( "ui-dialog-overlays" ) - 1; 12946 12947 if ( !overlays ) { 12948 this.document.off( "focusin.ui-dialog" ); 12949 this.document.removeData( "ui-dialog-overlays" ); 12950 } else { 12951 this.document.data( "ui-dialog-overlays", overlays ); 12952 } 12953 12954 this.overlay.remove(); 12955 this.overlay = null; 12956 } 12957 } 12958 } ); 12959 12960// DEPRECATED 12961// TODO: switch return back to widget declaration at top of file when this is removed 12962 if ( $.uiBackCompat === true ) { 12963 12964 // Backcompat for dialogClass option 12965 $.widget( "ui.dialog", $.ui.dialog, { 12966 options: { 12967 dialogClass: "" 12968 }, 12969 _createWrapper: function() { 12970 this._super(); 12971 this.uiDialog.addClass( this.options.dialogClass ); 12972 }, 12973 _setOption: function( key, value ) { 12974 if ( key === "dialogClass" ) { 12975 this.uiDialog 12976 .removeClass( this.options.dialogClass ) 12977 .addClass( value ); 12978 } 12979 this._superApply( arguments ); 12980 } 12981 } ); 12982 } 12983 12984 var widgetsDialog = $.ui.dialog; 12985 12986 12987 /*! 12988 * jQuery UI Droppable 1.14.1 12989 * https://jqueryui.com 12990 * 12991 * Copyright OpenJS Foundation and other contributors 12992 * Released under the MIT license. 12993 * https://jquery.org/license 12994 */ 12995 12996//>>label: Droppable 12997//>>group: Interactions 12998//>>description: Enables drop targets for draggable elements. 12999//>>docs: https://api.jqueryui.com/droppable/ 13000//>>demos: https://jqueryui.com/droppable/ 13001 13002 13003 $.widget( "ui.droppable", { 13004 version: "1.14.1", 13005 widgetEventPrefix: "drop", 13006 options: { 13007 accept: "*", 13008 addClasses: true, 13009 greedy: false, 13010 scope: "default", 13011 tolerance: "intersect", 13012 13013 // Callbacks 13014 activate: null, 13015 deactivate: null, 13016 drop: null, 13017 out: null, 13018 over: null 13019 }, 13020 _create: function() { 13021 13022 var proportions, 13023 o = this.options, 13024 accept = o.accept; 13025 13026 this.isover = false; 13027 this.isout = true; 13028 13029 this.accept = typeof accept === "function" ? accept : function( d ) { 13030 return d.is( accept ); 13031 }; 13032 13033 this.proportions = function( /* valueToWrite */ ) { 13034 if ( arguments.length ) { 13035 13036 // Store the droppable's proportions 13037 proportions = arguments[ 0 ]; 13038 } else { 13039 13040 // Retrieve or derive the droppable's proportions 13041 return proportions ? 13042 proportions : 13043 proportions = { 13044 width: this.element[ 0 ].offsetWidth, 13045 height: this.element[ 0 ].offsetHeight 13046 }; 13047 } 13048 }; 13049 13050 this._addToManager( o.scope ); 13051 13052 if ( o.addClasses ) { 13053 this._addClass( "ui-droppable" ); 13054 } 13055 13056 }, 13057 13058 _addToManager: function( scope ) { 13059 13060 // Add the reference and positions to the manager 13061 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; 13062 $.ui.ddmanager.droppables[ scope ].push( this ); 13063 }, 13064 13065 _splice: function( drop ) { 13066 var i = 0; 13067 for ( ; i < drop.length; i++ ) { 13068 if ( drop[ i ] === this ) { 13069 drop.splice( i, 1 ); 13070 } 13071 } 13072 }, 13073 13074 _destroy: function() { 13075 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 13076 13077 this._splice( drop ); 13078 }, 13079 13080 _setOption: function( key, value ) { 13081 13082 if ( key === "accept" ) { 13083 this.accept = typeof value === "function" ? value : function( d ) { 13084 return d.is( value ); 13085 }; 13086 } else if ( key === "scope" ) { 13087 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 13088 13089 this._splice( drop ); 13090 this._addToManager( value ); 13091 } 13092 13093 this._super( key, value ); 13094 }, 13095 13096 _activate: function( event ) { 13097 var draggable = $.ui.ddmanager.current; 13098 13099 this._addActiveClass(); 13100 if ( draggable ) { 13101 this._trigger( "activate", event, this.ui( draggable ) ); 13102 } 13103 }, 13104 13105 _deactivate: function( event ) { 13106 var draggable = $.ui.ddmanager.current; 13107 13108 this._removeActiveClass(); 13109 if ( draggable ) { 13110 this._trigger( "deactivate", event, this.ui( draggable ) ); 13111 } 13112 }, 13113 13114 _over: function( event ) { 13115 13116 var draggable = $.ui.ddmanager.current; 13117 13118 // Bail if draggable and droppable are same element 13119 if ( !draggable || ( draggable.currentItem || 13120 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13121 return; 13122 } 13123 13124 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 13125 draggable.element ) ) ) { 13126 this._addHoverClass(); 13127 this._trigger( "over", event, this.ui( draggable ) ); 13128 } 13129 13130 }, 13131 13132 _out: function( event ) { 13133 13134 var draggable = $.ui.ddmanager.current; 13135 13136 // Bail if draggable and droppable are same element 13137 if ( !draggable || ( draggable.currentItem || 13138 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13139 return; 13140 } 13141 13142 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 13143 draggable.element ) ) ) { 13144 this._removeHoverClass(); 13145 this._trigger( "out", event, this.ui( draggable ) ); 13146 } 13147 13148 }, 13149 13150 _drop: function( event, custom ) { 13151 13152 var draggable = custom || $.ui.ddmanager.current, 13153 childrenIntersection = false; 13154 13155 // Bail if draggable and droppable are same element 13156 if ( !draggable || ( draggable.currentItem || 13157 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13158 return false; 13159 } 13160 13161 this.element 13162 .find( ":data(ui-droppable)" ) 13163 .not( ".ui-draggable-dragging" ) 13164 .each( function() { 13165 var inst = $( this ).droppable( "instance" ); 13166 if ( 13167 inst.options.greedy && 13168 !inst.options.disabled && 13169 inst.options.scope === draggable.options.scope && 13170 inst.accept.call( 13171 inst.element[ 0 ], ( draggable.currentItem || draggable.element ) 13172 ) && 13173 $.ui.intersect( 13174 draggable, 13175 $.extend( inst, { offset: inst.element.offset() } ), 13176 inst.options.tolerance, event 13177 ) 13178 ) { 13179 childrenIntersection = true; 13180 return false; 13181 } 13182 } ); 13183 if ( childrenIntersection ) { 13184 return false; 13185 } 13186 13187 if ( this.accept.call( this.element[ 0 ], 13188 ( draggable.currentItem || draggable.element ) ) ) { 13189 this._removeActiveClass(); 13190 this._removeHoverClass(); 13191 13192 this._trigger( "drop", event, this.ui( draggable ) ); 13193 return this.element; 13194 } 13195 13196 return false; 13197 13198 }, 13199 13200 ui: function( c ) { 13201 return { 13202 draggable: ( c.currentItem || c.element ), 13203 helper: c.helper, 13204 position: c.position, 13205 offset: c.positionAbs 13206 }; 13207 }, 13208 13209 // Extension points just to make backcompat sane and avoid duplicating logic 13210 // TODO: Remove in 1.14 along with call to it below 13211 _addHoverClass: function() { 13212 this._addClass( "ui-droppable-hover" ); 13213 }, 13214 13215 _removeHoverClass: function() { 13216 this._removeClass( "ui-droppable-hover" ); 13217 }, 13218 13219 _addActiveClass: function() { 13220 this._addClass( "ui-droppable-active" ); 13221 }, 13222 13223 _removeActiveClass: function() { 13224 this._removeClass( "ui-droppable-active" ); 13225 } 13226 } ); 13227 13228 $.ui.intersect = ( function() { 13229 function isOverAxis( x, reference, size ) { 13230 return ( x >= reference ) && ( x < ( reference + size ) ); 13231 } 13232 13233 return function( draggable, droppable, toleranceMode, event ) { 13234 13235 if ( !droppable.offset ) { 13236 return false; 13237 } 13238 13239 var x1 = ( draggable.positionAbs || 13240 draggable.position.absolute ).left + draggable.margins.left, 13241 y1 = ( draggable.positionAbs || 13242 draggable.position.absolute ).top + draggable.margins.top, 13243 x2 = x1 + draggable.helperProportions.width, 13244 y2 = y1 + draggable.helperProportions.height, 13245 l = droppable.offset.left, 13246 t = droppable.offset.top, 13247 r = l + droppable.proportions().width, 13248 b = t + droppable.proportions().height; 13249 13250 switch ( toleranceMode ) { 13251 case "fit": 13252 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); 13253 case "intersect": 13254 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half 13255 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half 13256 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half 13257 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half 13258 case "pointer": 13259 return isOverAxis( event.pageY, t, droppable.proportions().height ) && 13260 isOverAxis( event.pageX, l, droppable.proportions().width ); 13261 case "touch": 13262 return ( 13263 ( y1 >= t && y1 <= b ) || // Top edge touching 13264 ( y2 >= t && y2 <= b ) || // Bottom edge touching 13265 ( y1 < t && y2 > b ) // Surrounded vertically 13266 ) && ( 13267 ( x1 >= l && x1 <= r ) || // Left edge touching 13268 ( x2 >= l && x2 <= r ) || // Right edge touching 13269 ( x1 < l && x2 > r ) // Surrounded horizontally 13270 ); 13271 default: 13272 return false; 13273 } 13274 }; 13275 } )(); 13276 13277 /* 13278 This manager tracks offsets of draggables and droppables 13279*/ 13280 $.ui.ddmanager = { 13281 current: null, 13282 droppables: { "default": [] }, 13283 prepareOffsets: function( t, event ) { 13284 13285 var i, j, 13286 m = $.ui.ddmanager.droppables[ t.options.scope ] || [], 13287 type = event ? event.type : null, // workaround for #2317 13288 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); 13289 13290 droppablesLoop: for ( i = 0; i < m.length; i++ ) { 13291 13292 // No disabled and non-accepted 13293 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], 13294 ( t.currentItem || t.element ) ) ) ) { 13295 continue; 13296 } 13297 13298 // Filter out elements in the current dragged item 13299 for ( j = 0; j < list.length; j++ ) { 13300 if ( list[ j ] === m[ i ].element[ 0 ] ) { 13301 m[ i ].proportions().height = 0; 13302 continue droppablesLoop; 13303 } 13304 } 13305 13306 m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; 13307 if ( !m[ i ].visible ) { 13308 continue; 13309 } 13310 13311 // Activate the droppable if used directly from draggables 13312 if ( type === "mousedown" ) { 13313 m[ i ]._activate.call( m[ i ], event ); 13314 } 13315 13316 m[ i ].offset = m[ i ].element.offset(); 13317 m[ i ].proportions( { 13318 width: m[ i ].element[ 0 ].offsetWidth, 13319 height: m[ i ].element[ 0 ].offsetHeight 13320 } ); 13321 13322 } 13323 13324 }, 13325 drop: function( draggable, event ) { 13326 13327 var dropped = false; 13328 13329 // Create a copy of the droppables in case the list changes during the drop (#9116) 13330 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { 13331 13332 if ( !this.options ) { 13333 return; 13334 } 13335 if ( !this.options.disabled && this.visible && 13336 $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { 13337 dropped = this._drop.call( this, event ) || dropped; 13338 } 13339 13340 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], 13341 ( draggable.currentItem || draggable.element ) ) ) { 13342 this.isout = true; 13343 this.isover = false; 13344 this._deactivate.call( this, event ); 13345 } 13346 13347 } ); 13348 return dropped; 13349 13350 }, 13351 dragStart: function( draggable, event ) { 13352 13353 // Listen for scrolling so that if the dragging causes scrolling the position of the 13354 // droppables can be recalculated (see #5003) 13355 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() { 13356 if ( !draggable.options.refreshPositions ) { 13357 $.ui.ddmanager.prepareOffsets( draggable, event ); 13358 } 13359 } ); 13360 }, 13361 drag: function( draggable, event ) { 13362 13363 // If you have a highly dynamic page, you might try this option. It renders positions 13364 // every time you move the mouse. 13365 if ( draggable.options.refreshPositions ) { 13366 $.ui.ddmanager.prepareOffsets( draggable, event ); 13367 } 13368 13369 // Run through all droppables and check their positions based on specific tolerance options 13370 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { 13371 13372 if ( this.options.disabled || this.greedyChild || !this.visible ) { 13373 return; 13374 } 13375 13376 var parentInstance, scope, parent, 13377 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), 13378 c = !intersects && this.isover ? 13379 "isout" : 13380 ( intersects && !this.isover ? "isover" : null ); 13381 if ( !c ) { 13382 return; 13383 } 13384 13385 if ( this.options.greedy ) { 13386 13387 // find droppable parents with same scope 13388 scope = this.options.scope; 13389 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() { 13390 return $( this ).droppable( "instance" ).options.scope === scope; 13391 } ); 13392 13393 if ( parent.length ) { 13394 parentInstance = $( parent[ 0 ] ).droppable( "instance" ); 13395 parentInstance.greedyChild = ( c === "isover" ); 13396 } 13397 } 13398 13399 // We just moved into a greedy child 13400 if ( parentInstance && c === "isover" ) { 13401 parentInstance.isover = false; 13402 parentInstance.isout = true; 13403 parentInstance._out.call( parentInstance, event ); 13404 } 13405 13406 this[ c ] = true; 13407 this[ c === "isout" ? "isover" : "isout" ] = false; 13408 this[ c === "isover" ? "_over" : "_out" ].call( this, event ); 13409 13410 // We just moved out of a greedy child 13411 if ( parentInstance && c === "isout" ) { 13412 parentInstance.isout = false; 13413 parentInstance.isover = true; 13414 parentInstance._over.call( parentInstance, event ); 13415 } 13416 } ); 13417 13418 }, 13419 dragStop: function( draggable, event ) { 13420 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" ); 13421 13422 // Call prepareOffsets one final time since IE does not fire return scroll events when 13423 // overflow was caused by drag (see #5003) 13424 if ( !draggable.options.refreshPositions ) { 13425 $.ui.ddmanager.prepareOffsets( draggable, event ); 13426 } 13427 } 13428 }; 13429 13430// DEPRECATED 13431// TODO: switch return back to widget declaration at top of file when this is removed 13432 if ( $.uiBackCompat === true ) { 13433 13434 // Backcompat for activeClass and hoverClass options 13435 $.widget( "ui.droppable", $.ui.droppable, { 13436 options: { 13437 hoverClass: false, 13438 activeClass: false 13439 }, 13440 _addActiveClass: function() { 13441 this._super(); 13442 if ( this.options.activeClass ) { 13443 this.element.addClass( this.options.activeClass ); 13444 } 13445 }, 13446 _removeActiveClass: function() { 13447 this._super(); 13448 if ( this.options.activeClass ) { 13449 this.element.removeClass( this.options.activeClass ); 13450 } 13451 }, 13452 _addHoverClass: function() { 13453 this._super(); 13454 if ( this.options.hoverClass ) { 13455 this.element.addClass( this.options.hoverClass ); 13456 } 13457 }, 13458 _removeHoverClass: function() { 13459 this._super(); 13460 if ( this.options.hoverClass ) { 13461 this.element.removeClass( this.options.hoverClass ); 13462 } 13463 } 13464 } ); 13465 } 13466 13467 var widgetsDroppable = $.ui.droppable; 13468 13469 13470 /*! 13471 * jQuery UI Progressbar 1.14.1 13472 * https://jqueryui.com 13473 * 13474 * Copyright OpenJS Foundation and other contributors 13475 * Released under the MIT license. 13476 * https://jquery.org/license 13477 */ 13478 13479//>>label: Progressbar 13480//>>group: Widgets 13481 /* eslint-disable max-len */ 13482//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators. 13483 /* eslint-enable max-len */ 13484//>>docs: https://api.jqueryui.com/progressbar/ 13485//>>demos: https://jqueryui.com/progressbar/ 13486//>>css.structure: ../../themes/base/core.css 13487//>>css.structure: ../../themes/base/progressbar.css 13488//>>css.theme: ../../themes/base/theme.css 13489 13490 13491 var widgetsProgressbar = $.widget( "ui.progressbar", { 13492 version: "1.14.1", 13493 options: { 13494 classes: { 13495 "ui-progressbar": "ui-corner-all", 13496 "ui-progressbar-value": "ui-corner-left", 13497 "ui-progressbar-complete": "ui-corner-right" 13498 }, 13499 max: 100, 13500 value: 0, 13501 13502 change: null, 13503 complete: null 13504 }, 13505 13506 min: 0, 13507 13508 _create: function() { 13509 13510 // Constrain initial value 13511 this.oldValue = this.options.value = this._constrainedValue(); 13512 13513 this.element.attr( { 13514 13515 // Only set static values; aria-valuenow and aria-valuemax are 13516 // set inside _refreshValue() 13517 role: "progressbar", 13518 "aria-valuemin": this.min 13519 } ); 13520 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" ); 13521 13522 this.valueDiv = $( "<div>" ).appendTo( this.element ); 13523 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" ); 13524 this._refreshValue(); 13525 }, 13526 13527 _destroy: function() { 13528 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" ); 13529 13530 this.valueDiv.remove(); 13531 }, 13532 13533 value: function( newValue ) { 13534 if ( newValue === undefined ) { 13535 return this.options.value; 13536 } 13537 13538 this.options.value = this._constrainedValue( newValue ); 13539 this._refreshValue(); 13540 }, 13541 13542 _constrainedValue: function( newValue ) { 13543 if ( newValue === undefined ) { 13544 newValue = this.options.value; 13545 } 13546 13547 this.indeterminate = newValue === false; 13548 13549 // Sanitize value 13550 if ( typeof newValue !== "number" ) { 13551 newValue = 0; 13552 } 13553 13554 return this.indeterminate ? false : 13555 Math.min( this.options.max, Math.max( this.min, newValue ) ); 13556 }, 13557 13558 _setOptions: function( options ) { 13559 13560 // Ensure "value" option is set after other values (like max) 13561 var value = options.value; 13562 delete options.value; 13563 13564 this._super( options ); 13565 13566 this.options.value = this._constrainedValue( value ); 13567 this._refreshValue(); 13568 }, 13569 13570 _setOption: function( key, value ) { 13571 if ( key === "max" ) { 13572 13573 // Don't allow a max less than min 13574 value = Math.max( this.min, value ); 13575 } 13576 this._super( key, value ); 13577 }, 13578 13579 _setOptionDisabled: function( value ) { 13580 this._super( value ); 13581 13582 this.element.attr( "aria-disabled", value ); 13583 this._toggleClass( null, "ui-state-disabled", !!value ); 13584 }, 13585 13586 _percentage: function() { 13587 return this.indeterminate ? 13588 100 : 13589 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); 13590 }, 13591 13592 _refreshValue: function() { 13593 var value = this.options.value, 13594 percentage = this._percentage(); 13595 13596 this.valueDiv 13597 .toggle( this.indeterminate || value > this.min ) 13598 .width( percentage.toFixed( 0 ) + "%" ); 13599 13600 this 13601 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null, 13602 value === this.options.max ) 13603 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate ); 13604 13605 if ( this.indeterminate ) { 13606 this.element.removeAttr( "aria-valuenow" ); 13607 if ( !this.overlayDiv ) { 13608 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv ); 13609 this._addClass( this.overlayDiv, "ui-progressbar-overlay" ); 13610 } 13611 } else { 13612 this.element.attr( { 13613 "aria-valuemax": this.options.max, 13614 "aria-valuenow": value 13615 } ); 13616 if ( this.overlayDiv ) { 13617 this.overlayDiv.remove(); 13618 this.overlayDiv = null; 13619 } 13620 } 13621 13622 if ( this.oldValue !== value ) { 13623 this.oldValue = value; 13624 this._trigger( "change" ); 13625 } 13626 if ( value === this.options.max ) { 13627 this._trigger( "complete" ); 13628 } 13629 } 13630 } ); 13631 13632 13633 /*! 13634 * jQuery UI Selectable 1.14.1 13635 * https://jqueryui.com 13636 * 13637 * Copyright OpenJS Foundation and other contributors 13638 * Released under the MIT license. 13639 * https://jquery.org/license 13640 */ 13641 13642//>>label: Selectable 13643//>>group: Interactions 13644//>>description: Allows groups of elements to be selected with the mouse. 13645//>>docs: https://api.jqueryui.com/selectable/ 13646//>>demos: https://jqueryui.com/selectable/ 13647//>>css.structure: ../../themes/base/selectable.css 13648 13649 13650 var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, { 13651 version: "1.14.1", 13652 options: { 13653 appendTo: "body", 13654 autoRefresh: true, 13655 distance: 0, 13656 filter: "*", 13657 tolerance: "touch", 13658 13659 // Callbacks 13660 selected: null, 13661 selecting: null, 13662 start: null, 13663 stop: null, 13664 unselected: null, 13665 unselecting: null 13666 }, 13667 _create: function() { 13668 var that = this; 13669 13670 this._addClass( "ui-selectable" ); 13671 13672 this.dragged = false; 13673 13674 // Cache selectee children based on filter 13675 this.refresh = function() { 13676 that.elementPos = $( that.element[ 0 ] ).offset(); 13677 that.selectees = $( that.options.filter, that.element[ 0 ] ); 13678 that._addClass( that.selectees, "ui-selectee" ); 13679 that.selectees.each( function() { 13680 var $this = $( this ), 13681 selecteeOffset = $this.offset(), 13682 pos = { 13683 left: selecteeOffset.left - that.elementPos.left, 13684 top: selecteeOffset.top - that.elementPos.top 13685 }; 13686 $.data( this, "selectable-item", { 13687 element: this, 13688 $element: $this, 13689 left: pos.left, 13690 top: pos.top, 13691 right: pos.left + $this.outerWidth(), 13692 bottom: pos.top + $this.outerHeight(), 13693 startselected: false, 13694 selected: $this.hasClass( "ui-selected" ), 13695 selecting: $this.hasClass( "ui-selecting" ), 13696 unselecting: $this.hasClass( "ui-unselecting" ) 13697 } ); 13698 } ); 13699 }; 13700 this.refresh(); 13701 13702 this._mouseInit(); 13703 13704 this.helper = $( "<div>" ); 13705 this._addClass( this.helper, "ui-selectable-helper" ); 13706 }, 13707 13708 _destroy: function() { 13709 this.selectees.removeData( "selectable-item" ); 13710 this._mouseDestroy(); 13711 }, 13712 13713 _mouseStart: function( event ) { 13714 var that = this, 13715 options = this.options; 13716 13717 this.opos = [ event.pageX, event.pageY ]; 13718 this.elementPos = $( this.element[ 0 ] ).offset(); 13719 13720 if ( this.options.disabled ) { 13721 return; 13722 } 13723 13724 this.selectees = $( options.filter, this.element[ 0 ] ); 13725 13726 this._trigger( "start", event ); 13727 13728 $( options.appendTo ).append( this.helper ); 13729 13730 // position helper (lasso) 13731 this.helper.css( { 13732 "left": event.pageX, 13733 "top": event.pageY, 13734 "width": 0, 13735 "height": 0 13736 } ); 13737 13738 if ( options.autoRefresh ) { 13739 this.refresh(); 13740 } 13741 13742 this.selectees.filter( ".ui-selected" ).each( function() { 13743 var selectee = $.data( this, "selectable-item" ); 13744 selectee.startselected = true; 13745 if ( !event.metaKey && !event.ctrlKey ) { 13746 that._removeClass( selectee.$element, "ui-selected" ); 13747 selectee.selected = false; 13748 that._addClass( selectee.$element, "ui-unselecting" ); 13749 selectee.unselecting = true; 13750 13751 // selectable UNSELECTING callback 13752 that._trigger( "unselecting", event, { 13753 unselecting: selectee.element 13754 } ); 13755 } 13756 } ); 13757 13758 $( event.target ).parents().addBack().each( function() { 13759 var doSelect, 13760 selectee = $.data( this, "selectable-item" ); 13761 if ( selectee ) { 13762 doSelect = ( !event.metaKey && !event.ctrlKey ) || 13763 !selectee.$element.hasClass( "ui-selected" ); 13764 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" ) 13765 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" ); 13766 selectee.unselecting = !doSelect; 13767 selectee.selecting = doSelect; 13768 selectee.selected = doSelect; 13769 13770 // selectable (UN)SELECTING callback 13771 if ( doSelect ) { 13772 that._trigger( "selecting", event, { 13773 selecting: selectee.element 13774 } ); 13775 } else { 13776 that._trigger( "unselecting", event, { 13777 unselecting: selectee.element 13778 } ); 13779 } 13780 return false; 13781 } 13782 } ); 13783 13784 }, 13785 13786 _mouseDrag: function( event ) { 13787 13788 this.dragged = true; 13789 13790 if ( this.options.disabled ) { 13791 return; 13792 } 13793 13794 var tmp, 13795 that = this, 13796 options = this.options, 13797 x1 = this.opos[ 0 ], 13798 y1 = this.opos[ 1 ], 13799 x2 = event.pageX, 13800 y2 = event.pageY; 13801 13802 if ( x1 > x2 ) { 13803 tmp = x2; x2 = x1; x1 = tmp; 13804 } 13805 if ( y1 > y2 ) { 13806 tmp = y2; y2 = y1; y1 = tmp; 13807 } 13808 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } ); 13809 13810 this.selectees.each( function() { 13811 var selectee = $.data( this, "selectable-item" ), 13812 hit = false, 13813 offset = {}; 13814 13815 //prevent helper from being selected if appendTo: selectable 13816 if ( !selectee || selectee.element === that.element[ 0 ] ) { 13817 return; 13818 } 13819 13820 offset.left = selectee.left + that.elementPos.left; 13821 offset.right = selectee.right + that.elementPos.left; 13822 offset.top = selectee.top + that.elementPos.top; 13823 offset.bottom = selectee.bottom + that.elementPos.top; 13824 13825 if ( options.tolerance === "touch" ) { 13826 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 || 13827 offset.bottom < y1 ) ); 13828 } else if ( options.tolerance === "fit" ) { 13829 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 && 13830 offset.bottom < y2 ); 13831 } 13832 13833 if ( hit ) { 13834 13835 // SELECT 13836 if ( selectee.selected ) { 13837 that._removeClass( selectee.$element, "ui-selected" ); 13838 selectee.selected = false; 13839 } 13840 if ( selectee.unselecting ) { 13841 that._removeClass( selectee.$element, "ui-unselecting" ); 13842 selectee.unselecting = false; 13843 } 13844 if ( !selectee.selecting ) { 13845 that._addClass( selectee.$element, "ui-selecting" ); 13846 selectee.selecting = true; 13847 13848 // selectable SELECTING callback 13849 that._trigger( "selecting", event, { 13850 selecting: selectee.element 13851 } ); 13852 } 13853 } else { 13854 13855 // UNSELECT 13856 if ( selectee.selecting ) { 13857 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) { 13858 that._removeClass( selectee.$element, "ui-selecting" ); 13859 selectee.selecting = false; 13860 that._addClass( selectee.$element, "ui-selected" ); 13861 selectee.selected = true; 13862 } else { 13863 that._removeClass( selectee.$element, "ui-selecting" ); 13864 selectee.selecting = false; 13865 if ( selectee.startselected ) { 13866 that._addClass( selectee.$element, "ui-unselecting" ); 13867 selectee.unselecting = true; 13868 } 13869 13870 // selectable UNSELECTING callback 13871 that._trigger( "unselecting", event, { 13872 unselecting: selectee.element 13873 } ); 13874 } 13875 } 13876 if ( selectee.selected ) { 13877 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) { 13878 that._removeClass( selectee.$element, "ui-selected" ); 13879 selectee.selected = false; 13880 13881 that._addClass( selectee.$element, "ui-unselecting" ); 13882 selectee.unselecting = true; 13883 13884 // selectable UNSELECTING callback 13885 that._trigger( "unselecting", event, { 13886 unselecting: selectee.element 13887 } ); 13888 } 13889 } 13890 } 13891 } ); 13892 13893 return false; 13894 }, 13895 13896 _mouseStop: function( event ) { 13897 var that = this; 13898 13899 this.dragged = false; 13900 13901 $( ".ui-unselecting", this.element[ 0 ] ).each( function() { 13902 var selectee = $.data( this, "selectable-item" ); 13903 that._removeClass( selectee.$element, "ui-unselecting" ); 13904 selectee.unselecting = false; 13905 selectee.startselected = false; 13906 that._trigger( "unselected", event, { 13907 unselected: selectee.element 13908 } ); 13909 } ); 13910 $( ".ui-selecting", this.element[ 0 ] ).each( function() { 13911 var selectee = $.data( this, "selectable-item" ); 13912 that._removeClass( selectee.$element, "ui-selecting" ) 13913 ._addClass( selectee.$element, "ui-selected" ); 13914 selectee.selecting = false; 13915 selectee.selected = true; 13916 selectee.startselected = true; 13917 that._trigger( "selected", event, { 13918 selected: selectee.element 13919 } ); 13920 } ); 13921 this._trigger( "stop", event ); 13922 13923 this.helper.remove(); 13924 13925 return false; 13926 } 13927 13928 } ); 13929 13930 13931 /*! 13932 * jQuery UI Selectmenu 1.14.1 13933 * https://jqueryui.com 13934 * 13935 * Copyright OpenJS Foundation and other contributors 13936 * Released under the MIT license. 13937 * https://jquery.org/license 13938 */ 13939 13940//>>label: Selectmenu 13941//>>group: Widgets 13942 /* eslint-disable max-len */ 13943//>>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. 13944 /* eslint-enable max-len */ 13945//>>docs: https://api.jqueryui.com/selectmenu/ 13946//>>demos: https://jqueryui.com/selectmenu/ 13947//>>css.structure: ../../themes/base/core.css 13948//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css 13949//>>css.theme: ../../themes/base/theme.css 13950 13951 13952 var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, { 13953 version: "1.14.1", 13954 defaultElement: "<select>", 13955 options: { 13956 appendTo: null, 13957 classes: { 13958 "ui-selectmenu-button-open": "ui-corner-top", 13959 "ui-selectmenu-button-closed": "ui-corner-all" 13960 }, 13961 disabled: null, 13962 icons: { 13963 button: "ui-icon-triangle-1-s" 13964 }, 13965 position: { 13966 my: "left top", 13967 at: "left bottom", 13968 collision: "none" 13969 }, 13970 width: false, 13971 13972 // Callbacks 13973 change: null, 13974 close: null, 13975 focus: null, 13976 open: null, 13977 select: null 13978 }, 13979 13980 _create: function() { 13981 var selectmenuId = this.element.uniqueId().attr( "id" ); 13982 this.ids = { 13983 element: selectmenuId, 13984 button: selectmenuId + "-button", 13985 menu: selectmenuId + "-menu" 13986 }; 13987 13988 this._drawButton(); 13989 this._drawMenu(); 13990 this._bindFormResetHandler(); 13991 13992 this._rendered = false; 13993 this.menuItems = $(); 13994 }, 13995 13996 _drawButton: function() { 13997 var icon, 13998 that = this, 13999 item = this._parseOption( 14000 this.element.find( "option:selected" ), 14001 this.element[ 0 ].selectedIndex 14002 ); 14003 14004 // Associate existing label with the new button 14005 this.labels = this.element.labels().attr( "for", this.ids.button ); 14006 this._on( this.labels, { 14007 click: function( event ) { 14008 this.button.trigger( "focus" ); 14009 event.preventDefault(); 14010 } 14011 } ); 14012 14013 // Hide original select element 14014 this.element.hide(); 14015 14016 // Create button 14017 this.button = $( "<span>", { 14018 tabindex: this.options.disabled ? -1 : 0, 14019 id: this.ids.button, 14020 role: "combobox", 14021 "aria-expanded": "false", 14022 "aria-autocomplete": "list", 14023 "aria-owns": this.ids.menu, 14024 "aria-haspopup": "true", 14025 title: this.element.attr( "title" ) 14026 } ) 14027 .insertAfter( this.element ); 14028 14029 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed", 14030 "ui-button ui-widget" ); 14031 14032 icon = $( "<span>" ).appendTo( this.button ); 14033 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button ); 14034 this.buttonItem = this._renderButtonItem( item ) 14035 .appendTo( this.button ); 14036 14037 if ( this.options.width !== false ) { 14038 this._resizeButton(); 14039 } 14040 14041 this._on( this.button, this._buttonEvents ); 14042 this.button.one( "focusin", function() { 14043 14044 // Delay rendering the menu items until the button receives focus. 14045 // The menu may have already been rendered via a programmatic open. 14046 if ( !that._rendered ) { 14047 that._refreshMenu(); 14048 } 14049 } ); 14050 }, 14051 14052 _drawMenu: function() { 14053 var that = this; 14054 14055 // Create menu 14056 this.menu = $( "<ul>", { 14057 "aria-hidden": "true", 14058 "aria-labelledby": this.ids.button, 14059 id: this.ids.menu 14060 } ); 14061 14062 // Wrap menu 14063 this.menuWrap = $( "<div>" ).append( this.menu ); 14064 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" ); 14065 this.menuWrap.appendTo( this._appendTo() ); 14066 14067 // Initialize menu widget 14068 this.menuInstance = this.menu 14069 .menu( { 14070 classes: { 14071 "ui-menu": "ui-corner-bottom" 14072 }, 14073 role: "listbox", 14074 select: function( event, ui ) { 14075 event.preventDefault(); 14076 that._select( ui.item.data( "ui-selectmenu-item" ), event ); 14077 }, 14078 focus: function( event, ui ) { 14079 var item = ui.item.data( "ui-selectmenu-item" ); 14080 14081 // Prevent inital focus from firing and check if its a newly focused item 14082 if ( that.focusIndex != null && item.index !== that.focusIndex ) { 14083 that._trigger( "focus", event, { item: item } ); 14084 if ( !that.isOpen ) { 14085 that._select( item, event ); 14086 } 14087 } 14088 that.focusIndex = item.index; 14089 14090 that.button.attr( "aria-activedescendant", 14091 that.menuItems.eq( item.index ).attr( "id" ) ); 14092 } 14093 } ) 14094 .menu( "instance" ); 14095 14096 // Don't close the menu on mouseleave 14097 this.menuInstance._off( this.menu, "mouseleave" ); 14098 14099 // Cancel the menu's collapseAll on document click 14100 this.menuInstance._closeOnDocumentClick = function() { 14101 return false; 14102 }; 14103 14104 // Selects often contain empty items, but never contain dividers 14105 this.menuInstance._isDivider = function() { 14106 return false; 14107 }; 14108 }, 14109 14110 refresh: function() { 14111 this._refreshMenu(); 14112 this.buttonItem.replaceWith( 14113 this.buttonItem = this._renderButtonItem( 14114 14115 // Fall back to an empty object in case there are no options 14116 this._getSelectedItem().data( "ui-selectmenu-item" ) || {} 14117 ) 14118 ); 14119 if ( this.options.width === null ) { 14120 this._resizeButton(); 14121 } 14122 }, 14123 14124 _refreshMenu: function() { 14125 var item, 14126 options = this.element.find( "option" ); 14127 14128 this.menu.empty(); 14129 14130 this._parseOptions( options ); 14131 this._renderMenu( this.menu, this.items ); 14132 14133 this.menuInstance.refresh(); 14134 this.menuItems = this.menu.find( "li" ) 14135 .not( ".ui-selectmenu-optgroup" ) 14136 .find( ".ui-menu-item-wrapper" ); 14137 14138 this._rendered = true; 14139 14140 if ( !options.length ) { 14141 return; 14142 } 14143 14144 item = this._getSelectedItem(); 14145 14146 // Update the menu to have the correct item focused 14147 this.menuInstance.focus( null, item ); 14148 this._setAria( item.data( "ui-selectmenu-item" ) ); 14149 14150 // Set disabled state 14151 this._setOption( "disabled", this.element.prop( "disabled" ) ); 14152 }, 14153 14154 open: function( event ) { 14155 if ( this.options.disabled ) { 14156 return; 14157 } 14158 14159 // If this is the first time the menu is being opened, render the items 14160 if ( !this._rendered ) { 14161 this._refreshMenu(); 14162 } else { 14163 14164 // Menu clears focus on close, reset focus to selected item 14165 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" ); 14166 this.menuInstance.focus( null, this._getSelectedItem() ); 14167 } 14168 14169 // If there are no options, don't open the menu 14170 if ( !this.menuItems.length ) { 14171 return; 14172 } 14173 14174 this.isOpen = true; 14175 this._toggleAttr(); 14176 this._resizeMenu(); 14177 this._position(); 14178 14179 this._on( this.document, this._documentClick ); 14180 14181 this._trigger( "open", event ); 14182 }, 14183 14184 _position: function() { 14185 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); 14186 }, 14187 14188 close: function( event ) { 14189 if ( !this.isOpen ) { 14190 return; 14191 } 14192 14193 this.isOpen = false; 14194 this._toggleAttr(); 14195 14196 this.range = null; 14197 this._off( this.document ); 14198 14199 this._trigger( "close", event ); 14200 }, 14201 14202 widget: function() { 14203 return this.button; 14204 }, 14205 14206 menuWidget: function() { 14207 return this.menu; 14208 }, 14209 14210 _renderButtonItem: function( item ) { 14211 var buttonItem = $( "<span>" ); 14212 14213 this._setText( buttonItem, item.label ); 14214 this._addClass( buttonItem, "ui-selectmenu-text" ); 14215 14216 return buttonItem; 14217 }, 14218 14219 _renderMenu: function( ul, items ) { 14220 var that = this, 14221 currentOptgroup = ""; 14222 14223 $.each( items, function( index, item ) { 14224 var li; 14225 14226 if ( item.optgroup !== currentOptgroup ) { 14227 li = $( "<li>", { 14228 text: item.optgroup 14229 } ); 14230 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" + 14231 ( item.element.parent( "optgroup" ).prop( "disabled" ) ? 14232 " ui-state-disabled" : 14233 "" ) ); 14234 14235 li.appendTo( ul ); 14236 14237 currentOptgroup = item.optgroup; 14238 } 14239 14240 that._renderItemData( ul, item ); 14241 } ); 14242 }, 14243 14244 _renderItemData: function( ul, item ) { 14245 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); 14246 }, 14247 14248 _renderItem: function( ul, item ) { 14249 var li = $( "<li>" ), 14250 wrapper = $( "<div>", { 14251 title: item.element.attr( "title" ) 14252 } ); 14253 14254 if ( item.disabled ) { 14255 this._addClass( li, null, "ui-state-disabled" ); 14256 } 14257 14258 if ( item.hidden ) { 14259 li.prop( "hidden", true ); 14260 } else { 14261 this._setText( wrapper, item.label ); 14262 } 14263 14264 return li.append( wrapper ).appendTo( ul ); 14265 }, 14266 14267 _setText: function( element, value ) { 14268 if ( value ) { 14269 element.text( value ); 14270 } else { 14271 element.html( " " ); 14272 } 14273 }, 14274 14275 _move: function( direction, event ) { 14276 var item, next, 14277 filter = ".ui-menu-item"; 14278 14279 if ( this.isOpen ) { 14280 item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14281 } else { 14282 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14283 filter += ":not(.ui-state-disabled)"; 14284 } 14285 14286 if ( direction === "first" || direction === "last" ) { 14287 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); 14288 } else { 14289 next = item[ direction + "All" ]( filter ).eq( 0 ); 14290 } 14291 14292 if ( next.length ) { 14293 this.menuInstance.focus( event, next ); 14294 } 14295 }, 14296 14297 _getSelectedItem: function() { 14298 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14299 }, 14300 14301 _toggle: function( event ) { 14302 this[ this.isOpen ? "close" : "open" ]( event ); 14303 }, 14304 14305 _setSelection: function() { 14306 var selection; 14307 14308 if ( !this.range ) { 14309 return; 14310 } 14311 14312 selection = window.getSelection(); 14313 selection.removeAllRanges(); 14314 selection.addRange( this.range ); 14315 }, 14316 14317 _documentClick: { 14318 mousedown: function( event ) { 14319 if ( !this.isOpen ) { 14320 return; 14321 } 14322 14323 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + 14324 CSS.escape( this.ids.button ) ).length ) { 14325 this.close( event ); 14326 } 14327 } 14328 }, 14329 14330 _buttonEvents: { 14331 14332 // Prevent text selection from being reset when interacting with the selectmenu (#10144) 14333 mousedown: function() { 14334 var selection = window.getSelection(); 14335 if ( selection.rangeCount ) { 14336 this.range = selection.getRangeAt( 0 ); 14337 } 14338 }, 14339 14340 click: function( event ) { 14341 this._setSelection(); 14342 this._toggle( event ); 14343 }, 14344 14345 keydown: function( event ) { 14346 var preventDefault = true; 14347 switch ( event.keyCode ) { 14348 case $.ui.keyCode.TAB: 14349 case $.ui.keyCode.ESCAPE: 14350 this.close( event ); 14351 preventDefault = false; 14352 break; 14353 case $.ui.keyCode.ENTER: 14354 if ( this.isOpen ) { 14355 this._selectFocusedItem( event ); 14356 } 14357 break; 14358 case $.ui.keyCode.UP: 14359 if ( event.altKey ) { 14360 this._toggle( event ); 14361 } else { 14362 this._move( "prev", event ); 14363 } 14364 break; 14365 case $.ui.keyCode.DOWN: 14366 if ( event.altKey ) { 14367 this._toggle( event ); 14368 } else { 14369 this._move( "next", event ); 14370 } 14371 break; 14372 case $.ui.keyCode.SPACE: 14373 if ( this.isOpen ) { 14374 this._selectFocusedItem( event ); 14375 } else { 14376 this._toggle( event ); 14377 } 14378 break; 14379 case $.ui.keyCode.LEFT: 14380 this._move( "prev", event ); 14381 break; 14382 case $.ui.keyCode.RIGHT: 14383 this._move( "next", event ); 14384 break; 14385 case $.ui.keyCode.HOME: 14386 case $.ui.keyCode.PAGE_UP: 14387 this._move( "first", event ); 14388 break; 14389 case $.ui.keyCode.END: 14390 case $.ui.keyCode.PAGE_DOWN: 14391 this._move( "last", event ); 14392 break; 14393 default: 14394 this.menu.trigger( event ); 14395 preventDefault = false; 14396 } 14397 14398 if ( preventDefault ) { 14399 event.preventDefault(); 14400 } 14401 } 14402 }, 14403 14404 _selectFocusedItem: function( event ) { 14405 var item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14406 if ( !item.hasClass( "ui-state-disabled" ) ) { 14407 this._select( item.data( "ui-selectmenu-item" ), event ); 14408 } 14409 }, 14410 14411 _select: function( item, event ) { 14412 var oldIndex = this.element[ 0 ].selectedIndex; 14413 14414 // Change native select element 14415 this.element[ 0 ].selectedIndex = item.index; 14416 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) ); 14417 this._setAria( item ); 14418 this._trigger( "select", event, { item: item } ); 14419 14420 if ( item.index !== oldIndex ) { 14421 this._trigger( "change", event, { item: item } ); 14422 } 14423 14424 this.close( event ); 14425 }, 14426 14427 _setAria: function( item ) { 14428 var id = this.menuItems.eq( item.index ).attr( "id" ); 14429 14430 this.button.attr( { 14431 "aria-labelledby": id, 14432 "aria-activedescendant": id 14433 } ); 14434 this.menu.attr( "aria-activedescendant", id ); 14435 }, 14436 14437 _setOption: function( key, value ) { 14438 if ( key === "icons" ) { 14439 var icon = this.button.find( "span.ui-icon" ); 14440 this._removeClass( icon, null, this.options.icons.button ) 14441 ._addClass( icon, null, value.button ); 14442 } 14443 14444 this._super( key, value ); 14445 14446 if ( key === "appendTo" ) { 14447 this.menuWrap.appendTo( this._appendTo() ); 14448 } 14449 14450 if ( key === "width" ) { 14451 this._resizeButton(); 14452 } 14453 }, 14454 14455 _setOptionDisabled: function( value ) { 14456 this._super( value ); 14457 14458 this.menuInstance.option( "disabled", value ); 14459 this.button.attr( "aria-disabled", value ); 14460 this._toggleClass( this.button, null, "ui-state-disabled", value ); 14461 14462 this.element.prop( "disabled", value ); 14463 if ( value ) { 14464 this.button.attr( "tabindex", -1 ); 14465 this.close(); 14466 } else { 14467 this.button.attr( "tabindex", 0 ); 14468 } 14469 }, 14470 14471 _appendTo: function() { 14472 var element = this.options.appendTo; 14473 14474 if ( element ) { 14475 element = element.jquery || element.nodeType ? 14476 $( element ) : 14477 this.document.find( element ).eq( 0 ); 14478 } 14479 14480 if ( !element || !element[ 0 ] ) { 14481 element = this.element.closest( ".ui-front, dialog" ); 14482 } 14483 14484 if ( !element.length ) { 14485 element = this.document[ 0 ].body; 14486 } 14487 14488 return element; 14489 }, 14490 14491 _toggleAttr: function() { 14492 this.button.attr( "aria-expanded", this.isOpen ); 14493 14494 // We can't use two _toggleClass() calls here, because we need to make sure 14495 // we always remove classes first and add them second, otherwise if both classes have the 14496 // same theme class, it will be removed after we add it. 14497 this._removeClass( this.button, "ui-selectmenu-button-" + 14498 ( this.isOpen ? "closed" : "open" ) ) 14499 ._addClass( this.button, "ui-selectmenu-button-" + 14500 ( this.isOpen ? "open" : "closed" ) ) 14501 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen ); 14502 14503 this.menu.attr( "aria-hidden", !this.isOpen ); 14504 }, 14505 14506 _resizeButton: function() { 14507 var width = this.options.width; 14508 14509 // For `width: false`, just remove inline style and stop 14510 if ( width === false ) { 14511 this.button.css( "width", "" ); 14512 return; 14513 } 14514 14515 // For `width: null`, match the width of the original element 14516 if ( width === null ) { 14517 width = this.element.show().outerWidth(); 14518 this.element.hide(); 14519 } 14520 14521 this.button.outerWidth( width ); 14522 }, 14523 14524 _resizeMenu: function() { 14525 this.menu.outerWidth( Math.max( 14526 this.button.outerWidth(), 14527 this.menu.width( "" ).outerWidth() 14528 ) ); 14529 }, 14530 14531 _getCreateOptions: function() { 14532 var options = this._super(); 14533 14534 options.disabled = this.element.prop( "disabled" ); 14535 14536 return options; 14537 }, 14538 14539 _parseOptions: function( options ) { 14540 var that = this, 14541 data = []; 14542 options.each( function( index, item ) { 14543 data.push( that._parseOption( $( item ), index ) ); 14544 } ); 14545 this.items = data; 14546 }, 14547 14548 _parseOption: function( option, index ) { 14549 var optgroup = option.parent( "optgroup" ); 14550 14551 return { 14552 element: option, 14553 index: index, 14554 value: option.val(), 14555 label: option.text(), 14556 hidden: optgroup.prop( "hidden" ) || option.prop( "hidden" ), 14557 optgroup: optgroup.attr( "label" ) || "", 14558 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) 14559 }; 14560 }, 14561 14562 _destroy: function() { 14563 this._unbindFormResetHandler(); 14564 this.menuWrap.remove(); 14565 this.button.remove(); 14566 this.element.show(); 14567 this.element.removeUniqueId(); 14568 this.labels.attr( "for", this.ids.element ); 14569 } 14570 } ] ); 14571 14572 14573 /*! 14574 * jQuery UI Slider 1.14.1 14575 * https://jqueryui.com 14576 * 14577 * Copyright OpenJS Foundation and other contributors 14578 * Released under the MIT license. 14579 * https://jquery.org/license 14580 */ 14581 14582//>>label: Slider 14583//>>group: Widgets 14584//>>description: Displays a flexible slider with ranges and accessibility via keyboard. 14585//>>docs: https://api.jqueryui.com/slider/ 14586//>>demos: https://jqueryui.com/slider/ 14587//>>css.structure: ../../themes/base/core.css 14588//>>css.structure: ../../themes/base/slider.css 14589//>>css.theme: ../../themes/base/theme.css 14590 14591 14592 var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, { 14593 version: "1.14.1", 14594 widgetEventPrefix: "slide", 14595 14596 options: { 14597 animate: false, 14598 classes: { 14599 "ui-slider": "ui-corner-all", 14600 "ui-slider-handle": "ui-corner-all", 14601 14602 // Note: ui-widget-header isn't the most fittingly semantic framework class for this 14603 // element, but worked best visually with a variety of themes 14604 "ui-slider-range": "ui-corner-all ui-widget-header" 14605 }, 14606 distance: 0, 14607 max: 100, 14608 min: 0, 14609 orientation: "horizontal", 14610 range: false, 14611 step: 1, 14612 value: 0, 14613 values: null, 14614 14615 // Callbacks 14616 change: null, 14617 slide: null, 14618 start: null, 14619 stop: null 14620 }, 14621 14622 // Number of pages in a slider 14623 // (how many times can you page up/down to go through the whole range) 14624 numPages: 5, 14625 14626 _create: function() { 14627 this._keySliding = false; 14628 this._mouseSliding = false; 14629 this._animateOff = true; 14630 this._handleIndex = null; 14631 this._detectOrientation(); 14632 this._mouseInit(); 14633 this._calculateNewMax(); 14634 14635 this._addClass( "ui-slider ui-slider-" + this.orientation, 14636 "ui-widget ui-widget-content" ); 14637 14638 this._refresh(); 14639 14640 this._animateOff = false; 14641 }, 14642 14643 _refresh: function() { 14644 this._createRange(); 14645 this._createHandles(); 14646 this._setupEvents(); 14647 this._refreshValue(); 14648 }, 14649 14650 _createHandles: function() { 14651 var i, handleCount, 14652 options = this.options, 14653 existingHandles = this.element.find( ".ui-slider-handle" ), 14654 handle = "<span tabindex='0'></span>", 14655 handles = []; 14656 14657 handleCount = ( options.values && options.values.length ) || 1; 14658 14659 if ( existingHandles.length > handleCount ) { 14660 existingHandles.slice( handleCount ).remove(); 14661 existingHandles = existingHandles.slice( 0, handleCount ); 14662 } 14663 14664 for ( i = existingHandles.length; i < handleCount; i++ ) { 14665 handles.push( handle ); 14666 } 14667 14668 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 14669 14670 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" ); 14671 14672 this.handle = this.handles.eq( 0 ); 14673 14674 this.handles.each( function( i ) { 14675 $( this ) 14676 .data( "ui-slider-handle-index", i ) 14677 .attr( "tabIndex", 0 ); 14678 } ); 14679 }, 14680 14681 _createRange: function() { 14682 var options = this.options; 14683 14684 if ( options.range ) { 14685 if ( options.range === true ) { 14686 if ( !options.values ) { 14687 options.values = [ this._valueMin(), this._valueMin() ]; 14688 } else if ( options.values.length && options.values.length !== 2 ) { 14689 options.values = [ options.values[ 0 ], options.values[ 0 ] ]; 14690 } else if ( Array.isArray( options.values ) ) { 14691 options.values = options.values.slice( 0 ); 14692 } 14693 } 14694 14695 if ( !this.range || !this.range.length ) { 14696 this.range = $( "<div>" ) 14697 .appendTo( this.element ); 14698 14699 this._addClass( this.range, "ui-slider-range" ); 14700 } else { 14701 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" ); 14702 14703 // Handle range switching from true to min/max 14704 this.range.css( { 14705 "left": "", 14706 "bottom": "" 14707 } ); 14708 } 14709 if ( options.range === "min" || options.range === "max" ) { 14710 this._addClass( this.range, "ui-slider-range-" + options.range ); 14711 } 14712 } else { 14713 if ( this.range ) { 14714 this.range.remove(); 14715 } 14716 this.range = null; 14717 } 14718 }, 14719 14720 _setupEvents: function() { 14721 this._off( this.handles ); 14722 this._on( this.handles, this._handleEvents ); 14723 this._hoverable( this.handles ); 14724 this._focusable( this.handles ); 14725 }, 14726 14727 _destroy: function() { 14728 this.handles.remove(); 14729 if ( this.range ) { 14730 this.range.remove(); 14731 } 14732 14733 this._mouseDestroy(); 14734 }, 14735 14736 _mouseCapture: function( event ) { 14737 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 14738 that = this, 14739 o = this.options; 14740 14741 if ( o.disabled ) { 14742 return false; 14743 } 14744 14745 this.elementSize = { 14746 width: this.element.outerWidth(), 14747 height: this.element.outerHeight() 14748 }; 14749 this.elementOffset = this.element.offset(); 14750 14751 position = { x: event.pageX, y: event.pageY }; 14752 normValue = this._normValueFromMouse( position ); 14753 distance = this._valueMax() - this._valueMin() + 1; 14754 this.handles.each( function( i ) { 14755 var thisDistance = Math.abs( normValue - that.values( i ) ); 14756 if ( ( distance > thisDistance ) || 14757 ( distance === thisDistance && 14758 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) { 14759 distance = thisDistance; 14760 closestHandle = $( this ); 14761 index = i; 14762 } 14763 } ); 14764 14765 allowed = this._start( event, index ); 14766 if ( allowed === false ) { 14767 return false; 14768 } 14769 this._mouseSliding = true; 14770 14771 this._handleIndex = index; 14772 14773 this._addClass( closestHandle, null, "ui-state-active" ); 14774 closestHandle.trigger( "focus" ); 14775 14776 offset = closestHandle.offset(); 14777 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 14778 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 14779 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 14780 top: event.pageY - offset.top - 14781 ( closestHandle.height() / 2 ) - 14782 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) - 14783 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) + 14784 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 ) 14785 }; 14786 14787 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 14788 this._slide( event, index, normValue ); 14789 } 14790 this._animateOff = true; 14791 return true; 14792 }, 14793 14794 _mouseStart: function() { 14795 return true; 14796 }, 14797 14798 _mouseDrag: function( event ) { 14799 var position = { x: event.pageX, y: event.pageY }, 14800 normValue = this._normValueFromMouse( position ); 14801 14802 this._slide( event, this._handleIndex, normValue ); 14803 14804 return false; 14805 }, 14806 14807 _mouseStop: function( event ) { 14808 this._removeClass( this.handles, null, "ui-state-active" ); 14809 this._mouseSliding = false; 14810 14811 this._stop( event, this._handleIndex ); 14812 this._change( event, this._handleIndex ); 14813 14814 this._handleIndex = null; 14815 this._clickOffset = null; 14816 this._animateOff = false; 14817 14818 return false; 14819 }, 14820 14821 _detectOrientation: function() { 14822 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 14823 }, 14824 14825 _normValueFromMouse: function( position ) { 14826 var pixelTotal, 14827 pixelMouse, 14828 percentMouse, 14829 valueTotal, 14830 valueMouse; 14831 14832 if ( this.orientation === "horizontal" ) { 14833 pixelTotal = this.elementSize.width; 14834 pixelMouse = position.x - this.elementOffset.left - 14835 ( this._clickOffset ? this._clickOffset.left : 0 ); 14836 } else { 14837 pixelTotal = this.elementSize.height; 14838 pixelMouse = position.y - this.elementOffset.top - 14839 ( this._clickOffset ? this._clickOffset.top : 0 ); 14840 } 14841 14842 percentMouse = ( pixelMouse / pixelTotal ); 14843 if ( percentMouse > 1 ) { 14844 percentMouse = 1; 14845 } 14846 if ( percentMouse < 0 ) { 14847 percentMouse = 0; 14848 } 14849 if ( this.orientation === "vertical" ) { 14850 percentMouse = 1 - percentMouse; 14851 } 14852 14853 valueTotal = this._valueMax() - this._valueMin(); 14854 valueMouse = this._valueMin() + percentMouse * valueTotal; 14855 14856 return this._trimAlignValue( valueMouse ); 14857 }, 14858 14859 _uiHash: function( index, value, values ) { 14860 var uiHash = { 14861 handle: this.handles[ index ], 14862 handleIndex: index, 14863 value: value !== undefined ? value : this.value() 14864 }; 14865 14866 if ( this._hasMultipleValues() ) { 14867 uiHash.value = value !== undefined ? value : this.values( index ); 14868 uiHash.values = values || this.values(); 14869 } 14870 14871 return uiHash; 14872 }, 14873 14874 _hasMultipleValues: function() { 14875 return this.options.values && this.options.values.length; 14876 }, 14877 14878 _start: function( event, index ) { 14879 return this._trigger( "start", event, this._uiHash( index ) ); 14880 }, 14881 14882 _slide: function( event, index, newVal ) { 14883 var allowed, otherVal, 14884 currentValue = this.value(), 14885 newValues = this.values(); 14886 14887 if ( this._hasMultipleValues() ) { 14888 otherVal = this.values( index ? 0 : 1 ); 14889 currentValue = this.values( index ); 14890 14891 if ( this.options.values.length === 2 && this.options.range === true ) { 14892 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal ); 14893 } 14894 14895 newValues[ index ] = newVal; 14896 } 14897 14898 if ( newVal === currentValue ) { 14899 return; 14900 } 14901 14902 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) ); 14903 14904 // A slide can be canceled by returning false from the slide callback 14905 if ( allowed === false ) { 14906 return; 14907 } 14908 14909 if ( this._hasMultipleValues() ) { 14910 this.values( index, newVal ); 14911 } else { 14912 this.value( newVal ); 14913 } 14914 }, 14915 14916 _stop: function( event, index ) { 14917 this._trigger( "stop", event, this._uiHash( index ) ); 14918 }, 14919 14920 _change: function( event, index ) { 14921 if ( !this._keySliding && !this._mouseSliding ) { 14922 14923 //store the last changed value index for reference when handles overlap 14924 this._lastChangedValue = index; 14925 this._trigger( "change", event, this._uiHash( index ) ); 14926 } 14927 }, 14928 14929 value: function( newValue ) { 14930 if ( arguments.length ) { 14931 this.options.value = this._trimAlignValue( newValue ); 14932 this._refreshValue(); 14933 this._change( null, 0 ); 14934 return; 14935 } 14936 14937 return this._value(); 14938 }, 14939 14940 values: function( index, newValue ) { 14941 var vals, 14942 newValues, 14943 i; 14944 14945 if ( arguments.length > 1 ) { 14946 this.options.values[ index ] = this._trimAlignValue( newValue ); 14947 this._refreshValue(); 14948 this._change( null, index ); 14949 return; 14950 } 14951 14952 if ( arguments.length ) { 14953 if ( Array.isArray( arguments[ 0 ] ) ) { 14954 vals = this.options.values; 14955 newValues = arguments[ 0 ]; 14956 for ( i = 0; i < vals.length; i += 1 ) { 14957 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 14958 this._change( null, i ); 14959 } 14960 this._refreshValue(); 14961 } else { 14962 if ( this._hasMultipleValues() ) { 14963 return this._values( index ); 14964 } else { 14965 return this.value(); 14966 } 14967 } 14968 } else { 14969 return this._values(); 14970 } 14971 }, 14972 14973 _setOption: function( key, value ) { 14974 var i, 14975 valsLength = 0; 14976 14977 if ( key === "range" && this.options.range === true ) { 14978 if ( value === "min" ) { 14979 this.options.value = this._values( 0 ); 14980 this.options.values = null; 14981 } else if ( value === "max" ) { 14982 this.options.value = this._values( this.options.values.length - 1 ); 14983 this.options.values = null; 14984 } 14985 } 14986 14987 if ( Array.isArray( this.options.values ) ) { 14988 valsLength = this.options.values.length; 14989 } 14990 14991 this._super( key, value ); 14992 14993 switch ( key ) { 14994 case "orientation": 14995 this._detectOrientation(); 14996 this._removeClass( "ui-slider-horizontal ui-slider-vertical" ) 14997 ._addClass( "ui-slider-" + this.orientation ); 14998 this._refreshValue(); 14999 if ( this.options.range ) { 15000 this._refreshRange( value ); 15001 } 15002 15003 // Reset positioning from previous orientation 15004 this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); 15005 break; 15006 case "value": 15007 this._animateOff = true; 15008 this._refreshValue(); 15009 this._change( null, 0 ); 15010 this._animateOff = false; 15011 break; 15012 case "values": 15013 this._animateOff = true; 15014 this._refreshValue(); 15015 15016 // Start from the last handle to prevent unreachable handles (#9046) 15017 for ( i = valsLength - 1; i >= 0; i-- ) { 15018 this._change( null, i ); 15019 } 15020 this._animateOff = false; 15021 break; 15022 case "step": 15023 case "min": 15024 case "max": 15025 this._animateOff = true; 15026 this._calculateNewMax(); 15027 this._refreshValue(); 15028 this._animateOff = false; 15029 break; 15030 case "range": 15031 this._animateOff = true; 15032 this._refresh(); 15033 this._animateOff = false; 15034 break; 15035 } 15036 }, 15037 15038 _setOptionDisabled: function( value ) { 15039 this._super( value ); 15040 15041 this._toggleClass( null, "ui-state-disabled", !!value ); 15042 }, 15043 15044 //internal value getter 15045 // _value() returns value trimmed by min and max, aligned by step 15046 _value: function() { 15047 var val = this.options.value; 15048 val = this._trimAlignValue( val ); 15049 15050 return val; 15051 }, 15052 15053 //internal values getter 15054 // _values() returns array of values trimmed by min and max, aligned by step 15055 // _values( index ) returns single value trimmed by min and max, aligned by step 15056 _values: function( index ) { 15057 var val, 15058 vals, 15059 i; 15060 15061 if ( arguments.length ) { 15062 val = this.options.values[ index ]; 15063 val = this._trimAlignValue( val ); 15064 15065 return val; 15066 } else if ( this._hasMultipleValues() ) { 15067 15068 // .slice() creates a copy of the array 15069 // this copy gets trimmed by min and max and then returned 15070 vals = this.options.values.slice(); 15071 for ( i = 0; i < vals.length; i += 1 ) { 15072 vals[ i ] = this._trimAlignValue( vals[ i ] ); 15073 } 15074 15075 return vals; 15076 } else { 15077 return []; 15078 } 15079 }, 15080 15081 // Returns the step-aligned value that val is closest to, between (inclusive) min and max 15082 _trimAlignValue: function( val ) { 15083 if ( val <= this._valueMin() ) { 15084 return this._valueMin(); 15085 } 15086 if ( val >= this._valueMax() ) { 15087 return this._valueMax(); 15088 } 15089 var step = ( this.options.step > 0 ) ? this.options.step : 1, 15090 valModStep = ( val - this._valueMin() ) % step, 15091 alignValue = val - valModStep; 15092 15093 if ( Math.abs( valModStep ) * 2 >= step ) { 15094 alignValue += ( valModStep > 0 ) ? step : ( -step ); 15095 } 15096 15097 // Since JavaScript has problems with large floats, round 15098 // the final value to 5 digits after the decimal point (see #4124) 15099 return parseFloat( alignValue.toFixed( 5 ) ); 15100 }, 15101 15102 _calculateNewMax: function() { 15103 var max = this.options.max, 15104 min = this._valueMin(), 15105 step = this.options.step, 15106 aboveMin = Math.round( ( max - min ) / step ) * step; 15107 max = aboveMin + min; 15108 if ( max > this.options.max ) { 15109 15110 //If max is not divisible by step, rounding off may increase its value 15111 max -= step; 15112 } 15113 this.max = parseFloat( max.toFixed( this._precision() ) ); 15114 }, 15115 15116 _precision: function() { 15117 var precision = this._precisionOf( this.options.step ); 15118 if ( this.options.min !== null ) { 15119 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 15120 } 15121 return precision; 15122 }, 15123 15124 _precisionOf: function( num ) { 15125 var str = num.toString(), 15126 decimal = str.indexOf( "." ); 15127 return decimal === -1 ? 0 : str.length - decimal - 1; 15128 }, 15129 15130 _valueMin: function() { 15131 return this.options.min; 15132 }, 15133 15134 _valueMax: function() { 15135 return this.max; 15136 }, 15137 15138 _refreshRange: function( orientation ) { 15139 if ( orientation === "vertical" ) { 15140 this.range.css( { "width": "", "left": "" } ); 15141 } 15142 if ( orientation === "horizontal" ) { 15143 this.range.css( { "height": "", "bottom": "" } ); 15144 } 15145 }, 15146 15147 _refreshValue: function() { 15148 var lastValPercent, valPercent, value, valueMin, valueMax, 15149 oRange = this.options.range, 15150 o = this.options, 15151 that = this, 15152 animate = ( !this._animateOff ) ? o.animate : false, 15153 _set = {}; 15154 15155 if ( this._hasMultipleValues() ) { 15156 this.handles.each( function( i ) { 15157 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() - 15158 that._valueMin() ) * 100; 15159 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15160 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15161 if ( that.options.range === true ) { 15162 if ( that.orientation === "horizontal" ) { 15163 if ( i === 0 ) { 15164 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15165 left: valPercent + "%" 15166 }, o.animate ); 15167 } 15168 if ( i === 1 ) { 15169 that.range[ animate ? "animate" : "css" ]( { 15170 width: ( valPercent - lastValPercent ) + "%" 15171 }, { 15172 queue: false, 15173 duration: o.animate 15174 } ); 15175 } 15176 } else { 15177 if ( i === 0 ) { 15178 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15179 bottom: ( valPercent ) + "%" 15180 }, o.animate ); 15181 } 15182 if ( i === 1 ) { 15183 that.range[ animate ? "animate" : "css" ]( { 15184 height: ( valPercent - lastValPercent ) + "%" 15185 }, { 15186 queue: false, 15187 duration: o.animate 15188 } ); 15189 } 15190 } 15191 } 15192 lastValPercent = valPercent; 15193 } ); 15194 } else { 15195 value = this.value(); 15196 valueMin = this._valueMin(); 15197 valueMax = this._valueMax(); 15198 valPercent = ( valueMax !== valueMin ) ? 15199 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 15200 0; 15201 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15202 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15203 15204 if ( oRange === "min" && this.orientation === "horizontal" ) { 15205 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15206 width: valPercent + "%" 15207 }, o.animate ); 15208 } 15209 if ( oRange === "max" && this.orientation === "horizontal" ) { 15210 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15211 width: ( 100 - valPercent ) + "%" 15212 }, o.animate ); 15213 } 15214 if ( oRange === "min" && this.orientation === "vertical" ) { 15215 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15216 height: valPercent + "%" 15217 }, o.animate ); 15218 } 15219 if ( oRange === "max" && this.orientation === "vertical" ) { 15220 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15221 height: ( 100 - valPercent ) + "%" 15222 }, o.animate ); 15223 } 15224 } 15225 }, 15226 15227 _handleEvents: { 15228 keydown: function( event ) { 15229 var allowed, curVal, newVal, step, 15230 index = $( event.target ).data( "ui-slider-handle-index" ); 15231 15232 switch ( event.keyCode ) { 15233 case $.ui.keyCode.HOME: 15234 case $.ui.keyCode.END: 15235 case $.ui.keyCode.PAGE_UP: 15236 case $.ui.keyCode.PAGE_DOWN: 15237 case $.ui.keyCode.UP: 15238 case $.ui.keyCode.RIGHT: 15239 case $.ui.keyCode.DOWN: 15240 case $.ui.keyCode.LEFT: 15241 event.preventDefault(); 15242 if ( !this._keySliding ) { 15243 this._keySliding = true; 15244 this._addClass( $( event.target ), null, "ui-state-active" ); 15245 allowed = this._start( event, index ); 15246 if ( allowed === false ) { 15247 return; 15248 } 15249 } 15250 break; 15251 } 15252 15253 step = this.options.step; 15254 if ( this._hasMultipleValues() ) { 15255 curVal = newVal = this.values( index ); 15256 } else { 15257 curVal = newVal = this.value(); 15258 } 15259 15260 switch ( event.keyCode ) { 15261 case $.ui.keyCode.HOME: 15262 newVal = this._valueMin(); 15263 break; 15264 case $.ui.keyCode.END: 15265 newVal = this._valueMax(); 15266 break; 15267 case $.ui.keyCode.PAGE_UP: 15268 newVal = this._trimAlignValue( 15269 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) 15270 ); 15271 break; 15272 case $.ui.keyCode.PAGE_DOWN: 15273 newVal = this._trimAlignValue( 15274 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); 15275 break; 15276 case $.ui.keyCode.UP: 15277 case $.ui.keyCode.RIGHT: 15278 if ( curVal === this._valueMax() ) { 15279 return; 15280 } 15281 newVal = this._trimAlignValue( curVal + step ); 15282 break; 15283 case $.ui.keyCode.DOWN: 15284 case $.ui.keyCode.LEFT: 15285 if ( curVal === this._valueMin() ) { 15286 return; 15287 } 15288 newVal = this._trimAlignValue( curVal - step ); 15289 break; 15290 } 15291 15292 this._slide( event, index, newVal ); 15293 }, 15294 keyup: function( event ) { 15295 var index = $( event.target ).data( "ui-slider-handle-index" ); 15296 15297 if ( this._keySliding ) { 15298 this._keySliding = false; 15299 this._stop( event, index ); 15300 this._change( event, index ); 15301 this._removeClass( $( event.target ), null, "ui-state-active" ); 15302 } 15303 } 15304 } 15305 } ); 15306 15307 15308 /*! 15309 * jQuery UI Sortable 1.14.1 15310 * https://jqueryui.com 15311 * 15312 * Copyright OpenJS Foundation and other contributors 15313 * Released under the MIT license. 15314 * https://jquery.org/license 15315 */ 15316 15317//>>label: Sortable 15318//>>group: Interactions 15319//>>description: Enables items in a list to be sorted using the mouse. 15320//>>docs: https://api.jqueryui.com/sortable/ 15321//>>demos: https://jqueryui.com/sortable/ 15322//>>css.structure: ../../themes/base/sortable.css 15323 15324 15325 var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, { 15326 version: "1.14.1", 15327 widgetEventPrefix: "sort", 15328 ready: false, 15329 options: { 15330 appendTo: "parent", 15331 axis: false, 15332 connectWith: false, 15333 containment: false, 15334 cursor: "auto", 15335 cursorAt: false, 15336 dropOnEmpty: true, 15337 forcePlaceholderSize: false, 15338 forceHelperSize: false, 15339 grid: false, 15340 handle: false, 15341 helper: "original", 15342 items: "> *", 15343 opacity: false, 15344 placeholder: false, 15345 revert: false, 15346 scroll: true, 15347 scrollSensitivity: 20, 15348 scrollSpeed: 20, 15349 scope: "default", 15350 tolerance: "intersect", 15351 zIndex: 1000, 15352 15353 // Callbacks 15354 activate: null, 15355 beforeStop: null, 15356 change: null, 15357 deactivate: null, 15358 out: null, 15359 over: null, 15360 receive: null, 15361 remove: null, 15362 sort: null, 15363 start: null, 15364 stop: null, 15365 update: null 15366 }, 15367 15368 _isOverAxis: function( x, reference, size ) { 15369 return ( x >= reference ) && ( x < ( reference + size ) ); 15370 }, 15371 15372 _isFloating: function( item ) { 15373 return ( /left|right/ ).test( item.css( "float" ) ) || 15374 ( /inline|table-cell/ ).test( item.css( "display" ) ); 15375 }, 15376 15377 _create: function() { 15378 this.containerCache = {}; 15379 this._addClass( "ui-sortable" ); 15380 15381 //Get the items 15382 this.refresh(); 15383 15384 //Let's determine the parent's offset 15385 this.offset = this.element.offset(); 15386 15387 //Initialize mouse events for interaction 15388 this._mouseInit(); 15389 15390 this._setHandleClassName(); 15391 15392 //We're ready to go 15393 this.ready = true; 15394 15395 }, 15396 15397 _setOption: function( key, value ) { 15398 this._super( key, value ); 15399 15400 if ( key === "handle" ) { 15401 this._setHandleClassName(); 15402 } 15403 }, 15404 15405 _setHandleClassName: function() { 15406 var that = this; 15407 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" ); 15408 $.each( this.items, function() { 15409 that._addClass( 15410 this.instance.options.handle ? 15411 this.item.find( this.instance.options.handle ) : 15412 this.item, 15413 "ui-sortable-handle" 15414 ); 15415 } ); 15416 }, 15417 15418 _destroy: function() { 15419 this._mouseDestroy(); 15420 15421 for ( var i = this.items.length - 1; i >= 0; i-- ) { 15422 this.items[ i ].item.removeData( this.widgetName + "-item" ); 15423 } 15424 15425 return this; 15426 }, 15427 15428 _mouseCapture: function( event, overrideHandle ) { 15429 var currentItem = null, 15430 validHandle = false, 15431 that = this; 15432 15433 if ( this.reverting ) { 15434 return false; 15435 } 15436 15437 if ( this.options.disabled || this.options.type === "static" ) { 15438 return false; 15439 } 15440 15441 //We have to refresh the items data once first 15442 this._refreshItems( event ); 15443 15444 //Find out if the clicked node (or one of its parents) is a actual item in this.items 15445 $( event.target ).parents().each( function() { 15446 if ( $.data( this, that.widgetName + "-item" ) === that ) { 15447 currentItem = $( this ); 15448 return false; 15449 } 15450 } ); 15451 if ( $.data( event.target, that.widgetName + "-item" ) === that ) { 15452 currentItem = $( event.target ); 15453 } 15454 15455 if ( !currentItem ) { 15456 return false; 15457 } 15458 if ( this.options.handle && !overrideHandle ) { 15459 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() { 15460 if ( this === event.target ) { 15461 validHandle = true; 15462 } 15463 } ); 15464 if ( !validHandle ) { 15465 return false; 15466 } 15467 } 15468 15469 this.currentItem = currentItem; 15470 this._removeCurrentsFromItems(); 15471 return true; 15472 15473 }, 15474 15475 _mouseStart: function( event, overrideHandle, noActivation ) { 15476 15477 var i, body, 15478 o = this.options; 15479 15480 this.currentContainer = this; 15481 15482 //We only need to call refreshPositions, because the refreshItems call has been moved to 15483 // mouseCapture 15484 this.refreshPositions(); 15485 15486 //Prepare the dragged items parent 15487 this.appendTo = $( o.appendTo !== "parent" ? 15488 o.appendTo : 15489 this.currentItem.parent() ); 15490 15491 //Create and append the visible helper 15492 this.helper = this._createHelper( event ); 15493 15494 //Cache the helper size 15495 this._cacheHelperProportions(); 15496 15497 /* 15498 * - Position generation - 15499 * This block generates everything position related - it's the core of draggables. 15500 */ 15501 15502 //Cache the margins of the original element 15503 this._cacheMargins(); 15504 15505 //The element's absolute position on the page minus margins 15506 this.offset = this.currentItem.offset(); 15507 this.offset = { 15508 top: this.offset.top - this.margins.top, 15509 left: this.offset.left - this.margins.left 15510 }; 15511 15512 $.extend( this.offset, { 15513 click: { //Where the click happened, relative to the element 15514 left: event.pageX - this.offset.left, 15515 top: event.pageY - this.offset.top 15516 }, 15517 15518 // This is a relative to absolute position minus the actual position calculation - 15519 // only used for relative positioned helper 15520 relative: this._getRelativeOffset() 15521 } ); 15522 15523 // After we get the helper offset, but before we get the parent offset we can 15524 // change the helper's position to absolute 15525 // TODO: Still need to figure out a way to make relative sorting possible 15526 this.helper.css( "position", "absolute" ); 15527 this.cssPosition = this.helper.css( "position" ); 15528 15529 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 15530 if ( o.cursorAt ) { 15531 this._adjustOffsetFromHelper( o.cursorAt ); 15532 } 15533 15534 //Cache the former DOM position 15535 this.domPosition = { 15536 prev: this.currentItem.prev()[ 0 ], 15537 parent: this.currentItem.parent()[ 0 ] 15538 }; 15539 15540 // If the helper is not the original, hide the original so it's not playing any role during 15541 // the drag, won't cause anything bad this way 15542 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 15543 this.currentItem.hide(); 15544 } 15545 15546 //Create the placeholder 15547 this._createPlaceholder(); 15548 15549 //Get the next scrolling parent 15550 this.scrollParent = this.placeholder.scrollParent(); 15551 15552 $.extend( this.offset, { 15553 parent: this._getParentOffset() 15554 } ); 15555 15556 //Set a containment if given in the options 15557 if ( o.containment ) { 15558 this._setContainment(); 15559 } 15560 15561 if ( o.cursor && o.cursor !== "auto" ) { // cursor option 15562 body = this.document.find( "body" ); 15563 15564 this._storedStylesheet = 15565 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body ); 15566 } 15567 15568 // We need to make sure to grab the zIndex before setting the 15569 // opacity, because setting the opacity to anything lower than 1 15570 // causes the zIndex to change from "auto" to 0. 15571 if ( o.zIndex ) { // zIndex option 15572 if ( this.helper.css( "zIndex" ) ) { 15573 this._storedZIndex = this.helper.css( "zIndex" ); 15574 } 15575 this.helper.css( "zIndex", o.zIndex ); 15576 } 15577 15578 if ( o.opacity ) { // opacity option 15579 if ( this.helper.css( "opacity" ) ) { 15580 this._storedOpacity = this.helper.css( "opacity" ); 15581 } 15582 this.helper.css( "opacity", o.opacity ); 15583 } 15584 15585 //Prepare scrolling 15586 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15587 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15588 this.overflowOffset = this.scrollParent.offset(); 15589 } 15590 15591 //Call callbacks 15592 this._trigger( "start", event, this._uiHash() ); 15593 15594 //Recache the helper size 15595 if ( !this._preserveHelperProportions ) { 15596 this._cacheHelperProportions(); 15597 } 15598 15599 //Post "activate" events to possible containers 15600 if ( !noActivation ) { 15601 for ( i = this.containers.length - 1; i >= 0; i-- ) { 15602 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 15603 } 15604 } 15605 15606 //Prepare possible droppables 15607 if ( $.ui.ddmanager ) { 15608 $.ui.ddmanager.current = this; 15609 } 15610 15611 if ( $.ui.ddmanager && !o.dropBehaviour ) { 15612 $.ui.ddmanager.prepareOffsets( this, event ); 15613 } 15614 15615 this.dragging = true; 15616 15617 this._addClass( this.helper, "ui-sortable-helper" ); 15618 15619 //Move the helper, if needed 15620 if ( !this.helper.parent().is( this.appendTo ) ) { 15621 this.helper.detach().appendTo( this.appendTo ); 15622 15623 //Update position 15624 this.offset.parent = this._getParentOffset(); 15625 } 15626 15627 //Generate the original position 15628 this.position = this.originalPosition = this._generatePosition( event ); 15629 this.originalPageX = event.pageX; 15630 this.originalPageY = event.pageY; 15631 this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" ); 15632 15633 this._mouseDrag( event ); 15634 15635 return true; 15636 15637 }, 15638 15639 _scroll: function( event ) { 15640 var o = this.options, 15641 scrolled = false; 15642 15643 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15644 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15645 15646 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) - 15647 event.pageY < o.scrollSensitivity ) { 15648 this.scrollParent[ 0 ].scrollTop = 15649 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed; 15650 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) { 15651 this.scrollParent[ 0 ].scrollTop = 15652 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed; 15653 } 15654 15655 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) - 15656 event.pageX < o.scrollSensitivity ) { 15657 this.scrollParent[ 0 ].scrollLeft = scrolled = 15658 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed; 15659 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) { 15660 this.scrollParent[ 0 ].scrollLeft = scrolled = 15661 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed; 15662 } 15663 15664 } else { 15665 15666 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) { 15667 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed ); 15668 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) < 15669 o.scrollSensitivity ) { 15670 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed ); 15671 } 15672 15673 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) { 15674 scrolled = this.document.scrollLeft( 15675 this.document.scrollLeft() - o.scrollSpeed 15676 ); 15677 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) < 15678 o.scrollSensitivity ) { 15679 scrolled = this.document.scrollLeft( 15680 this.document.scrollLeft() + o.scrollSpeed 15681 ); 15682 } 15683 15684 } 15685 15686 return scrolled; 15687 }, 15688 15689 _mouseDrag: function( event ) { 15690 var i, item, itemElement, intersection, 15691 o = this.options; 15692 15693 //Compute the helpers position 15694 this.position = this._generatePosition( event ); 15695 this.positionAbs = this._convertPositionTo( "absolute" ); 15696 15697 //Set the helper position 15698 if ( !this.options.axis || this.options.axis !== "y" ) { 15699 this.helper[ 0 ].style.left = this.position.left + "px"; 15700 } 15701 if ( !this.options.axis || this.options.axis !== "x" ) { 15702 this.helper[ 0 ].style.top = this.position.top + "px"; 15703 } 15704 15705 //Do scrolling 15706 if ( o.scroll ) { 15707 if ( this._scroll( event ) !== false ) { 15708 15709 //Update item positions used in position checks 15710 this._refreshItemPositions( true ); 15711 15712 if ( $.ui.ddmanager && !o.dropBehaviour ) { 15713 $.ui.ddmanager.prepareOffsets( this, event ); 15714 } 15715 } 15716 } 15717 15718 this.dragDirection = { 15719 vertical: this._getDragVerticalDirection(), 15720 horizontal: this._getDragHorizontalDirection() 15721 }; 15722 15723 //Rearrange 15724 for ( i = this.items.length - 1; i >= 0; i-- ) { 15725 15726 //Cache variables and intersection, continue if no intersection 15727 item = this.items[ i ]; 15728 itemElement = item.item[ 0 ]; 15729 intersection = this._intersectsWithPointer( item ); 15730 if ( !intersection ) { 15731 continue; 15732 } 15733 15734 // Only put the placeholder inside the current Container, skip all 15735 // items from other containers. This works because when moving 15736 // an item from one container to another the 15737 // currentContainer is switched before the placeholder is moved. 15738 // 15739 // Without this, moving items in "sub-sortables" can cause 15740 // the placeholder to jitter between the outer and inner container. 15741 if ( item.instance !== this.currentContainer ) { 15742 continue; 15743 } 15744 15745 // Cannot intersect with itself 15746 // no useless actions that have been done before 15747 // no action if the item moved is the parent of the item checked 15748 if ( itemElement !== this.currentItem[ 0 ] && 15749 this.placeholder[ intersection === 1 ? 15750 "next" : "prev" ]()[ 0 ] !== itemElement && 15751 !$.contains( this.placeholder[ 0 ], itemElement ) && 15752 ( this.options.type === "semi-dynamic" ? 15753 !$.contains( this.element[ 0 ], itemElement ) : 15754 true 15755 ) 15756 ) { 15757 15758 this.direction = intersection === 1 ? "down" : "up"; 15759 15760 if ( this.options.tolerance === "pointer" || 15761 this._intersectsWithSides( item ) ) { 15762 this._rearrange( event, item ); 15763 } else { 15764 break; 15765 } 15766 15767 this._trigger( "change", event, this._uiHash() ); 15768 break; 15769 } 15770 } 15771 15772 //Post events to containers 15773 this._contactContainers( event ); 15774 15775 //Interconnect with droppables 15776 if ( $.ui.ddmanager ) { 15777 $.ui.ddmanager.drag( this, event ); 15778 } 15779 15780 //Call callbacks 15781 this._trigger( "sort", event, this._uiHash() ); 15782 15783 this.lastPositionAbs = this.positionAbs; 15784 return false; 15785 15786 }, 15787 15788 _mouseStop: function( event, noPropagation ) { 15789 15790 if ( !event ) { 15791 return; 15792 } 15793 15794 //If we are using droppables, inform the manager about the drop 15795 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 15796 $.ui.ddmanager.drop( this, event ); 15797 } 15798 15799 if ( this.options.revert ) { 15800 var that = this, 15801 cur = this.placeholder.offset(), 15802 axis = this.options.axis, 15803 animation = {}; 15804 15805 if ( !axis || axis === "x" ) { 15806 animation.left = cur.left - this.offset.parent.left - this.margins.left + 15807 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15808 0 : 15809 this.offsetParent[ 0 ].scrollLeft 15810 ); 15811 } 15812 if ( !axis || axis === "y" ) { 15813 animation.top = cur.top - this.offset.parent.top - this.margins.top + 15814 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15815 0 : 15816 this.offsetParent[ 0 ].scrollTop 15817 ); 15818 } 15819 this.reverting = true; 15820 $( this.helper ).animate( 15821 animation, 15822 parseInt( this.options.revert, 10 ) || 500, 15823 function() { 15824 that._clear( event ); 15825 } 15826 ); 15827 } else { 15828 this._clear( event, noPropagation ); 15829 } 15830 15831 return false; 15832 15833 }, 15834 15835 cancel: function() { 15836 15837 if ( this.dragging ) { 15838 15839 this._mouseUp( new $.Event( "mouseup", { target: null } ) ); 15840 15841 if ( this.options.helper === "original" ) { 15842 this.currentItem.css( this._storedCSS ); 15843 this._removeClass( this.currentItem, "ui-sortable-helper" ); 15844 } else { 15845 this.currentItem.show(); 15846 } 15847 15848 //Post deactivating events to containers 15849 for ( var i = this.containers.length - 1; i >= 0; i-- ) { 15850 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) ); 15851 if ( this.containers[ i ].containerCache.over ) { 15852 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) ); 15853 this.containers[ i ].containerCache.over = 0; 15854 } 15855 } 15856 15857 } 15858 15859 if ( this.placeholder ) { 15860 15861 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 15862 // it unbinds ALL events from the original node! 15863 if ( this.placeholder[ 0 ].parentNode ) { 15864 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 15865 } 15866 if ( this.options.helper !== "original" && this.helper && 15867 this.helper[ 0 ].parentNode ) { 15868 this.helper.remove(); 15869 } 15870 15871 $.extend( this, { 15872 helper: null, 15873 dragging: false, 15874 reverting: false, 15875 _noFinalSort: null 15876 } ); 15877 15878 if ( this.domPosition.prev ) { 15879 $( this.domPosition.prev ).after( this.currentItem ); 15880 } else { 15881 $( this.domPosition.parent ).prepend( this.currentItem ); 15882 } 15883 } 15884 15885 return this; 15886 15887 }, 15888 15889 serialize: function( o ) { 15890 15891 var items = this._getItemsAsjQuery( o && o.connected ), 15892 str = []; 15893 o = o || {}; 15894 15895 $( items ).each( function() { 15896 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" ) 15897 .match( o.expression || ( /(.+)[\-=_](.+)/ ) ); 15898 if ( res ) { 15899 str.push( 15900 ( o.key || res[ 1 ] + "[]" ) + 15901 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) ); 15902 } 15903 } ); 15904 15905 if ( !str.length && o.key ) { 15906 str.push( o.key + "=" ); 15907 } 15908 15909 return str.join( "&" ); 15910 15911 }, 15912 15913 toArray: function( o ) { 15914 15915 var items = this._getItemsAsjQuery( o && o.connected ), 15916 ret = []; 15917 15918 o = o || {}; 15919 15920 items.each( function() { 15921 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" ); 15922 } ); 15923 return ret; 15924 15925 }, 15926 15927 /* Be careful with the following core functions */ 15928 _intersectsWith: function( item ) { 15929 15930 var x1 = this.positionAbs.left, 15931 x2 = x1 + this.helperProportions.width, 15932 y1 = this.positionAbs.top, 15933 y2 = y1 + this.helperProportions.height, 15934 l = item.left, 15935 r = l + item.width, 15936 t = item.top, 15937 b = t + item.height, 15938 dyClick = this.offset.click.top, 15939 dxClick = this.offset.click.left, 15940 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && 15941 ( y1 + dyClick ) < b ), 15942 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && 15943 ( x1 + dxClick ) < r ), 15944 isOverElement = isOverElementHeight && isOverElementWidth; 15945 15946 if ( this.options.tolerance === "pointer" || 15947 this.options.forcePointerForContainers || 15948 ( this.options.tolerance !== "pointer" && 15949 this.helperProportions[ this.floating ? "width" : "height" ] > 15950 item[ this.floating ? "width" : "height" ] ) 15951 ) { 15952 return isOverElement; 15953 } else { 15954 15955 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half 15956 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half 15957 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half 15958 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half 15959 15960 } 15961 }, 15962 15963 _intersectsWithPointer: function( item ) { 15964 var verticalDirection, horizontalDirection, 15965 isOverElementHeight = ( this.options.axis === "x" ) || 15966 this._isOverAxis( 15967 this.positionAbs.top + this.offset.click.top, item.top, item.height ), 15968 isOverElementWidth = ( this.options.axis === "y" ) || 15969 this._isOverAxis( 15970 this.positionAbs.left + this.offset.click.left, item.left, item.width ), 15971 isOverElement = isOverElementHeight && isOverElementWidth; 15972 15973 if ( !isOverElement ) { 15974 return false; 15975 } 15976 15977 verticalDirection = this.dragDirection.vertical; 15978 horizontalDirection = this.dragDirection.horizontal; 15979 15980 return this.floating ? 15981 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) : 15982 ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) ); 15983 15984 }, 15985 15986 _intersectsWithSides: function( item ) { 15987 15988 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top + 15989 this.offset.click.top, item.top + ( item.height / 2 ), item.height ), 15990 isOverRightHalf = this._isOverAxis( this.positionAbs.left + 15991 this.offset.click.left, item.left + ( item.width / 2 ), item.width ), 15992 verticalDirection = this.dragDirection.vertical, 15993 horizontalDirection = this.dragDirection.horizontal; 15994 15995 if ( this.floating && horizontalDirection ) { 15996 return ( ( horizontalDirection === "right" && isOverRightHalf ) || 15997 ( horizontalDirection === "left" && !isOverRightHalf ) ); 15998 } else { 15999 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) || 16000 ( verticalDirection === "up" && !isOverBottomHalf ) ); 16001 } 16002 16003 }, 16004 16005 _getDragVerticalDirection: function() { 16006 var delta = this.positionAbs.top - this.lastPositionAbs.top; 16007 return delta !== 0 && ( delta > 0 ? "down" : "up" ); 16008 }, 16009 16010 _getDragHorizontalDirection: function() { 16011 var delta = this.positionAbs.left - this.lastPositionAbs.left; 16012 return delta !== 0 && ( delta > 0 ? "right" : "left" ); 16013 }, 16014 16015 refresh: function( event ) { 16016 this._refreshItems( event ); 16017 this._setHandleClassName(); 16018 this.refreshPositions(); 16019 return this; 16020 }, 16021 16022 _connectWith: function() { 16023 var options = this.options; 16024 return options.connectWith.constructor === String ? 16025 [ options.connectWith ] : 16026 options.connectWith; 16027 }, 16028 16029 _getItemsAsjQuery: function( connected ) { 16030 16031 var i, j, cur, inst, 16032 items = [], 16033 queries = [], 16034 connectWith = this._connectWith(); 16035 16036 if ( connectWith && connected ) { 16037 for ( i = connectWith.length - 1; i >= 0; i-- ) { 16038 cur = $( connectWith[ i ], this.document[ 0 ] ); 16039 for ( j = cur.length - 1; j >= 0; j-- ) { 16040 inst = $.data( cur[ j ], this.widgetFullName ); 16041 if ( inst && inst !== this && !inst.options.disabled ) { 16042 queries.push( [ typeof inst.options.items === "function" ? 16043 inst.options.items.call( inst.element ) : 16044 $( inst.options.items, inst.element ) 16045 .not( ".ui-sortable-helper" ) 16046 .not( ".ui-sortable-placeholder" ), inst ] ); 16047 } 16048 } 16049 } 16050 } 16051 16052 queries.push( [ typeof this.options.items === "function" ? 16053 this.options.items 16054 .call( this.element, null, { options: this.options, item: this.currentItem } ) : 16055 $( this.options.items, this.element ) 16056 .not( ".ui-sortable-helper" ) 16057 .not( ".ui-sortable-placeholder" ), this ] ); 16058 16059 function addItems() { 16060 items.push( this ); 16061 } 16062 for ( i = queries.length - 1; i >= 0; i-- ) { 16063 queries[ i ][ 0 ].each( addItems ); 16064 } 16065 16066 return $( items ); 16067 16068 }, 16069 16070 _removeCurrentsFromItems: function() { 16071 16072 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" ); 16073 16074 this.items = $.grep( this.items, function( item ) { 16075 for ( var j = 0; j < list.length; j++ ) { 16076 if ( list[ j ] === item.item[ 0 ] ) { 16077 return false; 16078 } 16079 } 16080 return true; 16081 } ); 16082 16083 }, 16084 16085 _refreshItems: function( event ) { 16086 16087 this.items = []; 16088 this.containers = [ this ]; 16089 16090 var i, j, cur, inst, targetData, _queries, item, queriesLength, 16091 items = this.items, 16092 queries = [ [ typeof this.options.items === "function" ? 16093 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) : 16094 $( this.options.items, this.element ), this ] ], 16095 connectWith = this._connectWith(); 16096 16097 //Shouldn't be run the first time through due to massive slow-down 16098 if ( connectWith && this.ready ) { 16099 for ( i = connectWith.length - 1; i >= 0; i-- ) { 16100 cur = $( connectWith[ i ], this.document[ 0 ] ); 16101 for ( j = cur.length - 1; j >= 0; j-- ) { 16102 inst = $.data( cur[ j ], this.widgetFullName ); 16103 if ( inst && inst !== this && !inst.options.disabled ) { 16104 queries.push( [ typeof inst.options.items === "function" ? 16105 inst.options.items 16106 .call( inst.element[ 0 ], event, { item: this.currentItem } ) : 16107 $( inst.options.items, inst.element ), inst ] ); 16108 this.containers.push( inst ); 16109 } 16110 } 16111 } 16112 } 16113 16114 for ( i = queries.length - 1; i >= 0; i-- ) { 16115 targetData = queries[ i ][ 1 ]; 16116 _queries = queries[ i ][ 0 ]; 16117 16118 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) { 16119 item = $( _queries[ j ] ); 16120 16121 // Data for target checking (mouse manager) 16122 item.data( this.widgetName + "-item", targetData ); 16123 16124 items.push( { 16125 item: item, 16126 instance: targetData, 16127 width: 0, height: 0, 16128 left: 0, top: 0 16129 } ); 16130 } 16131 } 16132 16133 }, 16134 16135 _refreshItemPositions: function( fast ) { 16136 var i, item, t, p; 16137 16138 for ( i = this.items.length - 1; i >= 0; i-- ) { 16139 item = this.items[ i ]; 16140 16141 //We ignore calculating positions of all connected containers when we're not over them 16142 if ( this.currentContainer && item.instance !== this.currentContainer && 16143 item.item[ 0 ] !== this.currentItem[ 0 ] ) { 16144 continue; 16145 } 16146 16147 t = this.options.toleranceElement ? 16148 $( this.options.toleranceElement, item.item ) : 16149 item.item; 16150 16151 if ( !fast ) { 16152 item.width = t.outerWidth(); 16153 item.height = t.outerHeight(); 16154 } 16155 16156 p = t.offset(); 16157 item.left = p.left; 16158 item.top = p.top; 16159 } 16160 }, 16161 16162 refreshPositions: function( fast ) { 16163 16164 // Determine whether items are being displayed horizontally 16165 this.floating = this.items.length ? 16166 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : 16167 false; 16168 16169 // This has to be redone because due to the item being moved out/into the offsetParent, 16170 // the offsetParent's position will change 16171 if ( this.offsetParent && this.helper ) { 16172 this.offset.parent = this._getParentOffset(); 16173 } 16174 16175 this._refreshItemPositions( fast ); 16176 16177 var i, p; 16178 16179 if ( this.options.custom && this.options.custom.refreshContainers ) { 16180 this.options.custom.refreshContainers.call( this ); 16181 } else { 16182 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16183 p = this.containers[ i ].element.offset(); 16184 this.containers[ i ].containerCache.left = p.left; 16185 this.containers[ i ].containerCache.top = p.top; 16186 this.containers[ i ].containerCache.width = 16187 this.containers[ i ].element.outerWidth(); 16188 this.containers[ i ].containerCache.height = 16189 this.containers[ i ].element.outerHeight(); 16190 } 16191 } 16192 16193 return this; 16194 }, 16195 16196 _createPlaceholder: function( that ) { 16197 that = that || this; 16198 var className, nodeName, 16199 o = that.options; 16200 16201 if ( !o.placeholder || o.placeholder.constructor === String ) { 16202 className = o.placeholder; 16203 nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(); 16204 o.placeholder = { 16205 element: function() { 16206 16207 var element = $( "<" + nodeName + ">", that.document[ 0 ] ); 16208 16209 that._addClass( element, "ui-sortable-placeholder", 16210 className || that.currentItem[ 0 ].className ) 16211 ._removeClass( element, "ui-sortable-helper" ); 16212 16213 if ( nodeName === "tbody" ) { 16214 that._createTrPlaceholder( 16215 that.currentItem.find( "tr" ).eq( 0 ), 16216 $( "<tr>", that.document[ 0 ] ).appendTo( element ) 16217 ); 16218 } else if ( nodeName === "tr" ) { 16219 that._createTrPlaceholder( that.currentItem, element ); 16220 } else if ( nodeName === "img" ) { 16221 element.attr( "src", that.currentItem.attr( "src" ) ); 16222 } 16223 16224 if ( !className ) { 16225 element.css( "visibility", "hidden" ); 16226 } 16227 16228 return element; 16229 }, 16230 update: function( container, p ) { 16231 16232 // 1. If a className is set as 'placeholder option, we don't force sizes - 16233 // the class is responsible for that 16234 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a 16235 // class name is specified 16236 if ( className && !o.forcePlaceholderSize ) { 16237 return; 16238 } 16239 16240 // If the element doesn't have a actual height or width by itself (without 16241 // styles coming from a stylesheet), it receives the inline height and width 16242 // from the dragged item. Or, if it's a tbody or tr, it's going to have a height 16243 // anyway since we're populating them with <td>s above, but they're unlikely to 16244 // be the correct height on their own if the row heights are dynamic, so we'll 16245 // always assign the height of the dragged item given forcePlaceholderSize 16246 // is true. 16247 if ( !p.height() || ( o.forcePlaceholderSize && 16248 ( nodeName === "tbody" || nodeName === "tr" ) ) ) { 16249 p.height( 16250 that.currentItem.innerHeight() - 16251 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) - 16252 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) ); 16253 } 16254 if ( !p.width() ) { 16255 p.width( 16256 that.currentItem.innerWidth() - 16257 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) - 16258 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) ); 16259 } 16260 } 16261 }; 16262 } 16263 16264 //Create the placeholder 16265 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) ); 16266 16267 //Append it after the actual current item 16268 that.currentItem.after( that.placeholder ); 16269 16270 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 16271 o.placeholder.update( that, that.placeholder ); 16272 16273 }, 16274 16275 _createTrPlaceholder: function( sourceTr, targetTr ) { 16276 var that = this; 16277 16278 sourceTr.children().each( function() { 16279 $( "<td> </td>", that.document[ 0 ] ) 16280 .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 16281 .appendTo( targetTr ); 16282 } ); 16283 }, 16284 16285 _contactContainers: function( event ) { 16286 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, 16287 floating, axis, 16288 innermostContainer = null, 16289 innermostIndex = null; 16290 16291 // Get innermost container that intersects with item 16292 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16293 16294 // Never consider a container that's located within the item itself 16295 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) { 16296 continue; 16297 } 16298 16299 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) { 16300 16301 // If we've already found a container and it's more "inner" than this, then continue 16302 if ( innermostContainer && 16303 $.contains( 16304 this.containers[ i ].element[ 0 ], 16305 innermostContainer.element[ 0 ] ) ) { 16306 continue; 16307 } 16308 16309 innermostContainer = this.containers[ i ]; 16310 innermostIndex = i; 16311 16312 } else { 16313 16314 // container doesn't intersect. trigger "out" event if necessary 16315 if ( this.containers[ i ].containerCache.over ) { 16316 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) ); 16317 this.containers[ i ].containerCache.over = 0; 16318 } 16319 } 16320 16321 } 16322 16323 // If no intersecting containers found, return 16324 if ( !innermostContainer ) { 16325 return; 16326 } 16327 16328 // Move the item into the container if it's not there already 16329 if ( this.containers.length === 1 ) { 16330 if ( !this.containers[ innermostIndex ].containerCache.over ) { 16331 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16332 this.containers[ innermostIndex ].containerCache.over = 1; 16333 } 16334 } else { 16335 16336 // When entering a new container, we will find the item with the least distance and 16337 // append our item near it 16338 dist = 10000; 16339 itemWithLeastDistance = null; 16340 floating = innermostContainer.floating || this._isFloating( this.currentItem ); 16341 posProperty = floating ? "left" : "top"; 16342 sizeProperty = floating ? "width" : "height"; 16343 axis = floating ? "pageX" : "pageY"; 16344 16345 for ( j = this.items.length - 1; j >= 0; j-- ) { 16346 if ( !$.contains( 16347 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] ) 16348 ) { 16349 continue; 16350 } 16351 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) { 16352 continue; 16353 } 16354 16355 cur = this.items[ j ].item.offset()[ posProperty ]; 16356 nearBottom = false; 16357 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 16358 nearBottom = true; 16359 } 16360 16361 if ( Math.abs( event[ axis ] - cur ) < dist ) { 16362 dist = Math.abs( event[ axis ] - cur ); 16363 itemWithLeastDistance = this.items[ j ]; 16364 this.direction = nearBottom ? "up" : "down"; 16365 } 16366 } 16367 16368 //Check if dropOnEmpty is enabled 16369 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) { 16370 return; 16371 } 16372 16373 if ( this.currentContainer === this.containers[ innermostIndex ] ) { 16374 if ( !this.currentContainer.containerCache.over ) { 16375 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); 16376 this.currentContainer.containerCache.over = 1; 16377 } 16378 return; 16379 } 16380 16381 if ( itemWithLeastDistance ) { 16382 this._rearrange( event, itemWithLeastDistance, null, true ); 16383 } else { 16384 this._rearrange( event, null, this.containers[ innermostIndex ].element, true ); 16385 } 16386 this._trigger( "change", event, this._uiHash() ); 16387 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) ); 16388 this.currentContainer = this.containers[ innermostIndex ]; 16389 16390 //Update the placeholder 16391 this.options.placeholder.update( this.currentContainer, this.placeholder ); 16392 16393 //Update scrollParent 16394 this.scrollParent = this.placeholder.scrollParent(); 16395 16396 //Update overflowOffset 16397 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16398 this.scrollParent[ 0 ].tagName !== "HTML" ) { 16399 this.overflowOffset = this.scrollParent.offset(); 16400 } 16401 16402 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16403 this.containers[ innermostIndex ].containerCache.over = 1; 16404 } 16405 16406 }, 16407 16408 _createHelper: function( event ) { 16409 16410 var o = this.options, 16411 helper = typeof o.helper === "function" ? 16412 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) : 16413 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem ); 16414 16415 //Add the helper to the DOM if that didn't happen already 16416 if ( !helper.parents( "body" ).length ) { 16417 this.appendTo[ 0 ].appendChild( helper[ 0 ] ); 16418 } 16419 16420 if ( helper[ 0 ] === this.currentItem[ 0 ] ) { 16421 this._storedCSS = { 16422 width: this.currentItem[ 0 ].style.width, 16423 height: this.currentItem[ 0 ].style.height, 16424 position: this.currentItem.css( "position" ), 16425 top: this.currentItem.css( "top" ), 16426 left: this.currentItem.css( "left" ) 16427 }; 16428 } 16429 16430 if ( !helper[ 0 ].style.width || o.forceHelperSize ) { 16431 helper.width( this.currentItem.width() ); 16432 } 16433 if ( !helper[ 0 ].style.height || o.forceHelperSize ) { 16434 helper.height( this.currentItem.height() ); 16435 } 16436 16437 return helper; 16438 16439 }, 16440 16441 _adjustOffsetFromHelper: function( obj ) { 16442 if ( typeof obj === "string" ) { 16443 obj = obj.split( " " ); 16444 } 16445 if ( Array.isArray( obj ) ) { 16446 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 16447 } 16448 if ( "left" in obj ) { 16449 this.offset.click.left = obj.left + this.margins.left; 16450 } 16451 if ( "right" in obj ) { 16452 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 16453 } 16454 if ( "top" in obj ) { 16455 this.offset.click.top = obj.top + this.margins.top; 16456 } 16457 if ( "bottom" in obj ) { 16458 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 16459 } 16460 }, 16461 16462 _getParentOffset: function() { 16463 16464 //Get the offsetParent and cache its position 16465 this.offsetParent = this.helper.offsetParent(); 16466 var po = this.offsetParent.offset(); 16467 16468 // This is a special case where we need to modify a offset calculated on start, since the 16469 // following happened: 16470 // 1. The position of the helper is absolute, so it's position is calculated based on the 16471 // next positioned parent 16472 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 16473 // the document, which means that the scroll is included in the initial calculation of the 16474 // offset of the parent, and never recalculated upon drag 16475 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] && 16476 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 16477 po.left += this.scrollParent.scrollLeft(); 16478 po.top += this.scrollParent.scrollTop(); 16479 } 16480 16481 // This needs to be actually done for all browsers, since pageX/pageY includes 16482 // this information. 16483 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ) { 16484 po = { top: 0, left: 0 }; 16485 } 16486 16487 return { 16488 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 16489 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 16490 }; 16491 16492 }, 16493 16494 _getRelativeOffset: function() { 16495 16496 if ( this.cssPosition === "relative" ) { 16497 var p = this.currentItem.position(); 16498 return { 16499 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 16500 this.scrollParent.scrollTop(), 16501 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 16502 this.scrollParent.scrollLeft() 16503 }; 16504 } else { 16505 return { top: 0, left: 0 }; 16506 } 16507 16508 }, 16509 16510 _cacheMargins: function() { 16511 this.margins = { 16512 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ), 16513 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 ) 16514 }; 16515 }, 16516 16517 _cacheHelperProportions: function() { 16518 this.helperProportions = { 16519 width: this.helper.outerWidth(), 16520 height: this.helper.outerHeight() 16521 }; 16522 }, 16523 16524 _setContainment: function() { 16525 16526 var ce, co, over, 16527 o = this.options; 16528 if ( o.containment === "parent" ) { 16529 o.containment = this.helper[ 0 ].parentNode; 16530 } 16531 if ( o.containment === "document" || o.containment === "window" ) { 16532 this.containment = [ 16533 0 - this.offset.relative.left - this.offset.parent.left, 16534 0 - this.offset.relative.top - this.offset.parent.top, 16535 o.containment === "document" ? 16536 this.document.width() : 16537 this.window.width() - this.helperProportions.width - this.margins.left, 16538 ( o.containment === "document" ? 16539 ( this.document.height() || document.body.parentNode.scrollHeight ) : 16540 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight 16541 ) - this.helperProportions.height - this.margins.top 16542 ]; 16543 } 16544 16545 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) { 16546 ce = $( o.containment )[ 0 ]; 16547 co = $( o.containment ).offset(); 16548 over = ( $( ce ).css( "overflow" ) !== "hidden" ); 16549 16550 this.containment = [ 16551 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) + 16552 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left, 16553 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) + 16554 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top, 16555 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 16556 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) - 16557 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) - 16558 this.helperProportions.width - this.margins.left, 16559 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 16560 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) - 16561 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) - 16562 this.helperProportions.height - this.margins.top 16563 ]; 16564 } 16565 16566 }, 16567 16568 _convertPositionTo: function( d, pos ) { 16569 16570 if ( !pos ) { 16571 pos = this.position; 16572 } 16573 var mod = d === "absolute" ? 1 : -1, 16574 scroll = this.cssPosition === "absolute" && 16575 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16576 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16577 this.offsetParent : 16578 this.scrollParent, 16579 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16580 16581 return { 16582 top: ( 16583 16584 // The absolute mouse position 16585 pos.top + 16586 16587 // Only for relative positioned nodes: Relative offset from element to offset parent 16588 this.offset.relative.top * mod + 16589 16590 // The offsetParent's offset without borders (offset + border) 16591 this.offset.parent.top * mod - 16592 ( ( this.cssPosition === "fixed" ? 16593 -this.scrollParent.scrollTop() : 16594 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod ) 16595 ), 16596 left: ( 16597 16598 // The absolute mouse position 16599 pos.left + 16600 16601 // Only for relative positioned nodes: Relative offset from element to offset parent 16602 this.offset.relative.left * mod + 16603 16604 // The offsetParent's offset without borders (offset + border) 16605 this.offset.parent.left * mod - 16606 ( ( this.cssPosition === "fixed" ? 16607 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : 16608 scroll.scrollLeft() ) * mod ) 16609 ) 16610 }; 16611 16612 }, 16613 16614 _generatePosition: function( event ) { 16615 16616 var top, left, 16617 o = this.options, 16618 pageX = event.pageX, 16619 pageY = event.pageY, 16620 scroll = this.cssPosition === "absolute" && 16621 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16622 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16623 this.offsetParent : 16624 this.scrollParent, 16625 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16626 16627 // This is another very weird special case that only happens for relative elements: 16628 // 1. If the css position is relative 16629 // 2. and the scroll parent is the document or similar to the offset parent 16630 // we have to refresh the relative offset during the scroll so there are no jumps 16631 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16632 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) { 16633 this.offset.relative = this._getRelativeOffset(); 16634 } 16635 16636 /* 16637 * - Position constraining - 16638 * Constrain the position to a mix of grid, containment. 16639 */ 16640 16641 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options 16642 16643 if ( this.containment ) { 16644 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) { 16645 pageX = this.containment[ 0 ] + this.offset.click.left; 16646 } 16647 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) { 16648 pageY = this.containment[ 1 ] + this.offset.click.top; 16649 } 16650 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) { 16651 pageX = this.containment[ 2 ] + this.offset.click.left; 16652 } 16653 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) { 16654 pageY = this.containment[ 3 ] + this.offset.click.top; 16655 } 16656 } 16657 16658 if ( o.grid ) { 16659 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) / 16660 o.grid[ 1 ] ) * o.grid[ 1 ]; 16661 pageY = this.containment ? 16662 ( ( top - this.offset.click.top >= this.containment[ 1 ] && 16663 top - this.offset.click.top <= this.containment[ 3 ] ) ? 16664 top : 16665 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ? 16666 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : 16667 top; 16668 16669 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) / 16670 o.grid[ 0 ] ) * o.grid[ 0 ]; 16671 pageX = this.containment ? 16672 ( ( left - this.offset.click.left >= this.containment[ 0 ] && 16673 left - this.offset.click.left <= this.containment[ 2 ] ) ? 16674 left : 16675 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ? 16676 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : 16677 left; 16678 } 16679 16680 } 16681 16682 return { 16683 top: ( 16684 16685 // The absolute mouse position 16686 pageY - 16687 16688 // Click offset (relative to the element) 16689 this.offset.click.top - 16690 16691 // Only for relative positioned nodes: Relative offset from element to offset parent 16692 this.offset.relative.top - 16693 16694 // The offsetParent's offset without borders (offset + border) 16695 this.offset.parent.top + 16696 ( ( this.cssPosition === "fixed" ? 16697 -this.scrollParent.scrollTop() : 16698 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) ) 16699 ), 16700 left: ( 16701 16702 // The absolute mouse position 16703 pageX - 16704 16705 // Click offset (relative to the element) 16706 this.offset.click.left - 16707 16708 // Only for relative positioned nodes: Relative offset from element to offset parent 16709 this.offset.relative.left - 16710 16711 // The offsetParent's offset without borders (offset + border) 16712 this.offset.parent.left + 16713 ( ( this.cssPosition === "fixed" ? 16714 -this.scrollParent.scrollLeft() : 16715 scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) 16716 ) 16717 }; 16718 16719 }, 16720 16721 _rearrange: function( event, i, a, hardRefresh ) { 16722 16723 if ( a ) { 16724 a[ 0 ].appendChild( this.placeholder[ 0 ] ); 16725 } else { 16726 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ], 16727 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) ); 16728 } 16729 16730 //Various things done here to improve the performance: 16731 // 1. we create a setTimeout, that calls refreshPositions 16732 // 2. on the instance, we have a counter variable, that get's higher after every append 16733 // 3. on the local scope, we copy the counter variable, and check in the timeout, 16734 // if it's still the same 16735 // 4. this lets only the last addition to the timeout stack through 16736 this.counter = this.counter ? ++this.counter : 1; 16737 var counter = this.counter; 16738 16739 this._delay( function() { 16740 if ( counter === this.counter ) { 16741 16742 //Precompute after each DOM insertion, NOT on mousemove 16743 this.refreshPositions( !hardRefresh ); 16744 } 16745 } ); 16746 16747 }, 16748 16749 _clear: function( event, noPropagation ) { 16750 16751 this.reverting = false; 16752 16753 // We delay all events that have to be triggered to after the point where the placeholder 16754 // has been removed and everything else normalized again 16755 var i, 16756 delayedTriggers = []; 16757 16758 // We first have to update the dom position of the actual currentItem 16759 // Note: don't do it if the current item is already removed (by a user), or it gets 16760 // reappended (see #4088) 16761 if ( !this._noFinalSort && this.currentItem.parent().length ) { 16762 this.placeholder.before( this.currentItem ); 16763 } 16764 this._noFinalSort = null; 16765 16766 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) { 16767 for ( i in this._storedCSS ) { 16768 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) { 16769 this._storedCSS[ i ] = ""; 16770 } 16771 } 16772 this.currentItem.css( this._storedCSS ); 16773 this._removeClass( this.currentItem, "ui-sortable-helper" ); 16774 } else { 16775 this.currentItem.show(); 16776 } 16777 16778 if ( this.fromOutside && !noPropagation ) { 16779 delayedTriggers.push( function( event ) { 16780 this._trigger( "receive", event, this._uiHash( this.fromOutside ) ); 16781 } ); 16782 } 16783 if ( ( this.fromOutside || 16784 this.domPosition.prev !== 16785 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] || 16786 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) { 16787 16788 // Trigger update callback if the DOM position has changed 16789 delayedTriggers.push( function( event ) { 16790 this._trigger( "update", event, this._uiHash() ); 16791 } ); 16792 } 16793 16794 // Check if the items Container has Changed and trigger appropriate 16795 // events. 16796 if ( this !== this.currentContainer ) { 16797 if ( !noPropagation ) { 16798 delayedTriggers.push( function( event ) { 16799 this._trigger( "remove", event, this._uiHash() ); 16800 } ); 16801 delayedTriggers.push( ( function( c ) { 16802 return function( event ) { 16803 c._trigger( "receive", event, this._uiHash( this ) ); 16804 }; 16805 } ).call( this, this.currentContainer ) ); 16806 delayedTriggers.push( ( function( c ) { 16807 return function( event ) { 16808 c._trigger( "update", event, this._uiHash( this ) ); 16809 }; 16810 } ).call( this, this.currentContainer ) ); 16811 } 16812 } 16813 16814 //Post events to containers 16815 function delayEvent( type, instance, container ) { 16816 return function( event ) { 16817 container._trigger( type, event, instance._uiHash( instance ) ); 16818 }; 16819 } 16820 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16821 if ( !noPropagation ) { 16822 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 16823 } 16824 if ( this.containers[ i ].containerCache.over ) { 16825 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 16826 this.containers[ i ].containerCache.over = 0; 16827 } 16828 } 16829 16830 //Do what was originally in plugins 16831 if ( this._storedStylesheet ) { 16832 this._storedStylesheet.remove(); 16833 this._storedStylesheet = null; 16834 } 16835 if ( this._storedOpacity ) { 16836 this.helper.css( "opacity", this._storedOpacity ); 16837 } 16838 if ( this._storedZIndex ) { 16839 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex ); 16840 } 16841 16842 this.dragging = false; 16843 16844 if ( !noPropagation ) { 16845 this._trigger( "beforeStop", event, this._uiHash() ); 16846 } 16847 16848 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 16849 // it unbinds ALL events from the original node! 16850 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 16851 16852 if ( !this.cancelHelperRemoval ) { 16853 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 16854 this.helper.remove(); 16855 } 16856 this.helper = null; 16857 } 16858 16859 if ( !noPropagation ) { 16860 for ( i = 0; i < delayedTriggers.length; i++ ) { 16861 16862 // Trigger all delayed events 16863 delayedTriggers[ i ].call( this, event ); 16864 } 16865 this._trigger( "stop", event, this._uiHash() ); 16866 } 16867 16868 this.fromOutside = false; 16869 return !this.cancelHelperRemoval; 16870 16871 }, 16872 16873 _trigger: function() { 16874 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) { 16875 this.cancel(); 16876 } 16877 }, 16878 16879 _uiHash: function( _inst ) { 16880 var inst = _inst || this; 16881 return { 16882 helper: inst.helper, 16883 placeholder: inst.placeholder || $( [] ), 16884 position: inst.position, 16885 originalPosition: inst.originalPosition, 16886 offset: inst.positionAbs, 16887 item: inst.currentItem, 16888 sender: _inst ? _inst.element : null 16889 }; 16890 } 16891 16892 } ); 16893 16894 16895 /*! 16896 * jQuery UI Spinner 1.14.1 16897 * https://jqueryui.com 16898 * 16899 * Copyright OpenJS Foundation and other contributors 16900 * Released under the MIT license. 16901 * https://jquery.org/license 16902 */ 16903 16904//>>label: Spinner 16905//>>group: Widgets 16906//>>description: Displays buttons to easily input numbers via the keyboard or mouse. 16907//>>docs: https://api.jqueryui.com/spinner/ 16908//>>demos: https://jqueryui.com/spinner/ 16909//>>css.structure: ../../themes/base/core.css 16910//>>css.structure: ../../themes/base/spinner.css 16911//>>css.theme: ../../themes/base/theme.css 16912 16913 16914 function spinnerModifier( fn ) { 16915 return function() { 16916 var previous = this.element.val(); 16917 fn.apply( this, arguments ); 16918 this._refresh(); 16919 if ( previous !== this.element.val() ) { 16920 this._trigger( "change" ); 16921 } 16922 }; 16923 } 16924 16925 $.widget( "ui.spinner", { 16926 version: "1.14.1", 16927 defaultElement: "<input>", 16928 widgetEventPrefix: "spin", 16929 options: { 16930 classes: { 16931 "ui-spinner": "ui-corner-all", 16932 "ui-spinner-down": "ui-corner-br", 16933 "ui-spinner-up": "ui-corner-tr" 16934 }, 16935 culture: null, 16936 icons: { 16937 down: "ui-icon-triangle-1-s", 16938 up: "ui-icon-triangle-1-n" 16939 }, 16940 incremental: true, 16941 max: null, 16942 min: null, 16943 numberFormat: null, 16944 page: 10, 16945 step: 1, 16946 16947 change: null, 16948 spin: null, 16949 start: null, 16950 stop: null 16951 }, 16952 16953 _create: function() { 16954 16955 // handle string values that need to be parsed 16956 this._setOption( "max", this.options.max ); 16957 this._setOption( "min", this.options.min ); 16958 this._setOption( "step", this.options.step ); 16959 16960 // Only format if there is a value, prevents the field from being marked 16961 // as invalid in Firefox, see #9573. 16962 if ( this.value() !== "" ) { 16963 16964 // Format the value, but don't constrain. 16965 this._value( this.element.val(), true ); 16966 } 16967 16968 this._draw(); 16969 this._on( this._events ); 16970 this._refresh(); 16971 16972 // Turning off autocomplete prevents the browser from remembering the 16973 // value when navigating through history, so we re-enable autocomplete 16974 // if the page is unloaded before the widget is destroyed. #7790 16975 this._on( this.window, { 16976 beforeunload: function() { 16977 this.element.removeAttr( "autocomplete" ); 16978 } 16979 } ); 16980 }, 16981 16982 _getCreateOptions: function() { 16983 var options = this._super(); 16984 var element = this.element; 16985 16986 $.each( [ "min", "max", "step" ], function( i, option ) { 16987 var value = element.attr( option ); 16988 if ( value != null && value.length ) { 16989 options[ option ] = value; 16990 } 16991 } ); 16992 16993 return options; 16994 }, 16995 16996 _events: { 16997 keydown: function( event ) { 16998 if ( this._start( event ) && this._keydown( event ) ) { 16999 event.preventDefault(); 17000 } 17001 }, 17002 keyup: "_stop", 17003 focus: function() { 17004 this.previous = this.element.val(); 17005 }, 17006 blur: function( event ) { 17007 this._stop(); 17008 this._refresh(); 17009 if ( this.previous !== this.element.val() ) { 17010 this._trigger( "change", event ); 17011 } 17012 }, 17013 mousewheel: function( event, delta ) { 17014 var activeElement = this.document[ 0 ].activeElement; 17015 var isActive = this.element[ 0 ] === activeElement; 17016 17017 if ( !isActive || !delta ) { 17018 return; 17019 } 17020 17021 if ( !this.spinning && !this._start( event ) ) { 17022 return false; 17023 } 17024 17025 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); 17026 clearTimeout( this.mousewheelTimer ); 17027 this.mousewheelTimer = this._delay( function() { 17028 if ( this.spinning ) { 17029 this._stop( event ); 17030 } 17031 }, 100 ); 17032 event.preventDefault(); 17033 }, 17034 "mousedown .ui-spinner-button": function( event ) { 17035 var previous; 17036 17037 // We never want the buttons to have focus; whenever the user is 17038 // interacting with the spinner, the focus should be on the input. 17039 // If the input is focused then this.previous is properly set from 17040 // when the input first received focus. If the input is not focused 17041 // then we need to set this.previous based on the value before spinning. 17042 previous = this.element[ 0 ] === this.document[ 0 ].activeElement ? 17043 this.previous : this.element.val(); 17044 function checkFocus() { 17045 var isActive = this.element[ 0 ] === this.document[ 0 ].activeElement; 17046 if ( !isActive ) { 17047 this.element.trigger( "focus" ); 17048 this.previous = previous; 17049 } 17050 } 17051 17052 // Ensure focus is on (or stays on) the text field 17053 event.preventDefault(); 17054 checkFocus.call( this ); 17055 17056 if ( this._start( event ) === false ) { 17057 return; 17058 } 17059 17060 this._repeat( null, $( event.currentTarget ) 17061 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 17062 }, 17063 "mouseup .ui-spinner-button": "_stop", 17064 "mouseenter .ui-spinner-button": function( event ) { 17065 17066 // button will add ui-state-active if mouse was down while mouseleave and kept down 17067 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 17068 return; 17069 } 17070 17071 if ( this._start( event ) === false ) { 17072 return false; 17073 } 17074 this._repeat( null, $( event.currentTarget ) 17075 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 17076 }, 17077 17078 // TODO: do we really want to consider this a stop? 17079 // shouldn't we just stop the repeater and wait until mouseup before 17080 // we trigger the stop event? 17081 "mouseleave .ui-spinner-button": "_stop" 17082 }, 17083 17084 // Support mobile enhanced option and make backcompat more sane 17085 _enhance: function() { 17086 this.uiSpinner = this.element 17087 .attr( "autocomplete", "off" ) 17088 .wrap( "<span>" ) 17089 .parent() 17090 17091 // Add buttons 17092 .append( 17093 "<a></a><a></a>" 17094 ); 17095 }, 17096 17097 _draw: function() { 17098 this._enhance(); 17099 17100 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); 17101 this._addClass( "ui-spinner-input" ); 17102 17103 this.element.attr( "role", "spinbutton" ); 17104 17105 // Button bindings 17106 this.buttons = this.uiSpinner.children( "a" ) 17107 .attr( "tabIndex", -1 ) 17108 .attr( "aria-hidden", true ) 17109 .button( { 17110 classes: { 17111 "ui-button": "" 17112 } 17113 } ); 17114 17115 // TODO: Right now button does not support classes this is already updated in button PR 17116 this._removeClass( this.buttons, "ui-corner-all" ); 17117 17118 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); 17119 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); 17120 this.buttons.first().button( { 17121 "icon": this.options.icons.up, 17122 "showLabel": false 17123 } ); 17124 this.buttons.last().button( { 17125 "icon": this.options.icons.down, 17126 "showLabel": false 17127 } ); 17128 17129 // IE 6 doesn't understand height: 50% for the buttons 17130 // unless the wrapper has an explicit height 17131 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && 17132 this.uiSpinner.height() > 0 ) { 17133 this.uiSpinner.height( this.uiSpinner.height() ); 17134 } 17135 }, 17136 17137 _keydown: function( event ) { 17138 var options = this.options, 17139 keyCode = $.ui.keyCode; 17140 17141 switch ( event.keyCode ) { 17142 case keyCode.UP: 17143 this._repeat( null, 1, event ); 17144 return true; 17145 case keyCode.DOWN: 17146 this._repeat( null, -1, event ); 17147 return true; 17148 case keyCode.PAGE_UP: 17149 this._repeat( null, options.page, event ); 17150 return true; 17151 case keyCode.PAGE_DOWN: 17152 this._repeat( null, -options.page, event ); 17153 return true; 17154 } 17155 17156 return false; 17157 }, 17158 17159 _start: function( event ) { 17160 if ( !this.spinning && this._trigger( "start", event ) === false ) { 17161 return false; 17162 } 17163 17164 if ( !this.counter ) { 17165 this.counter = 1; 17166 } 17167 this.spinning = true; 17168 return true; 17169 }, 17170 17171 _repeat: function( i, steps, event ) { 17172 i = i || 500; 17173 17174 clearTimeout( this.timer ); 17175 this.timer = this._delay( function() { 17176 this._repeat( 40, steps, event ); 17177 }, i ); 17178 17179 this._spin( steps * this.options.step, event ); 17180 }, 17181 17182 _spin: function( step, event ) { 17183 var value = this.value() || 0; 17184 17185 if ( !this.counter ) { 17186 this.counter = 1; 17187 } 17188 17189 value = this._adjustValue( value + step * this._increment( this.counter ) ); 17190 17191 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { 17192 this._value( value ); 17193 this.counter++; 17194 } 17195 }, 17196 17197 _increment: function( i ) { 17198 var incremental = this.options.incremental; 17199 17200 if ( incremental ) { 17201 return typeof incremental === "function" ? 17202 incremental( i ) : 17203 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 17204 } 17205 17206 return 1; 17207 }, 17208 17209 _precision: function() { 17210 var precision = this._precisionOf( this.options.step ); 17211 if ( this.options.min !== null ) { 17212 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 17213 } 17214 return precision; 17215 }, 17216 17217 _precisionOf: function( num ) { 17218 var str = num.toString(), 17219 decimal = str.indexOf( "." ); 17220 return decimal === -1 ? 0 : str.length - decimal - 1; 17221 }, 17222 17223 _adjustValue: function( value ) { 17224 var base, aboveMin, 17225 options = this.options; 17226 17227 // Make sure we're at a valid step 17228 // - find out where we are relative to the base (min or 0) 17229 base = options.min !== null ? options.min : 0; 17230 aboveMin = value - base; 17231 17232 // - round to the nearest step 17233 aboveMin = Math.round( aboveMin / options.step ) * options.step; 17234 17235 // - rounding is based on 0, so adjust back to our base 17236 value = base + aboveMin; 17237 17238 // Fix precision from bad JS floating point math 17239 value = parseFloat( value.toFixed( this._precision() ) ); 17240 17241 // Clamp the value 17242 if ( options.max !== null && value > options.max ) { 17243 return options.max; 17244 } 17245 if ( options.min !== null && value < options.min ) { 17246 return options.min; 17247 } 17248 17249 return value; 17250 }, 17251 17252 _stop: function( event ) { 17253 if ( !this.spinning ) { 17254 return; 17255 } 17256 17257 clearTimeout( this.timer ); 17258 clearTimeout( this.mousewheelTimer ); 17259 this.counter = 0; 17260 this.spinning = false; 17261 this._trigger( "stop", event ); 17262 }, 17263 17264 _setOption: function( key, value ) { 17265 var prevValue, first, last; 17266 17267 if ( key === "culture" || key === "numberFormat" ) { 17268 prevValue = this._parse( this.element.val() ); 17269 this.options[ key ] = value; 17270 this.element.val( this._format( prevValue ) ); 17271 return; 17272 } 17273 17274 if ( key === "max" || key === "min" || key === "step" ) { 17275 if ( typeof value === "string" ) { 17276 value = this._parse( value ); 17277 } 17278 } 17279 if ( key === "icons" ) { 17280 first = this.buttons.first().find( ".ui-icon" ); 17281 this._removeClass( first, null, this.options.icons.up ); 17282 this._addClass( first, null, value.up ); 17283 last = this.buttons.last().find( ".ui-icon" ); 17284 this._removeClass( last, null, this.options.icons.down ); 17285 this._addClass( last, null, value.down ); 17286 } 17287 17288 this._super( key, value ); 17289 }, 17290 17291 _setOptionDisabled: function( value ) { 17292 this._super( value ); 17293 17294 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); 17295 this.element.prop( "disabled", !!value ); 17296 this.buttons.button( value ? "disable" : "enable" ); 17297 }, 17298 17299 _setOptions: spinnerModifier( function( options ) { 17300 this._super( options ); 17301 } ), 17302 17303 _parse: function( val ) { 17304 if ( typeof val === "string" && val !== "" ) { 17305 val = window.Globalize && this.options.numberFormat ? 17306 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 17307 } 17308 return val === "" || isNaN( val ) ? null : val; 17309 }, 17310 17311 _format: function( value ) { 17312 if ( value === "" ) { 17313 return ""; 17314 } 17315 return window.Globalize && this.options.numberFormat ? 17316 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 17317 value; 17318 }, 17319 17320 _refresh: function() { 17321 this.element.attr( { 17322 "aria-valuemin": this.options.min, 17323 "aria-valuemax": this.options.max, 17324 17325 // TODO: what should we do with values that can't be parsed? 17326 "aria-valuenow": this._parse( this.element.val() ) 17327 } ); 17328 }, 17329 17330 isValid: function() { 17331 var value = this.value(); 17332 17333 // Null is invalid 17334 if ( value === null ) { 17335 return false; 17336 } 17337 17338 // If value gets adjusted, it's invalid 17339 return value === this._adjustValue( value ); 17340 }, 17341 17342 // Update the value without triggering change 17343 _value: function( value, allowAny ) { 17344 var parsed; 17345 if ( value !== "" ) { 17346 parsed = this._parse( value ); 17347 if ( parsed !== null ) { 17348 if ( !allowAny ) { 17349 parsed = this._adjustValue( parsed ); 17350 } 17351 value = this._format( parsed ); 17352 } 17353 } 17354 this.element.val( value ); 17355 this._refresh(); 17356 }, 17357 17358 _destroy: function() { 17359 this.element 17360 .prop( "disabled", false ) 17361 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); 17362 17363 this.uiSpinner.replaceWith( this.element ); 17364 }, 17365 17366 stepUp: spinnerModifier( function( steps ) { 17367 this._stepUp( steps ); 17368 } ), 17369 _stepUp: function( steps ) { 17370 if ( this._start() ) { 17371 this._spin( ( steps || 1 ) * this.options.step ); 17372 this._stop(); 17373 } 17374 }, 17375 17376 stepDown: spinnerModifier( function( steps ) { 17377 this._stepDown( steps ); 17378 } ), 17379 _stepDown: function( steps ) { 17380 if ( this._start() ) { 17381 this._spin( ( steps || 1 ) * -this.options.step ); 17382 this._stop(); 17383 } 17384 }, 17385 17386 pageUp: spinnerModifier( function( pages ) { 17387 this._stepUp( ( pages || 1 ) * this.options.page ); 17388 } ), 17389 17390 pageDown: spinnerModifier( function( pages ) { 17391 this._stepDown( ( pages || 1 ) * this.options.page ); 17392 } ), 17393 17394 value: function( newVal ) { 17395 if ( !arguments.length ) { 17396 return this._parse( this.element.val() ); 17397 } 17398 spinnerModifier( this._value ).call( this, newVal ); 17399 }, 17400 17401 widget: function() { 17402 return this.uiSpinner; 17403 } 17404 } ); 17405 17406// DEPRECATED 17407// TODO: switch return back to widget declaration at top of file when this is removed 17408 if ( $.uiBackCompat === true ) { 17409 17410 // Backcompat for spinner html extension points 17411 $.widget( "ui.spinner", $.ui.spinner, { 17412 _enhance: function() { 17413 this.uiSpinner = this.element 17414 .attr( "autocomplete", "off" ) 17415 .wrap( this._uiSpinnerHtml() ) 17416 .parent() 17417 17418 // Add buttons 17419 .append( this._buttonHtml() ); 17420 }, 17421 _uiSpinnerHtml: function() { 17422 return "<span>"; 17423 }, 17424 17425 _buttonHtml: function() { 17426 return "<a></a><a></a>"; 17427 } 17428 } ); 17429 } 17430 17431 var widgetsSpinner = $.ui.spinner; 17432 17433 17434 /*! 17435 * jQuery UI Tabs 1.14.1 17436 * https://jqueryui.com 17437 * 17438 * Copyright OpenJS Foundation and other contributors 17439 * Released under the MIT license. 17440 * https://jquery.org/license 17441 */ 17442 17443//>>label: Tabs 17444//>>group: Widgets 17445//>>description: Transforms a set of container elements into a tab structure. 17446//>>docs: https://api.jqueryui.com/tabs/ 17447//>>demos: https://jqueryui.com/tabs/ 17448//>>css.structure: ../../themes/base/core.css 17449//>>css.structure: ../../themes/base/tabs.css 17450//>>css.theme: ../../themes/base/theme.css 17451 17452 17453 $.widget( "ui.tabs", { 17454 version: "1.14.1", 17455 delay: 300, 17456 options: { 17457 active: null, 17458 classes: { 17459 "ui-tabs": "ui-corner-all", 17460 "ui-tabs-nav": "ui-corner-all", 17461 "ui-tabs-panel": "ui-corner-bottom", 17462 "ui-tabs-tab": "ui-corner-top" 17463 },
vendor: 7,426 bytes, lines 17464-17742
17464 collapsible: false, 17465 event: "click", 17466 heightStyle: "content", 17467 hide: null, 17468 show: null, 17469 17470 // Callbacks 17471 activate: null, 17472 beforeActivate: null, 17473 beforeLoad: null, 17474 load: null 17475 }, 17476 17477 _isLocal: ( function() { 17478 var rhash = /#.*$/; 17479 17480 return function( anchor ) { 17481 var anchorUrl, locationUrl; 17482 17483 anchorUrl = anchor.href.replace( rhash, "" ); 17484 locationUrl = location.href.replace( rhash, "" ); 17485 17486 // Decoding may throw an error if the URL isn't UTF-8 (#9518) 17487 try { 17488 anchorUrl = decodeURIComponent( anchorUrl ); 17489 } catch ( error ) {} 17490 try { 17491 locationUrl = decodeURIComponent( locationUrl ); 17492 } catch ( error ) {} 17493 17494 return anchor.hash.length > 1 && anchorUrl === locationUrl; 17495 }; 17496 } )(), 17497 17498 _create: function() { 17499 var that = this, 17500 options = this.options; 17501 17502 this.running = false; 17503 17504 this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); 17505 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); 17506 17507 this._processTabs(); 17508 options.active = this._initialActive(); 17509 17510 // Take disabling tabs via class attribute from HTML 17511 // into account and update option properly. 17512 if ( Array.isArray( options.disabled ) ) { 17513 options.disabled = $.uniqueSort( options.disabled.concat( 17514 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { 17515 return that.tabs.index( li ); 17516 } ) 17517 ) ).sort(); 17518 } 17519 17520 // Check for length avoids error when initializing empty list 17521 if ( this.options.active !== false && this.anchors.length ) { 17522 this.active = this._findActive( options.active ); 17523 } else { 17524 this.active = $(); 17525 } 17526 17527 this._refresh(); 17528 17529 if ( this.active.length ) { 17530 this.load( options.active ); 17531 } 17532 }, 17533 17534 _initialActive: function() { 17535 var active = this.options.active, 17536 collapsible = this.options.collapsible, 17537 locationHashDecoded = decodeURIComponent( location.hash.substring( 1 ) ); 17538 17539 if ( active === null ) { 17540 17541 // check the fragment identifier in the URL 17542 if ( locationHashDecoded ) { 17543 this.tabs.each( function( i, tab ) { 17544 if ( $( tab ).attr( "aria-controls" ) === locationHashDecoded ) { 17545 active = i; 17546 return false; 17547 } 17548 } ); 17549 } 17550 17551 // Check for a tab marked active via a class 17552 if ( active === null ) { 17553 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); 17554 } 17555 17556 // No active tab, set to false 17557 if ( active === null || active === -1 ) { 17558 active = this.tabs.length ? 0 : false; 17559 } 17560 } 17561 17562 // Handle numbers: negative, out of range 17563 if ( active !== false ) { 17564 active = this.tabs.index( this.tabs.eq( active ) ); 17565 if ( active === -1 ) { 17566 active = collapsible ? false : 0; 17567 } 17568 } 17569 17570 // Don't allow collapsible: false and active: false 17571 if ( !collapsible && active === false && this.anchors.length ) { 17572 active = 0; 17573 } 17574 17575 return active; 17576 }, 17577 17578 _getCreateEventData: function() { 17579 return { 17580 tab: this.active, 17581 panel: !this.active.length ? $() : this._getPanelForTab( this.active ) 17582 }; 17583 }, 17584 17585 _tabKeydown: function( event ) { 17586 var focusedTab = $( this.document[ 0 ].activeElement ).closest( "li" ), 17587 selectedIndex = this.tabs.index( focusedTab ), 17588 goingForward = true; 17589 17590 if ( this._handlePageNav( event ) ) { 17591 return; 17592 } 17593 17594 switch ( event.keyCode ) { 17595 case $.ui.keyCode.RIGHT: 17596 case $.ui.keyCode.DOWN: 17597 selectedIndex++; 17598 break; 17599 case $.ui.keyCode.UP: 17600 case $.ui.keyCode.LEFT: 17601 goingForward = false; 17602 selectedIndex--; 17603 break; 17604 case $.ui.keyCode.END: 17605 selectedIndex = this.anchors.length - 1; 17606 break; 17607 case $.ui.keyCode.HOME: 17608 selectedIndex = 0; 17609 break; 17610 case $.ui.keyCode.SPACE: 17611 17612 // Activate only, no collapsing 17613 event.preventDefault(); 17614 clearTimeout( this.activating ); 17615 this._activate( selectedIndex ); 17616 return; 17617 case $.ui.keyCode.ENTER: 17618 17619 // Toggle (cancel delayed activation, allow collapsing) 17620 event.preventDefault(); 17621 clearTimeout( this.activating ); 17622 17623 // Determine if we should collapse or activate 17624 this._activate( selectedIndex === this.options.active ? false : selectedIndex ); 17625 return; 17626 default: 17627 return; 17628 } 17629 17630 // Focus the appropriate tab, based on which key was pressed 17631 event.preventDefault(); 17632 clearTimeout( this.activating ); 17633 selectedIndex = this._focusNextTab( selectedIndex, goingForward ); 17634 17635 // Navigating with control/command key will prevent automatic activation 17636 if ( !event.ctrlKey && !event.metaKey ) { 17637 17638 // Update aria-selected immediately so that AT think the tab is already selected. 17639 // Otherwise AT may confuse the user by stating that they need to activate the tab, 17640 // but the tab will already be activated by the time the announcement finishes. 17641 focusedTab.attr( "aria-selected", "false" ); 17642 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); 17643 17644 this.activating = this._delay( function() { 17645 this.option( "active", selectedIndex ); 17646 }, this.delay ); 17647 } 17648 }, 17649 17650 _panelKeydown: function( event ) { 17651 if ( this._handlePageNav( event ) ) { 17652 return; 17653 } 17654 17655 // Ctrl+up moves focus to the current tab 17656 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { 17657 event.preventDefault(); 17658 this.active.trigger( "focus" ); 17659 } 17660 }, 17661 17662 // Alt+page up/down moves focus to the previous/next tab (and activates) 17663 _handlePageNav: function( event ) { 17664 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { 17665 this._activate( this._focusNextTab( this.options.active - 1, false ) ); 17666 return true; 17667 } 17668 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { 17669 this._activate( this._focusNextTab( this.options.active + 1, true ) ); 17670 return true; 17671 } 17672 }, 17673 17674 _findNextTab: function( index, goingForward ) { 17675 var lastTabIndex = this.tabs.length - 1; 17676 17677 function constrain() { 17678 if ( index > lastTabIndex ) { 17679 index = 0; 17680 } 17681 if ( index < 0 ) { 17682 index = lastTabIndex; 17683 } 17684 return index; 17685 } 17686 17687 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { 17688 index = goingForward ? index + 1 : index - 1; 17689 } 17690 17691 return index; 17692 }, 17693 17694 _focusNextTab: function( index, goingForward ) { 17695 index = this._findNextTab( index, goingForward ); 17696 this.tabs.eq( index ).trigger( "focus" ); 17697 return index; 17698 }, 17699 17700 _setOption: function( key, value ) { 17701 if ( key === "active" ) { 17702 17703 // _activate() will handle invalid values and update this.options 17704 this._activate( value ); 17705 return; 17706 } 17707 17708 this._super( key, value ); 17709 17710 if ( key === "collapsible" ) { 17711 this._toggleClass( "ui-tabs-collapsible", null, value ); 17712 17713 // Setting collapsible: false while collapsed; open first panel 17714 if ( !value && this.options.active === false ) { 17715 this._activate( 0 ); 17716 } 17717 } 17718 17719 if ( key === "event" ) { 17720 this._setupEvents( value ); 17721 } 17722 17723 if ( key === "heightStyle" ) { 17724 this._setupHeightStyle( value ); 17725 } 17726 }, 17727 17728 refresh: function() { 17729 var options = this.options, 17730 lis = this.tablist.children( ":has(a[href])" ); 17731 17732 // Get disabled tabs from class attribute from HTML 17733 // this will get converted to a boolean if needed in _refresh() 17734 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { 17735 return lis.index( tab ); 17736 } ); 17737 17738 this._processTabs(); 17739 17740 // Was collapsed or no tabs 17741 if ( options.active === false || !this.anchors.length ) { 17742 options.active = false;
vendor: 29,075 bytes, lines 17743-18809
17743 this.active = $(); 17744 17745 // was active, but active tab is gone 17746 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { 17747 17748 // all remaining tabs are disabled 17749 if ( this.tabs.length === options.disabled.length ) { 17750 options.active = false; 17751 this.active = $(); 17752 17753 // activate previous tab 17754 } else { 17755 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); 17756 } 17757 17758 // was active, active tab still exists 17759 } else { 17760 17761 // make sure active index is correct 17762 options.active = this.tabs.index( this.active ); 17763 } 17764 17765 this._refresh(); 17766 }, 17767 17768 _refresh: function() { 17769 this._setOptionDisabled( this.options.disabled ); 17770 this._setupEvents( this.options.event ); 17771 this._setupHeightStyle( this.options.heightStyle ); 17772 17773 this.tabs.not( this.active ).attr( { 17774 "aria-selected": "false", 17775 "aria-expanded": "false", 17776 tabIndex: -1 17777 } ); 17778 this.panels.not( this._getPanelForTab( this.active ) ) 17779 .hide() 17780 .attr( { 17781 "aria-hidden": "true" 17782 } ); 17783 17784 // Make sure one tab is in the tab order 17785 if ( !this.active.length ) { 17786 this.tabs.eq( 0 ).attr( "tabIndex", 0 ); 17787 } else { 17788 this.active 17789 .attr( { 17790 "aria-selected": "true", 17791 "aria-expanded": "true", 17792 tabIndex: 0 17793 } ); 17794 this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); 17795 this._getPanelForTab( this.active ) 17796 .show() 17797 .attr( { 17798 "aria-hidden": "false" 17799 } ); 17800 } 17801 }, 17802 17803 _processTabs: function() { 17804 var that = this, 17805 prevTabs = this.tabs, 17806 prevAnchors = this.anchors, 17807 prevPanels = this.panels; 17808 17809 this.tablist = this._getList().attr( "role", "tablist" ); 17810 this._addClass( this.tablist, "ui-tabs-nav", 17811 "ui-helper-reset ui-helper-clearfix ui-widget-header" ); 17812 17813 // Prevent users from focusing disabled tabs via click 17814 this.tablist 17815 .on( "mousedown" + this.eventNamespace, "> li", function( event ) { 17816 if ( $( this ).is( ".ui-state-disabled" ) ) { 17817 event.preventDefault(); 17818 } 17819 } ); 17820 17821 this.tabs = this.tablist.find( "> li:has(a[href])" ) 17822 .attr( { 17823 role: "tab", 17824 tabIndex: -1 17825 } ); 17826 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); 17827 17828 this.anchors = this.tabs.map( function() { 17829 return $( "a", this )[ 0 ]; 17830 } ) 17831 .attr( { 17832 tabIndex: -1 17833 } ); 17834 this._addClass( this.anchors, "ui-tabs-anchor" ); 17835 17836 this.panels = $(); 17837 17838 this.anchors.each( function( i, anchor ) { 17839 var selector, panel, panelId, 17840 anchorId = $( anchor ).uniqueId().attr( "id" ), 17841 tab = $( anchor ).closest( "li" ), 17842 originalAriaControls = tab.attr( "aria-controls" ); 17843 17844 // Inline tab 17845 if ( that._isLocal( anchor ) ) { 17846 selector = decodeURIComponent( anchor.hash ); 17847 panelId = selector.substring( 1 ); 17848 panel = that.element.find( "#" + CSS.escape( panelId ) ); 17849 17850 // remote tab 17851 } else { 17852 17853 // If the tab doesn't already have aria-controls, 17854 // generate an id by using a throw-away element 17855 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; 17856 selector = "#" + panelId; 17857 panel = that.element.find( selector ); 17858 if ( !panel.length ) { 17859 panel = that._createPanel( panelId ); 17860 panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); 17861 } 17862 panel.attr( "aria-live", "polite" ); 17863 } 17864 17865 if ( panel.length ) { 17866 that.panels = that.panels.add( panel ); 17867 } 17868 if ( originalAriaControls ) { 17869 tab.data( "ui-tabs-aria-controls", originalAriaControls ); 17870 } 17871 tab.attr( { 17872 "aria-controls": panelId, 17873 "aria-labelledby": anchorId 17874 } ); 17875 panel.attr( "aria-labelledby", anchorId ); 17876 } ); 17877 17878 this.panels.attr( "role", "tabpanel" ); 17879 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); 17880 17881 // Avoid memory leaks (#10056) 17882 if ( prevTabs ) { 17883 this._off( prevTabs.not( this.tabs ) ); 17884 this._off( prevAnchors.not( this.anchors ) ); 17885 this._off( prevPanels.not( this.panels ) ); 17886 } 17887 }, 17888 17889 // Allow overriding how to find the list for rare usage scenarios (#7715) 17890 _getList: function() { 17891 return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); 17892 }, 17893 17894 _createPanel: function( id ) { 17895 return $( "<div>" ) 17896 .attr( "id", id ) 17897 .data( "ui-tabs-destroy", true ); 17898 }, 17899 17900 _setOptionDisabled: function( disabled ) { 17901 var currentItem, li, i; 17902 17903 if ( Array.isArray( disabled ) ) { 17904 if ( !disabled.length ) { 17905 disabled = false; 17906 } else if ( disabled.length === this.anchors.length ) { 17907 disabled = true; 17908 } 17909 } 17910 17911 // Disable tabs 17912 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { 17913 currentItem = $( li ); 17914 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { 17915 currentItem.attr( "aria-disabled", "true" ); 17916 this._addClass( currentItem, null, "ui-state-disabled" ); 17917 } else { 17918 currentItem.removeAttr( "aria-disabled" ); 17919 this._removeClass( currentItem, null, "ui-state-disabled" ); 17920 } 17921 } 17922 17923 this.options.disabled = disabled; 17924 17925 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, 17926 disabled === true ); 17927 }, 17928 17929 _setupEvents: function( event ) { 17930 var events = {}; 17931 if ( event ) { 17932 $.each( event.split( " " ), function( index, eventName ) { 17933 events[ eventName ] = "_eventHandler"; 17934 } ); 17935 } 17936 17937 this._off( this.anchors.add( this.tabs ).add( this.panels ) ); 17938 17939 // Always prevent the default action, even when disabled 17940 this._on( true, this.anchors, { 17941 click: function( event ) { 17942 event.preventDefault(); 17943 } 17944 } ); 17945 this._on( this.anchors, events ); 17946 this._on( this.tabs, { keydown: "_tabKeydown" } ); 17947 this._on( this.panels, { keydown: "_panelKeydown" } ); 17948 17949 this._focusable( this.tabs ); 17950 this._hoverable( this.tabs ); 17951 }, 17952 17953 _setupHeightStyle: function( heightStyle ) { 17954 var maxHeight, 17955 parent = this.element.parent(); 17956 17957 if ( heightStyle === "fill" ) { 17958 maxHeight = parent.height(); 17959 maxHeight -= this.element.outerHeight() - this.element.height(); 17960 17961 this.element.siblings( ":visible" ).each( function() { 17962 var elem = $( this ), 17963 position = elem.css( "position" ); 17964 17965 if ( position === "absolute" || position === "fixed" ) { 17966 return; 17967 } 17968 maxHeight -= elem.outerHeight( true ); 17969 } ); 17970 17971 this.element.children().not( this.panels ).each( function() { 17972 maxHeight -= $( this ).outerHeight( true ); 17973 } ); 17974 17975 this.panels.each( function() { 17976 $( this ).height( Math.max( 0, maxHeight - 17977 $( this ).innerHeight() + $( this ).height() ) ); 17978 } ) 17979 .css( "overflow", "auto" ); 17980 } else if ( heightStyle === "auto" ) { 17981 maxHeight = 0; 17982 this.panels.each( function() { 17983 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 17984 } ).height( maxHeight ); 17985 } 17986 }, 17987 17988 _eventHandler: function( event ) { 17989 var options = this.options, 17990 active = this.active, 17991 anchor = $( event.currentTarget ), 17992 tab = anchor.closest( "li" ), 17993 clickedIsActive = tab[ 0 ] === active[ 0 ], 17994 collapsing = clickedIsActive && options.collapsible, 17995 toShow = collapsing ? $() : this._getPanelForTab( tab ), 17996 toHide = !active.length ? $() : this._getPanelForTab( active ), 17997 eventData = { 17998 oldTab: active, 17999 oldPanel: toHide, 18000 newTab: collapsing ? $() : tab, 18001 newPanel: toShow 18002 }; 18003 18004 event.preventDefault(); 18005 18006 if ( tab.hasClass( "ui-state-disabled" ) || 18007 18008 // tab is already loading 18009 tab.hasClass( "ui-tabs-loading" ) || 18010 18011 // can't switch durning an animation 18012 this.running || 18013 18014 // click on active header, but not collapsible 18015 ( clickedIsActive && !options.collapsible ) || 18016 18017 // allow canceling activation 18018 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 18019 return; 18020 } 18021 18022 options.active = collapsing ? false : this.tabs.index( tab ); 18023 18024 this.active = clickedIsActive ? $() : tab; 18025 if ( this.xhr ) { 18026 this.xhr.abort(); 18027 } 18028 18029 if ( !toHide.length && !toShow.length ) { 18030 $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); 18031 } 18032 18033 if ( toShow.length ) { 18034 this.load( this.tabs.index( tab ), event ); 18035 } 18036 this._toggle( event, eventData ); 18037 }, 18038 18039 // Handles show/hide for selecting tabs 18040 _toggle: function( event, eventData ) { 18041 var that = this, 18042 toShow = eventData.newPanel, 18043 toHide = eventData.oldPanel; 18044 18045 this.running = true; 18046 18047 function complete() { 18048 that.running = false; 18049 that._trigger( "activate", event, eventData ); 18050 } 18051 18052 function show() { 18053 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); 18054 18055 if ( toShow.length && that.options.show ) { 18056 that._show( toShow, that.options.show, complete ); 18057 } else { 18058 toShow.show(); 18059 complete(); 18060 } 18061 } 18062 18063 // Start out by hiding, then showing, then completing 18064 if ( toHide.length && this.options.hide ) { 18065 this._hide( toHide, this.options.hide, function() { 18066 that._removeClass( eventData.oldTab.closest( "li" ), 18067 "ui-tabs-active", "ui-state-active" ); 18068 show(); 18069 } ); 18070 } else { 18071 this._removeClass( eventData.oldTab.closest( "li" ), 18072 "ui-tabs-active", "ui-state-active" ); 18073 toHide.hide(); 18074 show(); 18075 } 18076 18077 toHide.attr( "aria-hidden", "true" ); 18078 eventData.oldTab.attr( { 18079 "aria-selected": "false", 18080 "aria-expanded": "false" 18081 } ); 18082 18083 // If we're switching tabs, remove the old tab from the tab order. 18084 // If we're opening from collapsed state, remove the previous tab from the tab order. 18085 // If we're collapsing, then keep the collapsing tab in the tab order. 18086 if ( toShow.length && toHide.length ) { 18087 eventData.oldTab.attr( "tabIndex", -1 ); 18088 } else if ( toShow.length ) { 18089 this.tabs.filter( function() { 18090 return $( this ).attr( "tabIndex" ) === 0; 18091 } ) 18092 .attr( "tabIndex", -1 ); 18093 } 18094 18095 toShow.attr( "aria-hidden", "false" ); 18096 eventData.newTab.attr( { 18097 "aria-selected": "true", 18098 "aria-expanded": "true", 18099 tabIndex: 0 18100 } ); 18101 }, 18102 18103 _activate: function( index ) { 18104 var anchor, 18105 active = this._findActive( index ); 18106 18107 // Trying to activate the already active panel 18108 if ( active[ 0 ] === this.active[ 0 ] ) { 18109 return; 18110 } 18111 18112 // Trying to collapse, simulate a click on the current active header 18113 if ( !active.length ) { 18114 active = this.active; 18115 } 18116 18117 anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; 18118 this._eventHandler( { 18119 target: anchor, 18120 currentTarget: anchor, 18121 preventDefault: $.noop 18122 } ); 18123 }, 18124 18125 _findActive: function( index ) { 18126 return index === false ? $() : this.tabs.eq( index ); 18127 }, 18128 18129 _getIndex: function( index ) { 18130 18131 // meta-function to give users option to provide a href string instead of a numerical index. 18132 if ( typeof index === "string" ) { 18133 index = this.anchors.index( this.anchors.filter( "[href$='" + 18134 CSS.escape( index ) + "']" ) ); 18135 } 18136 18137 return index; 18138 }, 18139 18140 _destroy: function() { 18141 if ( this.xhr ) { 18142 this.xhr.abort(); 18143 } 18144 18145 this.tablist 18146 .removeAttr( "role" ) 18147 .off( this.eventNamespace ); 18148 18149 this.anchors 18150 .removeAttr( "role tabIndex" ) 18151 .removeUniqueId(); 18152 18153 this.tabs.add( this.panels ).each( function() { 18154 if ( $.data( this, "ui-tabs-destroy" ) ) { 18155 $( this ).remove(); 18156 } else { 18157 $( this ).removeAttr( "role tabIndex " + 18158 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); 18159 } 18160 } ); 18161 18162 this.tabs.each( function() { 18163 var li = $( this ), 18164 prev = li.data( "ui-tabs-aria-controls" ); 18165 if ( prev ) { 18166 li 18167 .attr( "aria-controls", prev ) 18168 .removeData( "ui-tabs-aria-controls" ); 18169 } else { 18170 li.removeAttr( "aria-controls" ); 18171 } 18172 } ); 18173 18174 this.panels.show(); 18175 18176 if ( this.options.heightStyle !== "content" ) { 18177 this.panels.css( "height", "" ); 18178 } 18179 }, 18180 18181 enable: function( index ) { 18182 var disabled = this.options.disabled; 18183 if ( disabled === false ) { 18184 return; 18185 } 18186 18187 if ( index === undefined ) { 18188 disabled = false; 18189 } else { 18190 index = this._getIndex( index ); 18191 if ( Array.isArray( disabled ) ) { 18192 disabled = $.map( disabled, function( num ) { 18193 return num !== index ? num : null; 18194 } ); 18195 } else { 18196 disabled = $.map( this.tabs, function( li, num ) { 18197 return num !== index ? num : null; 18198 } ); 18199 } 18200 } 18201 this._setOptionDisabled( disabled ); 18202 }, 18203 18204 disable: function( index ) { 18205 var disabled = this.options.disabled; 18206 if ( disabled === true ) { 18207 return; 18208 } 18209 18210 if ( index === undefined ) { 18211 disabled = true; 18212 } else { 18213 index = this._getIndex( index ); 18214 if ( $.inArray( index, disabled ) !== -1 ) { 18215 return; 18216 } 18217 if ( Array.isArray( disabled ) ) { 18218 disabled = $.merge( [ index ], disabled ).sort(); 18219 } else { 18220 disabled = [ index ]; 18221 } 18222 } 18223 this._setOptionDisabled( disabled ); 18224 }, 18225 18226 load: function( index, event ) { 18227 index = this._getIndex( index ); 18228 var that = this, 18229 tab = this.tabs.eq( index ), 18230 anchor = tab.find( ".ui-tabs-anchor" ), 18231 panel = this._getPanelForTab( tab ), 18232 eventData = { 18233 tab: tab, 18234 panel: panel 18235 }, 18236 complete = function( jqXHR, status ) { 18237 if ( status === "abort" ) { 18238 that.panels.stop( false, true ); 18239 } 18240 18241 that._removeClass( tab, "ui-tabs-loading" ); 18242 panel.removeAttr( "aria-busy" ); 18243 18244 if ( jqXHR === that.xhr ) { 18245 delete that.xhr; 18246 } 18247 }; 18248 18249 // Not remote 18250 if ( this._isLocal( anchor[ 0 ] ) ) { 18251 return; 18252 } 18253 18254 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); 18255 18256 if ( this.xhr.statusText !== "canceled" ) { 18257 this._addClass( tab, "ui-tabs-loading" ); 18258 panel.attr( "aria-busy", "true" ); 18259 18260 this.xhr 18261 .done( function( response, status, jqXHR ) { 18262 panel.html( response ); 18263 that._trigger( "load", event, eventData ); 18264 18265 complete( jqXHR, status ); 18266 } ) 18267 .fail( function( jqXHR, status ) { 18268 complete( jqXHR, status ); 18269 } ); 18270 } 18271 }, 18272 18273 _ajaxSettings: function( anchor, event, eventData ) { 18274 var that = this; 18275 return { 18276 url: anchor.attr( "href" ), 18277 beforeSend: function( jqXHR, settings ) { 18278 return that._trigger( "beforeLoad", event, 18279 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); 18280 } 18281 }; 18282 }, 18283 18284 _getPanelForTab: function( tab ) { 18285 var id = $( tab ).attr( "aria-controls" ); 18286 return this.element.find( "#" + CSS.escape( id ) ); 18287 } 18288 } ); 18289 18290// DEPRECATED 18291// TODO: Switch return back to widget declaration at top of file when this is removed 18292 if ( $.uiBackCompat === true ) { 18293 18294 // Backcompat for ui-tab class (now ui-tabs-tab) 18295 $.widget( "ui.tabs", $.ui.tabs, { 18296 _processTabs: function() { 18297 this._superApply( arguments ); 18298 this._addClass( this.tabs, "ui-tab" ); 18299 } 18300 } ); 18301 } 18302 18303 var widgetsTabs = $.ui.tabs; 18304 18305 18306 /*! 18307 * jQuery UI Tooltip 1.14.1 18308 * https://jqueryui.com 18309 * 18310 * Copyright OpenJS Foundation and other contributors 18311 * Released under the MIT license. 18312 * https://jquery.org/license 18313 */ 18314 18315//>>label: Tooltip 18316//>>group: Widgets 18317//>>description: Shows additional information for any element on hover or focus. 18318//>>docs: https://api.jqueryui.com/tooltip/ 18319//>>demos: https://jqueryui.com/tooltip/ 18320//>>css.structure: ../../themes/base/core.css 18321//>>css.structure: ../../themes/base/tooltip.css 18322//>>css.theme: ../../themes/base/theme.css 18323 18324 18325 $.widget( "ui.tooltip", { 18326 version: "1.14.1", 18327 options: { 18328 classes: { 18329 "ui-tooltip": "ui-corner-all ui-widget-shadow" 18330 }, 18331 content: function() { 18332 var title = $( this ).attr( "title" ); 18333 18334 // Escape title, since we're going from an attribute to raw HTML 18335 return $( "<a>" ).text( title ).html(); 18336 }, 18337 hide: true, 18338 18339 // Disabled elements have inconsistent behavior across browsers (#8661) 18340 items: "[title]:not([disabled])", 18341 position: { 18342 my: "left top+15", 18343 at: "left bottom", 18344 collision: "flipfit flip" 18345 }, 18346 show: true, 18347 track: false, 18348 18349 // Callbacks 18350 close: null, 18351 open: null 18352 }, 18353 18354 _addDescribedBy: function( elem, id ) { 18355 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); 18356 describedby.push( id ); 18357 elem 18358 .data( "ui-tooltip-id", id ) 18359 .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) ); 18360 }, 18361 18362 _removeDescribedBy: function( elem ) { 18363 var id = elem.data( "ui-tooltip-id" ), 18364 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), 18365 index = $.inArray( id, describedby ); 18366 18367 if ( index !== -1 ) { 18368 describedby.splice( index, 1 ); 18369 } 18370 18371 elem.removeData( "ui-tooltip-id" ); 18372 describedby = String.prototype.trim.call( describedby.join( " " ) ); 18373 if ( describedby ) { 18374 elem.attr( "aria-describedby", describedby ); 18375 } else { 18376 elem.removeAttr( "aria-describedby" ); 18377 } 18378 }, 18379 18380 _create: function() { 18381 this._on( { 18382 mouseover: "open", 18383 focusin: "open" 18384 } ); 18385 18386 // IDs of generated tooltips, needed for destroy 18387 this.tooltips = {}; 18388 18389 // IDs of parent tooltips where we removed the title attribute 18390 this.parents = {}; 18391 18392 // Append the aria-live region so tooltips announce correctly 18393 this.liveRegion = $( "<div>" ) 18394 .attr( { 18395 role: "log", 18396 "aria-live": "assertive", 18397 "aria-relevant": "additions" 18398 } ) 18399 .appendTo( this.document[ 0 ].body ); 18400 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 18401 18402 this.disabledTitles = $( [] ); 18403 }, 18404 18405 _setOption: function( key, value ) { 18406 var that = this; 18407 18408 this._super( key, value ); 18409 18410 if ( key === "content" ) { 18411 $.each( this.tooltips, function( id, tooltipData ) { 18412 that._updateContent( tooltipData.element ); 18413 } ); 18414 } 18415 }, 18416 18417 _setOptionDisabled: function( value ) { 18418 this[ value ? "_disable" : "_enable" ](); 18419 }, 18420 18421 _disable: function() { 18422 var that = this; 18423 18424 // Close open tooltips 18425 $.each( this.tooltips, function( id, tooltipData ) { 18426 var event = $.Event( "blur" ); 18427 event.target = event.currentTarget = tooltipData.element[ 0 ]; 18428 that.close( event, true ); 18429 } ); 18430 18431 // Remove title attributes to prevent native tooltips 18432 this.disabledTitles = this.disabledTitles.add( 18433 this.element.find( this.options.items ).addBack() 18434 .filter( function() { 18435 var element = $( this ); 18436 if ( element.is( "[title]" ) ) { 18437 return element 18438 .data( "ui-tooltip-title", element.attr( "title" ) ) 18439 .removeAttr( "title" ); 18440 } 18441 } ) 18442 ); 18443 }, 18444 18445 _enable: function() { 18446 18447 // restore title attributes 18448 this.disabledTitles.each( function() { 18449 var element = $( this ); 18450 if ( element.data( "ui-tooltip-title" ) ) { 18451 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18452 } 18453 } ); 18454 this.disabledTitles = $( [] ); 18455 }, 18456 18457 open: function( event ) { 18458 var that = this, 18459 target = $( event ? event.target : this.element ) 18460 18461 // we need closest here due to mouseover bubbling, 18462 // but always pointing at the same event target 18463 .closest( this.options.items ); 18464 18465 // No element to show a tooltip for or the tooltip is already open 18466 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 18467 return; 18468 } 18469 18470 if ( target.attr( "title" ) ) { 18471 target.data( "ui-tooltip-title", target.attr( "title" ) ); 18472 } 18473 18474 target.data( "ui-tooltip-open", true ); 18475 18476 // Kill parent tooltips, custom or native, for hover 18477 if ( event && event.type === "mouseover" ) { 18478 target.parents().each( function() { 18479 var parent = $( this ), 18480 blurEvent; 18481 if ( parent.data( "ui-tooltip-open" ) ) { 18482 blurEvent = $.Event( "blur" ); 18483 blurEvent.target = blurEvent.currentTarget = this; 18484 that.close( blurEvent, true ); 18485 } 18486 if ( parent.attr( "title" ) ) { 18487 parent.uniqueId(); 18488 that.parents[ this.id ] = { 18489 element: this, 18490 title: parent.attr( "title" ) 18491 }; 18492 parent.attr( "title", "" ); 18493 } 18494 } ); 18495 } 18496 18497 this._registerCloseHandlers( event, target ); 18498 this._updateContent( target, event ); 18499 }, 18500 18501 _updateContent: function( target, event ) { 18502 var content, 18503 contentOption = this.options.content, 18504 that = this, 18505 eventType = event ? event.type : null; 18506 18507 if ( typeof contentOption === "string" || contentOption.nodeType || 18508 contentOption.jquery ) { 18509 return this._open( event, target, contentOption ); 18510 } 18511 18512 content = contentOption.call( target[ 0 ], function( response ) { 18513 18514 // Ignore async response if tooltip was closed already 18515 if ( !target.data( "ui-tooltip-open" ) ) { 18516 return; 18517 } 18518 18519 // JQuery creates a special event for focusin when it doesn't 18520 // exist natively. To improve performance, the native event 18521 // object is reused and the type is changed. Therefore, we can't 18522 // rely on the type being correct after the event finished 18523 // bubbling, so we set it back to the previous value. (#8740) 18524 if ( event ) { 18525 event.type = eventType; 18526 } 18527 that._open( event, target, response ); 18528 } ); 18529 if ( content ) { 18530 this._open( event, target, content ); 18531 } 18532 }, 18533 18534 _open: function( event, target, content ) { 18535 var tooltipData, tooltip, delayedShow, a11yContent, 18536 positionOption = $.extend( {}, this.options.position ); 18537 18538 if ( !content ) { 18539 return; 18540 } 18541 18542 // Content can be updated multiple times. If the tooltip already 18543 // exists, then just update the content and bail. 18544 tooltipData = this._find( target ); 18545 if ( tooltipData ) { 18546 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); 18547 return; 18548 } 18549 18550 // If we have a title, clear it to prevent the native tooltip 18551 // we have to check first to avoid defining a title if none exists 18552 // (we don't want to cause an element to start matching [title]) 18553 // 18554 // We use removeAttr only for key events, to allow IE to export the correct 18555 // accessible attributes. For mouse events, set to empty string to avoid 18556 // native tooltip showing up (happens only when removing inside mouseover). 18557 if ( target.is( "[title]" ) ) { 18558 if ( event && event.type === "mouseover" ) { 18559 target.attr( "title", "" ); 18560 } else { 18561 target.removeAttr( "title" ); 18562 } 18563 } 18564 18565 tooltipData = this._tooltip( target ); 18566 tooltip = tooltipData.tooltip; 18567 this._addDescribedBy( target, tooltip.attr( "id" ) ); 18568 tooltip.find( ".ui-tooltip-content" ).html( content ); 18569 18570 // Support: Voiceover on OS X, JAWS on IE <= 9 18571 // JAWS announces deletions even when aria-relevant="additions" 18572 // Voiceover will sometimes re-read the entire log region's contents from the beginning 18573 this.liveRegion.children().hide(); 18574 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() ); 18575 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); 18576 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 18577 a11yContent.appendTo( this.liveRegion ); 18578 18579 function position( event ) { 18580 positionOption.of = event; 18581 if ( tooltip.is( ":hidden" ) ) { 18582 return; 18583 } 18584 tooltip.position( positionOption ); 18585 } 18586 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 18587 this._on( this.document, { 18588 mousemove: position 18589 } ); 18590 18591 // trigger once to override element-relative positioning 18592 position( event ); 18593 } else { 18594 tooltip.position( $.extend( { 18595 of: target 18596 }, this.options.position ) ); 18597 } 18598 18599 tooltip.hide(); 18600 18601 this._show( tooltip, this.options.show ); 18602 18603 // Handle tracking tooltips that are shown with a delay (#8644). As soon 18604 // as the tooltip is visible, position the tooltip using the most recent 18605 // event. 18606 // Adds the check to add the timers only when both delay and track options are set (#14682) 18607 if ( this.options.track && this.options.show && this.options.show.delay ) { 18608 delayedShow = this.delayedShow = setInterval( function() { 18609 if ( tooltip.is( ":visible" ) ) { 18610 position( positionOption.of ); 18611 clearInterval( delayedShow ); 18612 } 18613 }, 13 ); 18614 } 18615 18616 this._trigger( "open", event, { tooltip: tooltip } ); 18617 }, 18618 18619 _registerCloseHandlers: function( event, target ) { 18620 var events = { 18621 keyup: function( event ) { 18622 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 18623 var fakeEvent = $.Event( event ); 18624 fakeEvent.currentTarget = target[ 0 ]; 18625 this.close( fakeEvent, true ); 18626 } 18627 } 18628 }; 18629 18630 // Only bind remove handler for delegated targets. Non-delegated 18631 // tooltips will handle this in destroy. 18632 if ( target[ 0 ] !== this.element[ 0 ] ) { 18633 events.remove = function() { 18634 var targetElement = this._find( target ); 18635 if ( targetElement ) { 18636 this._removeTooltip( targetElement.tooltip ); 18637 } 18638 }; 18639 } 18640 18641 if ( !event || event.type === "mouseover" ) { 18642 events.mouseleave = "close"; 18643 } 18644 if ( !event || event.type === "focusin" ) { 18645 events.focusout = "close"; 18646 } 18647 this._on( true, target, events ); 18648 }, 18649 18650 close: function( event ) { 18651 var tooltip, 18652 that = this, 18653 target = $( event ? event.currentTarget : this.element ), 18654 tooltipData = this._find( target ); 18655 18656 // The tooltip may already be closed 18657 if ( !tooltipData ) { 18658 18659 // We set ui-tooltip-open immediately upon open (in open()), but only set the 18660 // additional data once there's actually content to show (in _open()). So even if the 18661 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in 18662 // the period between open() and _open(). 18663 target.removeData( "ui-tooltip-open" ); 18664 return; 18665 } 18666 18667 tooltip = tooltipData.tooltip; 18668 18669 // Disabling closes the tooltip, so we need to track when we're closing 18670 // to avoid an infinite loop in case the tooltip becomes disabled on close 18671 if ( tooltipData.closing ) { 18672 return; 18673 } 18674 18675 // Clear the interval for delayed tracking tooltips 18676 clearInterval( this.delayedShow ); 18677 18678 // Only set title if we had one before (see comment in _open()) 18679 // If the title attribute has changed since open(), don't restore 18680 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 18681 target.attr( "title", target.data( "ui-tooltip-title" ) ); 18682 } 18683 18684 this._removeDescribedBy( target ); 18685 18686 tooltipData.hiding = true; 18687 tooltip.stop( true ); 18688 this._hide( tooltip, this.options.hide, function() { 18689 that._removeTooltip( $( this ) ); 18690 } ); 18691 18692 target.removeData( "ui-tooltip-open" ); 18693 this._off( target, "mouseleave focusout keyup" ); 18694 18695 // Remove 'remove' binding only on delegated targets 18696 if ( target[ 0 ] !== this.element[ 0 ] ) { 18697 this._off( target, "remove" ); 18698 } 18699 this._off( this.document, "mousemove" ); 18700 18701 if ( event && event.type === "mouseleave" ) { 18702 $.each( this.parents, function( id, parent ) { 18703 $( parent.element ).attr( "title", parent.title ); 18704 delete that.parents[ id ]; 18705 } ); 18706 } 18707 18708 tooltipData.closing = true; 18709 this._trigger( "close", event, { tooltip: tooltip } ); 18710 if ( !tooltipData.hiding ) { 18711 tooltipData.closing = false; 18712 } 18713 }, 18714 18715 _tooltip: function( element ) { 18716 var tooltip = $( "<div>" ).attr( "role", "tooltip" ), 18717 content = $( "<div>" ).appendTo( tooltip ), 18718 id = tooltip.uniqueId().attr( "id" ); 18719 18720 this._addClass( content, "ui-tooltip-content" ); 18721 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); 18722 18723 tooltip.appendTo( this._appendTo( element ) ); 18724 18725 return this.tooltips[ id ] = { 18726 element: element, 18727 tooltip: tooltip 18728 }; 18729 }, 18730 18731 _find: function( target ) { 18732 var id = target.data( "ui-tooltip-id" ); 18733 return id ? this.tooltips[ id ] : null; 18734 }, 18735 18736 _removeTooltip: function( tooltip ) { 18737 18738 // Clear the interval for delayed tracking tooltips 18739 clearInterval( this.delayedShow ); 18740 18741 tooltip.remove(); 18742 delete this.tooltips[ tooltip.attr( "id" ) ]; 18743 }, 18744 18745 _appendTo: function( target ) { 18746 var element = target.closest( ".ui-front, dialog" ); 18747 18748 if ( !element.length ) { 18749 element = this.document[ 0 ].body; 18750 } 18751 18752 return element; 18753 }, 18754 18755 _destroy: function() { 18756 var that = this; 18757 18758 // Close open tooltips 18759 $.each( this.tooltips, function( id, tooltipData ) { 18760 18761 // Delegate to close method to handle common cleanup 18762 var event = $.Event( "blur" ), 18763 element = tooltipData.element; 18764 event.target = event.currentTarget = element[ 0 ]; 18765 that.close( event, true ); 18766 18767 // Remove immediately; destroying an open tooltip doesn't use the 18768 // hide animation 18769 $( "#" + id ).remove(); 18770 18771 // Restore the title 18772 if ( element.data( "ui-tooltip-title" ) ) { 18773 18774 // If the title attribute has changed since open(), don't restore 18775 if ( !element.attr( "title" ) ) { 18776 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18777 } 18778 element.removeData( "ui-tooltip-title" ); 18779 } 18780 } ); 18781 this.liveRegion.remove(); 18782 } 18783 } ); 18784 18785// DEPRECATED 18786// TODO: Switch return back to widget declaration at top of file when this is removed 18787 if ( $.uiBackCompat === true ) { 18788 18789 // Backcompat for tooltipClass option 18790 $.widget( "ui.tooltip", $.ui.tooltip, { 18791 options: { 18792 tooltipClass: null 18793 }, 18794 _tooltip: function() { 18795 var tooltipData = this._superApply( arguments ); 18796 if ( this.options.tooltipClass ) { 18797 tooltipData.tooltip.addClass( this.options.tooltipClass ); 18798 } 18799 return tooltipData; 18800 } 18801 } ); 18802 } 18803 18804 var widgetsTooltip = $.ui.tooltip; 18805 18806 18807 18808 18809} );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.