vendor: 575,188 bytes, lines 1-16243
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 23var 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 42var widgetUuid = 0; 43var widgetHasOwnProperty = Array.prototype.hasOwnProperty; 44var 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 768var 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() { 790var 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 800function 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 807function parseCss( element, property ) { 808 return parseInt( $.css( element, property ), 10 ) || 0; 809} 810 811function isWindow( obj ) { 812 return obj != null && obj === obj.window; 813} 814 815function 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 1265var 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 1283var 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 1307var 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 1331var 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 1479each( 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 1489jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), 1490 function( _i, name ) { 1491 class2type[ "[object " + name + "]" ] = name.toLowerCase(); 1492 } ); 1493 1494function 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 1504function 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 1525function 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 1565color.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} ); 1781color.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 1786function 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 1800spaces.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 1837spaces.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 1857each( 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 1940color.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 1968color.hook( stepHooks ); 1969 1970jQuery.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. 1984colors = 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 2029var 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 2042var 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 2067function camelCase( string ) { 2068 return string.replace( /-([\da-z])/gi, function( all, letter ) { 2069 return letter.toUpperCase(); 2070 } ); 2071} 2072 2073function 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 2089function 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 2238if ( $.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 2246if ( $.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: 2574function _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 2626function 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 2853function 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 2894var 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 2939var 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 2958var 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 3013var 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 3108var 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 3158var 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 3214var 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 3308var 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 3340var 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 3414var 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 3456var 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 3634var 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 3674var 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 3700var 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 3749var 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 3808var 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 3869var effect; 3870if ( $.uiBackCompat === true ) { 3871 effect = $.effects.define( "transfer", function( options, done ) { 3872 $( this ).transfer( options, done ); 3873 } ); 3874} 3875var 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 3938var 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 3956var 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 4021if ( !$.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. 4029if ( !$.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 4060var 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 4095var 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 4149var 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 4183var 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 4207var 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 4251var 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 4851var 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 6139var 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 6161var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g; 6162 6163var 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 6695var 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 6963if ( $.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 7120var 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 7145var datepicker_instActive; 7146 7147function 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 7177function 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 isHoliday: null, // true: add class for displaying holiday 7245 beforeShowDay: null, // Function that takes a date and returns an array with 7246 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 7247 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 7248 beforeShow: null, // Function that takes an input field and 7249 // returns a set of custom settings for the date picker 7250 onSelect: null, // Define a callback function when a date is selected 7251 onChangeMonthYear: null, // Define a callback function when the month or year is changed 7252 onClose: null, // Define a callback function when the datepicker is closed 7253 onUpdateDatepicker: null, // Define a callback function when the datepicker is updated 7254 numberOfMonths: 1, // Number of months to show at a time 7255 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 7256 stepMonths: 1, // Number of months to step back/forward 7257 stepBigMonths: 12, // Number of months to step back/forward for the big links 7258 altField: "", // Selector for an alternate field to store selected dates into 7259 altFormat: "", // The date format to use for the alternate field 7260 constrainInput: true, // The input is constrained by the current date format 7261 showButtonPanel: false, // True to show button panel, false to not show it 7262 autoSize: false, // True to size the input for the date format, false to leave as is 7263 disabled: false // The initial disabled state 7264 }; 7265 $.extend( this._defaults, this.regional[ "" ] ); 7266 this.regional.en = $.extend( true, {}, this.regional[ "" ] ); 7267 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 7268 this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ); 7269} 7270 7271$.extend( Datepicker.prototype, { 7272 7273 /* Class name added to elements to indicate already configured with a date picker. */ 7274 markerClassName: "hasDatepicker", 7275 7276 //Keep track of the maximum number of rows displayed (see #7043) 7277 maxRows: 4, 7278 7279 // TODO rename to "widget" when switching to widget factory 7280 _widgetDatepicker: function() { 7281 return this.dpDiv; 7282 }, 7283 7284 /* Override the default settings for all instances of the date picker. 7285 * @param settings object - the new settings to use as defaults (anonymous object) 7286 * @return the manager object 7287 */ 7288 setDefaults: function( settings ) { 7289 datepicker_extendRemove( this._defaults, settings || {} ); 7290 return this; 7291 }, 7292 7293 /* Attach the date picker to a jQuery selection. 7294 * @param target element - the target input field or division or span 7295 * @param settings object - the new settings to use for this date picker instance (anonymous) 7296 */ 7297 _attachDatepicker: function( target, settings ) { 7298 var nodeName, inline, inst; 7299 nodeName = target.nodeName.toLowerCase(); 7300 inline = ( nodeName === "div" || nodeName === "span" ); 7301 if ( !target.id ) { 7302 this.uuid += 1; 7303 target.id = "dp" + this.uuid; 7304 } 7305 inst = this._newInst( $( target ), inline ); 7306 inst.settings = $.extend( {}, settings || {} ); 7307 if ( nodeName === "input" ) { 7308 this._connectDatepicker( target, inst ); 7309 } else if ( inline ) { 7310 this._inlineDatepicker( target, inst ); 7311 } 7312 }, 7313 7314 /* Create a new instance object. */ 7315 _newInst: function( target, inline ) { 7316 var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars 7317 return { id: id, input: target, // associated target 7318 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 7319 drawMonth: 0, drawYear: 0, // month being drawn 7320 inline: inline, // is datepicker inline or not 7321 dpDiv: ( !inline ? this.dpDiv : // presentation div 7322 datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) }; 7323 }, 7324 7325 /* Attach the date picker to an input field. */ 7326 _connectDatepicker: function( target, inst ) { 7327 var input = $( target ); 7328 inst.append = $( [] ); 7329 inst.trigger = $( [] ); 7330 if ( input.hasClass( this.markerClassName ) ) { 7331 return; 7332 } 7333 this._attachments( input, inst ); 7334 input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ). 7335 on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp ); 7336 this._autoSize( inst ); 7337 $.data( target, "datepicker", inst ); 7338 7339 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 7340 if ( inst.settings.disabled ) { 7341 this._disableDatepicker( target ); 7342 } 7343 }, 7344 7345 /* Make attachments based on settings. */ 7346 _attachments: function( input, inst ) { 7347 var showOn, buttonText, buttonImage, 7348 appendText = this._get( inst, "appendText" ), 7349 isRTL = this._get( inst, "isRTL" ); 7350 7351 if ( inst.append ) { 7352 inst.append.remove(); 7353 } 7354 if ( appendText ) { 7355 inst.append = $( "<span>" ) 7356 .addClass( this._appendClass ) 7357 .text( appendText ); 7358 input[ isRTL ? "before" : "after" ]( inst.append ); 7359 } 7360 7361 input.off( "focus", this._showDatepicker ); 7362 7363 if ( inst.trigger ) { 7364 inst.trigger.remove(); 7365 } 7366 7367 showOn = this._get( inst, "showOn" ); 7368 if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field 7369 input.on( "focus", this._showDatepicker ); 7370 } 7371 if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked 7372 buttonText = this._get( inst, "buttonText" ); 7373 buttonImage = this._get( inst, "buttonImage" ); 7374 7375 if ( this._get( inst, "buttonImageOnly" ) ) { 7376 inst.trigger = $( "<img>" ) 7377 .addClass( this._triggerClass ) 7378 .attr( { 7379 src: buttonImage, 7380 alt: "ëê´ ì ì²ê¸°ê° ì í ë¬ë ¥", 7381 title: "ëê´ ì ì²ê¸°ê° ì í ë¬ë ¥" 7382 } ); 7383 } else { 7384 inst.trigger = $( "<button type='button'>" ) 7385 .addClass( this._triggerClass ); 7386 if ( buttonImage ) { 7387 inst.trigger.html( 7388 $( "<img>" ) 7389 .attr( { 7390 src: buttonImage, 7391 alt: "ëê´ ì ì²ê¸°ê° ì í ë¬ë ¥", 7392 title: "ëê´ ì ì²ê¸°ê° ì í ë¬ë ¥" 7393 } ) 7394 ); 7395 } else { 7396 inst.trigger.text( buttonText ); 7397 } 7398 } 7399 7400 input[ isRTL ? "before" : "after" ]( inst.trigger ); 7401 inst.trigger.on( "click", function() { 7402 if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) { 7403 $.datepicker._hideDatepicker(); 7404 } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) { 7405 $.datepicker._hideDatepicker(); 7406 $.datepicker._showDatepicker( input[ 0 ] ); 7407 } else { 7408 $.datepicker._showDatepicker( input[ 0 ] ); 7409 } 7410 return false; 7411 } ); 7412 } 7413 }, 7414 7415 /* Apply the maximum length for the date format. */ 7416 _autoSize: function( inst ) { 7417 if ( this._get( inst, "autoSize" ) && !inst.inline ) { 7418 var findMax, max, maxI, i, 7419 date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits 7420 dateFormat = this._get( inst, "dateFormat" ); 7421 7422 if ( dateFormat.match( /[DM]/ ) ) { 7423 findMax = function( names ) { 7424 max = 0; 7425 maxI = 0; 7426 for ( i = 0; i < names.length; i++ ) { 7427 if ( names[ i ].length > max ) { 7428 max = names[ i ].length; 7429 maxI = i; 7430 } 7431 } 7432 return maxI; 7433 }; 7434 date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ? 7435 "monthNames" : "monthNamesShort" ) ) ) ); 7436 date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ? 7437 "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() ); 7438 } 7439 inst.input.attr( "size", this._formatDate( inst, date ).length ); 7440 } 7441 }, 7442 7443 /* Attach an inline date picker to a div. */ 7444 _inlineDatepicker: function( target, inst ) { 7445 var divSpan = $( target ); 7446 if ( divSpan.hasClass( this.markerClassName ) ) { 7447 return; 7448 } 7449 divSpan.addClass( this.markerClassName ).append( inst.dpDiv ); 7450 $.data( target, "datepicker", inst ); 7451 this._setDate( inst, this._getDefaultDate( inst ), true ); 7452 this._updateDatepicker( inst ); 7453 this._updateAlternate( inst ); 7454 7455 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 7456 if ( inst.settings.disabled ) { 7457 this._disableDatepicker( target ); 7458 } 7459 7460 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 7461 // https://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 7462 inst.dpDiv.css( "display", "block" ); 7463 }, 7464 7465 /* Pop-up the date picker in a "dialog" box. 7466 * @param input element - ignored 7467 * @param date string or Date - the initial date to display 7468 * @param onSelect function - the function to call when a date is selected 7469 * @param settings object - update the dialog date picker instance's settings (anonymous object) 7470 * @param pos int[2] - coordinates for the dialog's position within the screen or 7471 * event - with x/y coordinates or 7472 * leave empty for default (screen centre) 7473 * @return the manager object 7474 */ 7475 _dialogDatepicker: function( input, date, onSelect, settings, pos ) { 7476 var id, browserWidth, browserHeight, scrollX, scrollY, 7477 inst = this._dialogInst; // internal instance 7478 7479 if ( !inst ) { 7480 this.uuid += 1; 7481 id = "dp" + this.uuid; 7482 this._dialogInput = $( "<input type='text' id='" + id + 7483 "' style='position: absolute; top: -100px; width: 0px;'/>" ); 7484 this._dialogInput.on( "keydown", this._doKeyDown ); 7485 $( "body" ).append( this._dialogInput ); 7486 inst = this._dialogInst = this._newInst( this._dialogInput, false ); 7487 inst.settings = {}; 7488 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7489 } 7490 datepicker_extendRemove( inst.settings, settings || {} ); 7491 date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date ); 7492 this._dialogInput.val( date ); 7493 7494 this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null ); 7495 if ( !this._pos ) { 7496 browserWidth = document.documentElement.clientWidth; 7497 browserHeight = document.documentElement.clientHeight; 7498 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 7499 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 7500 this._pos = // should use actual width/height below 7501 [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ]; 7502 } 7503 7504 // Move input on screen for focus, but hidden behind dialog 7505 this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" ); 7506 inst.settings.onSelect = onSelect; 7507 this._inDialog = true; 7508 this.dpDiv.addClass( this._dialogClass ); 7509 this._showDatepicker( this._dialogInput[ 0 ] ); 7510 if ( $.blockUI ) { 7511 $.blockUI( this.dpDiv ); 7512 } 7513 $.data( this._dialogInput[ 0 ], "datepicker", inst ); 7514 return this; 7515 }, 7516 7517 /* Detach a datepicker from its control. 7518 * @param target element - the target input field or division or span 7519 */ 7520 _destroyDatepicker: function( target ) { 7521 var nodeName, 7522 $target = $( target ), 7523 inst = $.data( target, "datepicker" ); 7524 7525 if ( !$target.hasClass( this.markerClassName ) ) { 7526 return; 7527 } 7528 7529 nodeName = target.nodeName.toLowerCase(); 7530 $.removeData( target, "datepicker" ); 7531 if ( nodeName === "input" ) { 7532 inst.append.remove(); 7533 inst.trigger.remove(); 7534 $target.removeClass( this.markerClassName ). 7535 off( "focus", this._showDatepicker ). 7536 off( "keydown", this._doKeyDown ). 7537 off( "keypress", this._doKeyPress ). 7538 off( "keyup", this._doKeyUp ); 7539 } else if ( nodeName === "div" || nodeName === "span" ) { 7540 $target.removeClass( this.markerClassName ).empty(); 7541 } 7542 7543 $.datepicker._hideDatepicker(); 7544 if ( datepicker_instActive === inst ) { 7545 datepicker_instActive = null; 7546 this._curInst = null; 7547 } 7548 }, 7549 7550 /* Enable the date picker to a jQuery selection. 7551 * @param target element - the target input field or division or span 7552 */ 7553 _enableDatepicker: function( target ) { 7554 var nodeName, inline, 7555 $target = $( target ), 7556 inst = $.data( target, "datepicker" ); 7557 7558 if ( !$target.hasClass( this.markerClassName ) ) { 7559 return; 7560 } 7561 7562 nodeName = target.nodeName.toLowerCase(); 7563 if ( nodeName === "input" ) { 7564 target.disabled = false; 7565 inst.trigger.filter( "button" ). 7566 each( function() { 7567 this.disabled = false; 7568 } ).end(). 7569 filter( "img" ).css( { opacity: "1.0", cursor: "" } ); 7570 } else if ( nodeName === "div" || nodeName === "span" ) { 7571 inline = $target.children( "." + this._inlineClass ); 7572 inline.children().removeClass( "ui-state-disabled" ); 7573 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7574 prop( "disabled", false ); 7575 } 7576 this._disabledInputs = $.map( this._disabledInputs, 7577 7578 // Delete entry 7579 function( value ) { 7580 return ( value === target ? null : value ); 7581 } ); 7582 }, 7583 7584 /* Disable the date picker to a jQuery selection. 7585 * @param target element - the target input field or division or span 7586 */ 7587 _disableDatepicker: function( target ) { 7588 var nodeName, inline, 7589 $target = $( target ), 7590 inst = $.data( target, "datepicker" ); 7591 7592 if ( !$target.hasClass( this.markerClassName ) ) { 7593 return; 7594 } 7595 7596 nodeName = target.nodeName.toLowerCase(); 7597 if ( nodeName === "input" ) { 7598 target.disabled = true; 7599 inst.trigger.filter( "button" ). 7600 each( function() { 7601 this.disabled = true; 7602 } ).end(). 7603 filter( "img" ).css( { opacity: "0.5", cursor: "default" } ); 7604 } else if ( nodeName === "div" || nodeName === "span" ) { 7605 inline = $target.children( "." + this._inlineClass ); 7606 inline.children().addClass( "ui-state-disabled" ); 7607 inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ). 7608 prop( "disabled", true ); 7609 } 7610 this._disabledInputs = $.map( this._disabledInputs, 7611 7612 // Delete entry 7613 function( value ) { 7614 return ( value === target ? null : value ); 7615 } ); 7616 this._disabledInputs[ this._disabledInputs.length ] = target; 7617 }, 7618 7619 /* Is the first field in a jQuery collection disabled as a datepicker? 7620 * @param target element - the target input field or division or span 7621 * @return boolean - true if disabled, false if enabled 7622 */ 7623 _isDisabledDatepicker: function( target ) { 7624 if ( !target ) { 7625 return false; 7626 } 7627 for ( var i = 0; i < this._disabledInputs.length; i++ ) { 7628 if ( this._disabledInputs[ i ] === target ) { 7629 return true; 7630 } 7631 } 7632 return false; 7633 }, 7634 7635 /* Retrieve the instance data for the target control. 7636 * @param target element - the target input field or division or span 7637 * @return object - the associated instance data 7638 * @throws error if a jQuery problem getting data 7639 */ 7640 _getInst: function( target ) { 7641 try { 7642 return $.data( target, "datepicker" ); 7643 } catch ( err ) { 7644 throw "Missing instance data for this datepicker"; 7645 } 7646 }, 7647 7648 /* Update or retrieve the settings for a date picker attached to an input field or division. 7649 * @param target element - the target input field or division or span 7650 * @param name object - the new settings to update or 7651 * string - the name of the setting to change or retrieve, 7652 * when retrieving also "all" for all instance settings or 7653 * "defaults" for all global defaults 7654 * @param value any - the new value for the setting 7655 * (omit if above is an object or to retrieve a value) 7656 */ 7657 _optionDatepicker: function( target, name, value ) { 7658 var settings, date, minDate, maxDate, 7659 inst = this._getInst( target ); 7660 7661 if ( arguments.length === 2 && typeof name === "string" ) { 7662 return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) : 7663 ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) : 7664 this._get( inst, name ) ) : null ) ); 7665 } 7666 7667 settings = name || {}; 7668 if ( typeof name === "string" ) { 7669 settings = {}; 7670 settings[ name ] = value; 7671 } 7672 7673 if ( inst ) { 7674 if ( this._curInst === inst ) { 7675 this._hideDatepicker(); 7676 } 7677 7678 date = this._getDateDatepicker( target, true ); 7679 minDate = this._getMinMaxDate( inst, "min" ); 7680 maxDate = this._getMinMaxDate( inst, "max" ); 7681 datepicker_extendRemove( inst.settings, settings ); 7682 7683 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 7684 if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) { 7685 inst.settings.minDate = this._formatDate( inst, minDate ); 7686 } 7687 if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) { 7688 inst.settings.maxDate = this._formatDate( inst, maxDate ); 7689 } 7690 if ( "disabled" in settings ) { 7691 if ( settings.disabled ) { 7692 this._disableDatepicker( target ); 7693 } else { 7694 this._enableDatepicker( target ); 7695 } 7696 } 7697 this._attachments( $( target ), inst ); 7698 this._autoSize( inst ); 7699 this._setDate( inst, date ); 7700 this._updateAlternate( inst ); 7701 this._updateDatepicker( inst ); 7702 } 7703 }, 7704 7705 // Change method deprecated 7706 _changeDatepicker: function( target, name, value ) { 7707 this._optionDatepicker( target, name, value ); 7708 }, 7709 7710 /* Redraw the date picker attached to an input field or division. 7711 * @param target element - the target input field or division or span 7712 */ 7713 _refreshDatepicker: function( target ) { 7714 var inst = this._getInst( target ); 7715 if ( inst ) { 7716 this._updateDatepicker( inst ); 7717 } 7718 }, 7719 7720 /* Set the dates for a jQuery selection. 7721 * @param target element - the target input field or division or span 7722 * @param date Date - the new date 7723 */ 7724 _setDateDatepicker: function( target, date ) { 7725 var inst = this._getInst( target ); 7726 if ( inst ) { 7727 this._setDate( inst, date ); 7728 this._updateDatepicker( inst ); 7729 this._updateAlternate( inst ); 7730 } 7731 }, 7732 7733 /* Get the date(s) for the first entry in a jQuery selection. 7734 * @param target element - the target input field or division or span 7735 * @param noDefault boolean - true if no default date is to be used 7736 * @return Date - the current date 7737 */ 7738 _getDateDatepicker: function( target, noDefault ) { 7739 var inst = this._getInst( target ); 7740 if ( inst && !inst.inline ) { 7741 this._setDateFromField( inst, noDefault ); 7742 } 7743 return ( inst ? this._getDate( inst ) : null ); 7744 }, 7745 7746 /* Handle keystrokes. */ 7747 _doKeyDown: function( event ) { 7748 var onSelect, dateStr, sel, 7749 inst = $.datepicker._getInst( event.target ), 7750 handled = true, 7751 isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" ); 7752 7753 inst._keyEvent = true; 7754 if ( $.datepicker._datepickerShowing ) { 7755 switch ( event.keyCode ) { 7756 case 9: $.datepicker._hideDatepicker(); 7757 handled = false; 7758 break; // hide on tab out 7759 case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." + 7760 $.datepicker._currentClass + ")", inst.dpDiv ); 7761 if ( sel[ 0 ] ) { 7762 $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] ); 7763 } 7764 7765 onSelect = $.datepicker._get( inst, "onSelect" ); 7766 if ( onSelect ) { 7767 dateStr = $.datepicker._formatDate( inst ); 7768 7769 // Trigger custom callback 7770 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); 7771 } else { 7772 $.datepicker._hideDatepicker(); 7773 } 7774 7775 return false; // don't submit the form 7776 case 27: $.datepicker._hideDatepicker(); 7777 break; // hide on escape 7778 case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7779 -$.datepicker._get( inst, "stepBigMonths" ) : 7780 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7781 break; // previous month/year on page up/+ ctrl 7782 case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7783 +$.datepicker._get( inst, "stepBigMonths" ) : 7784 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7785 break; // next month/year on page down/+ ctrl 7786 case 35: if ( event.ctrlKey || event.metaKey ) { 7787 $.datepicker._clearDate( event.target ); 7788 } 7789 handled = event.ctrlKey || event.metaKey; 7790 break; // clear on ctrl or command +end 7791 case 36: if ( event.ctrlKey || event.metaKey ) { 7792 $.datepicker._gotoToday( event.target ); 7793 } 7794 handled = event.ctrlKey || event.metaKey; 7795 break; // current on ctrl or command +home 7796 case 37: if ( event.ctrlKey || event.metaKey ) { 7797 $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" ); 7798 } 7799 handled = event.ctrlKey || event.metaKey; 7800 7801 // -1 day on ctrl or command +left 7802 if ( event.originalEvent.altKey ) { 7803 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7804 -$.datepicker._get( inst, "stepBigMonths" ) : 7805 -$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7806 } 7807 7808 // next month/year on alt +left on Mac 7809 break; 7810 case 38: if ( event.ctrlKey || event.metaKey ) { 7811 $.datepicker._adjustDate( event.target, -7, "D" ); 7812 } 7813 handled = event.ctrlKey || event.metaKey; 7814 break; // -1 week on ctrl or command +up 7815 case 39: if ( event.ctrlKey || event.metaKey ) { 7816 $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" ); 7817 } 7818 handled = event.ctrlKey || event.metaKey; 7819 7820 // +1 day on ctrl or command +right 7821 if ( event.originalEvent.altKey ) { 7822 $.datepicker._adjustDate( event.target, ( event.ctrlKey ? 7823 +$.datepicker._get( inst, "stepBigMonths" ) : 7824 +$.datepicker._get( inst, "stepMonths" ) ), "M" ); 7825 } 7826 7827 // next month/year on alt +right 7828 break; 7829 case 40: if ( event.ctrlKey || event.metaKey ) { 7830 $.datepicker._adjustDate( event.target, +7, "D" ); 7831 } 7832 handled = event.ctrlKey || event.metaKey; 7833 break; // +1 week on ctrl or command +down 7834 default: handled = false; 7835 } 7836 } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home 7837 $.datepicker._showDatepicker( this ); 7838 } else { 7839 handled = false; 7840 } 7841 7842 if ( handled ) { 7843 event.preventDefault(); 7844 event.stopPropagation(); 7845 } 7846 }, 7847 7848 /* Filter entered characters - based on date format. */ 7849 _doKeyPress: function( event ) { 7850 var chars, chr, 7851 inst = $.datepicker._getInst( event.target ); 7852 7853 if ( $.datepicker._get( inst, "constrainInput" ) ) { 7854 chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) ); 7855 chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode ); 7856 return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 ); 7857 } 7858 }, 7859 7860 /* Synchronise manual entry and field/alternate field. */ 7861 _doKeyUp: function( event ) { 7862 var date, 7863 inst = $.datepicker._getInst( event.target ); 7864 7865 if ( inst.input.val() !== inst.lastVal ) { 7866 try { 7867 date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 7868 ( inst.input ? inst.input.val() : null ), 7869 $.datepicker._getFormatConfig( inst ) ); 7870 7871 if ( date ) { // only if valid 7872 $.datepicker._setDateFromField( inst ); 7873 $.datepicker._updateAlternate( inst ); 7874 $.datepicker._updateDatepicker( inst ); 7875 } 7876 } catch ( err ) { 7877 } 7878 } 7879 return true; 7880 }, 7881 7882 /* Pop-up the date picker for a given input field. 7883 * If false returned from beforeShow event handler do not show. 7884 * @param input element - the input field attached to the date picker or 7885 * event - if triggered by focus 7886 */ 7887 _showDatepicker: function( input ) { 7888 input = input.target || input; 7889 if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger 7890 input = $( "input", input.parentNode )[ 0 ]; 7891 } 7892 7893 if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here 7894 return; 7895 } 7896 7897 var inst, beforeShow, beforeShowSettings, isFixed, 7898 offset, showAnim, duration; 7899 7900 inst = $.datepicker._getInst( input ); 7901 if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) { 7902 $.datepicker._curInst.dpDiv.stop( true, true ); 7903 if ( inst && $.datepicker._datepickerShowing ) { 7904 $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] ); 7905 } 7906 } 7907 7908 beforeShow = $.datepicker._get( inst, "beforeShow" ); 7909 beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {}; 7910 if ( beforeShowSettings === false ) { 7911 return; 7912 } 7913 datepicker_extendRemove( inst.settings, beforeShowSettings ); 7914 7915 inst.lastVal = null; 7916 $.datepicker._lastInput = input; 7917 $.datepicker._setDateFromField( inst ); 7918 7919 if ( $.datepicker._inDialog ) { // hide cursor 7920 input.value = ""; 7921 } 7922 if ( !$.datepicker._pos ) { // position below input 7923 $.datepicker._pos = $.datepicker._findPos( input ); 7924 $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height 7925 } 7926 7927 isFixed = false; 7928 $( input ).parents().each( function() { 7929 isFixed |= $( this ).css( "position" ) === "fixed"; 7930 return !isFixed; 7931 } ); 7932 7933 offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] }; 7934 $.datepicker._pos = null; 7935 7936 //to avoid flashes on Firefox 7937 inst.dpDiv.empty(); 7938 7939 // determine sizing offscreen 7940 inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } ); 7941 $.datepicker._updateDatepicker( inst ); 7942 7943 // fix width for dynamic number of date pickers 7944 // and adjust position before showing 7945 offset = $.datepicker._checkOffset( inst, offset, isFixed ); 7946 inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ? 7947 "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none", 7948 left: offset.left + "px", top: offset.top + "px" } ); 7949 7950 if ( !inst.inline ) { 7951 showAnim = $.datepicker._get( inst, "showAnim" ); 7952 duration = $.datepicker._get( inst, "duration" ); 7953 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 7954 $.datepicker._datepickerShowing = true; 7955 7956 if ( $.effects && $.effects.effect[ showAnim ] ) { 7957 inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration ); 7958 } else { 7959 inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null ); 7960 } 7961 7962 if ( $.datepicker._shouldFocusInput( inst ) ) { 7963 inst.input.trigger( "focus" ); 7964 } 7965 7966 $.datepicker._curInst = inst; 7967 } 7968 }, 7969 7970 /* Generate the date picker content. */ 7971 _updateDatepicker: function( inst ) { 7972 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 7973 datepicker_instActive = inst; // for delegate hover events 7974 inst.dpDiv.empty().append( this._generateHTML( inst ) ); 7975 this._attachHandlers( inst ); 7976 7977 var origyearshtml, 7978 numMonths = this._getNumberOfMonths( inst ), 7979 cols = numMonths[ 1 ], 7980 width = 17, 7981 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ), 7982 onUpdateDatepicker = $.datepicker._get( inst, "onUpdateDatepicker" ); 7983 7984 if ( activeCell.length > 0 ) { 7985 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 7986 } 7987 7988 inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" ); 7989 if ( cols > 1 ) { 7990 inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" ); 7991 } 7992 inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) + 7993 "Class" ]( "ui-datepicker-multi" ); 7994 inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) + 7995 "Class" ]( "ui-datepicker-rtl" ); 7996 7997 if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 7998 inst.input.trigger( "focus" ); 7999 } 8000 8001 // Deffered render of the years select (to avoid flashes on Firefox) 8002 if ( inst.yearshtml ) { 8003 origyearshtml = inst.yearshtml; 8004 setTimeout( function() { 8005 8006 //assure that inst.yearshtml didn't change. 8007 if ( origyearshtml === inst.yearshtml && inst.yearshtml ) { 8008 inst.dpDiv.find( "select.ui-datepicker-year" ).first().replaceWith( inst.yearshtml ); 8009 } 8010 origyearshtml = inst.yearshtml = null; 8011 }, 0 ); 8012 } 8013 8014 if ( onUpdateDatepicker ) { 8015 onUpdateDatepicker.apply( ( inst.input ? inst.input[ 0 ] : null ), [ inst ] ); 8016 } 8017 }, 8018 8019 _shouldFocusInput: function( inst ) { 8020 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ); 8021 }, 8022 8023 /* Check positioning to remain on screen. */ 8024 _checkOffset: function( inst, offset, isFixed ) { 8025 var dpWidth = inst.dpDiv.outerWidth(), 8026 dpHeight = inst.dpDiv.outerHeight(), 8027 inputWidth = inst.input ? inst.input.outerWidth() : 0, 8028 inputHeight = inst.input ? inst.input.outerHeight() : 0, 8029 viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ), 8030 viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() ); 8031 8032 offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 ); 8033 offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0; 8034 offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0; 8035 8036 // Now check if datepicker is showing outside window viewport - move to a better place if so. 8037 offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ? 8038 Math.abs( offset.left + dpWidth - viewWidth ) : 0 ); 8039 offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ? 8040 Math.abs( dpHeight + inputHeight ) : 0 ); 8041 8042 return offset; 8043 }, 8044 8045 /* Find an object's position on the screen. */ 8046 _findPos: function( obj ) { 8047 var position, 8048 inst = this._getInst( obj ), 8049 isRTL = this._get( inst, "isRTL" ); 8050 8051 while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.pseudos.hidden( obj ) ) ) { 8052 obj = obj[ isRTL ? "previousSibling" : "nextSibling" ]; 8053 } 8054 8055 position = $( obj ).offset(); 8056 return [ position.left, position.top ]; 8057 }, 8058 8059 /* Hide the date picker from view. 8060 * @param input element - the input field attached to the date picker 8061 */ 8062 _hideDatepicker: function( input ) { 8063 var showAnim, duration, postProcess, onClose, 8064 inst = this._curInst; 8065 8066 if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) { 8067 return; 8068 } 8069 8070 if ( this._datepickerShowing ) { 8071 showAnim = this._get( inst, "showAnim" ); 8072 duration = this._get( inst, "duration" ); 8073 postProcess = function() { 8074 $.datepicker._tidyDialog( inst ); 8075 }; 8076 8077 if ( $.effects && ( $.effects.effect[ showAnim ] ) ) { 8078 inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess ); 8079 } else { 8080 inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" : 8081 ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess ); 8082 } 8083 8084 if ( !showAnim ) { 8085 postProcess(); 8086 } 8087 this._datepickerShowing = false; 8088 8089 onClose = this._get( inst, "onClose" ); 8090 if ( onClose ) { 8091 onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] ); 8092 } 8093 8094 this._lastInput = null; 8095 if ( this._inDialog ) { 8096 this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } ); 8097 if ( $.blockUI ) { 8098 $.unblockUI(); 8099 $( "body" ).append( this.dpDiv ); 8100 } 8101 } 8102 this._inDialog = false; 8103 } 8104 }, 8105 8106 /* Tidy up after a dialog display. */ 8107 _tidyDialog: function( inst ) { 8108 inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" ); 8109 }, 8110 8111 /* Close date picker if clicked elsewhere. */ 8112 _checkExternalClick: function( event ) { 8113 if ( !$.datepicker._curInst ) { 8114 return; 8115 } 8116 8117 var $target = $( event.target ), 8118 inst = $.datepicker._getInst( $target[ 0 ] ); 8119 8120 if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId && 8121 $target.parents( "#" + $.datepicker._mainDivId ).length === 0 && 8122 !$target.hasClass( $.datepicker.markerClassName ) && 8123 !$target.closest( "." + $.datepicker._triggerClass ).length && 8124 $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) || 8125 ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) { 8126 $.datepicker._hideDatepicker(); 8127 } 8128 }, 8129 8130 /* Adjust one of the date sub-fields. */ 8131 _adjustDate: function( id, offset, period ) { 8132 var target = $( id ), 8133 inst = this._getInst( target[ 0 ] ); 8134 8135 if ( this._isDisabledDatepicker( target[ 0 ] ) ) { 8136 return; 8137 } 8138 this._adjustInstDate( inst, offset, period ); 8139 this._updateDatepicker( inst ); 8140 }, 8141 8142 /* Action for current link. */ 8143 _gotoToday: function( id ) { 8144 var date, 8145 target = $( id ), 8146 inst = this._getInst( target[ 0 ] ); 8147 8148 if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) { 8149 inst.selectedDay = inst.currentDay; 8150 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 8151 inst.drawYear = inst.selectedYear = inst.currentYear; 8152 } else { 8153 date = new Date(); 8154 inst.selectedDay = date.getDate(); 8155 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8156 inst.drawYear = inst.selectedYear = date.getFullYear(); 8157 } 8158 this._notifyChange( inst ); 8159 this._adjustDate( target ); 8160 }, 8161 8162 /* Action for selecting a new month/year. */ 8163 _selectMonthYear: function( id, select, period ) { 8164 var target = $( id ), 8165 inst = this._getInst( target[ 0 ] ); 8166 8167 inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] = 8168 inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] = 8169 parseInt( select.options[ select.selectedIndex ].value, 10 ); 8170 8171 this._notifyChange( inst ); 8172 this._adjustDate( target ); 8173 }, 8174 8175 /* Action for selecting a day. */ 8176 _selectDay: function( id, month, year, td ) { 8177 var inst, 8178 target = $( id ); 8179 8180 if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) { 8181 return; 8182 } 8183 8184 inst = this._getInst( target[ 0 ] ); 8185 inst.selectedDay = inst.currentDay = parseInt( $( "a", td ).attr( "data-date" ) ); 8186 inst.selectedMonth = inst.currentMonth = month; 8187 inst.selectedYear = inst.currentYear = year; 8188 this._selectDate( id, this._formatDate( inst, 8189 inst.currentDay, inst.currentMonth, inst.currentYear ) ); 8190 }, 8191 8192 /* Erase the input field and hide the date picker. */ 8193 _clearDate: function( id ) { 8194 var target = $( id ); 8195 this._selectDate( target, "" ); 8196 }, 8197 8198 /* Update the input field with the selected date. */ 8199 _selectDate: function( id, dateStr ) { 8200 var onSelect, 8201 target = $( id ), 8202 inst = this._getInst( target[ 0 ] ); 8203 8204 dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) ); 8205 if ( inst.input ) { 8206 inst.input.val( dateStr ); 8207 } 8208 this._updateAlternate( inst ); 8209 8210 onSelect = this._get( inst, "onSelect" ); 8211 if ( onSelect ) { 8212 onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback 8213 } else if ( inst.input ) { 8214 inst.input.trigger( "change" ); // fire the change event 8215 } 8216 8217 if ( inst.inline ) { 8218 this._updateDatepicker( inst ); 8219 } else { 8220 this._hideDatepicker(); 8221 this._lastInput = inst.input[ 0 ]; 8222 if ( typeof( inst.input[ 0 ] ) !== "object" ) { 8223 inst.input.trigger( "focus" ); // restore focus 8224 } 8225 this._lastInput = null; 8226 } 8227 }, 8228 8229 /* Update any alternate field to synchronise with the main field. */ 8230 _updateAlternate: function( inst ) { 8231 var altFormat, date, dateStr, 8232 altField = this._get( inst, "altField" ); 8233 8234 if ( altField ) { // update alternate field too 8235 altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" ); 8236 date = this._getDate( inst ); 8237 dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) ); 8238 $( document ).find( altField ).val( dateStr ); 8239 } 8240 }, 8241 8242 /* Set as beforeShowDay function to prevent selection of weekends. 8243 * @param date Date - the date to customise 8244 * @return [boolean, string] - is this date selectable?, what is its CSS class? 8245 */ 8246 noWeekends: function( date ) { 8247 var day = date.getDay(); 8248 return [ ( day > 0 && day < 6 ), "" ]; 8249 }, 8250 8251 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 8252 * @param date Date - the date to get the week for 8253 * @return number - the number of the week within the year that contains this date 8254 */ 8255 iso8601Week: function( date ) { 8256 var time, 8257 checkDate = new Date( date.getTime() ); 8258 8259 // Find Thursday of this week starting on Monday 8260 checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) ); 8261 8262 time = checkDate.getTime(); 8263 checkDate.setMonth( 0 ); // Compare with Jan 1 8264 checkDate.setDate( 1 ); 8265 return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1; 8266 }, 8267 8268 /* Parse a string value into a date object. 8269 * See formatDate below for the possible formats. 8270 * 8271 * @param format string - the expected format of the date 8272 * @param value string - the date in the above format 8273 * @param settings Object - attributes include: 8274 * shortYearCutoff number - the cutoff year for determining the century (optional) 8275 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8276 * dayNames string[7] - names of the days from Sunday (optional) 8277 * monthNamesShort string[12] - abbreviated names of the months (optional) 8278 * monthNames string[12] - names of the months (optional) 8279 * @return Date - the extracted date value or null if value is blank 8280 */ 8281 parseDate: function( format, value, settings ) { 8282 if ( format == null || value == null ) { 8283 throw "Invalid arguments"; 8284 } 8285 8286 value = ( typeof value === "object" ? value.toString() : value + "" ); 8287 if ( value === "" ) { 8288 return null; 8289 } 8290 8291 var iFormat, dim, extra, 8292 iValue = 0, 8293 shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff, 8294 shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 8295 new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ), 8296 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8297 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8298 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8299 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8300 year = -1, 8301 month = -1, 8302 day = -1, 8303 doy = -1, 8304 literal = false, 8305 date, 8306 8307 // Check whether a format character is doubled 8308 lookAhead = function( match ) { 8309 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8310 if ( matches ) { 8311 iFormat++; 8312 } 8313 return matches; 8314 }, 8315 8316 // Extract a number from the string value 8317 getNumber = function( match ) { 8318 var isDoubled = lookAhead( match ), 8319 size = ( match === "@" ? 14 : ( match === "!" ? 20 : 8320 ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ), 8321 minSize = ( match === "y" ? size : 1 ), 8322 digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ), 8323 num = value.substring( iValue ).match( digits ); 8324 if ( !num ) { 8325 throw "Missing number at position " + iValue; 8326 } 8327 iValue += num[ 0 ].length; 8328 return parseInt( num[ 0 ], 10 ); 8329 }, 8330 8331 // Extract a name from the string value and convert to an index 8332 getName = function( match, shortNames, longNames ) { 8333 var index = -1, 8334 names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) { 8335 return [ [ k, v ] ]; 8336 } ).sort( function( a, b ) { 8337 return -( a[ 1 ].length - b[ 1 ].length ); 8338 } ); 8339 8340 $.each( names, function( i, pair ) { 8341 var name = pair[ 1 ]; 8342 if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) { 8343 index = pair[ 0 ]; 8344 iValue += name.length; 8345 return false; 8346 } 8347 } ); 8348 if ( index !== -1 ) { 8349 return index + 1; 8350 } else { 8351 throw "Unknown name at position " + iValue; 8352 } 8353 }, 8354 8355 // Confirm that a literal character matches the string value 8356 checkLiteral = function() { 8357 if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) { 8358 throw "Unexpected literal at position " + iValue; 8359 } 8360 iValue++; 8361 }; 8362 8363 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8364 if ( literal ) { 8365 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8366 literal = false; 8367 } else { 8368 checkLiteral(); 8369 } 8370 } else { 8371 switch ( format.charAt( iFormat ) ) { 8372 case "d": 8373 day = getNumber( "d" ); 8374 break; 8375 case "D": 8376 getName( "D", dayNamesShort, dayNames ); 8377 break; 8378 case "o": 8379 doy = getNumber( "o" ); 8380 break; 8381 case "m": 8382 month = getNumber( "m" ); 8383 break; 8384 case "M": 8385 month = getName( "M", monthNamesShort, monthNames ); 8386 break; 8387 case "y": 8388 year = getNumber( "y" ); 8389 break; 8390 case "@": 8391 date = new Date( getNumber( "@" ) ); 8392 year = date.getFullYear(); 8393 month = date.getMonth() + 1; 8394 day = date.getDate(); 8395 break; 8396 case "!": 8397 date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 ); 8398 year = date.getFullYear(); 8399 month = date.getMonth() + 1; 8400 day = date.getDate(); 8401 break; 8402 case "'": 8403 if ( lookAhead( "'" ) ) { 8404 checkLiteral(); 8405 } else { 8406 literal = true; 8407 } 8408 break; 8409 default: 8410 checkLiteral(); 8411 } 8412 } 8413 } 8414 8415 if ( iValue < value.length ) { 8416 extra = value.substr( iValue ); 8417 if ( !/^\s+/.test( extra ) ) { 8418 throw "Extra/unparsed characters found in date: " + extra; 8419 } 8420 } 8421 8422 if ( year === -1 ) { 8423 year = new Date().getFullYear(); 8424 } else if ( year < 100 ) { 8425 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 8426 ( year <= shortYearCutoff ? 0 : -100 ); 8427 } 8428 8429 if ( doy > -1 ) { 8430 month = 1; 8431 day = doy; 8432 do { 8433 dim = this._getDaysInMonth( year, month - 1 ); 8434 if ( day <= dim ) { 8435 break; 8436 } 8437 month++; 8438 day -= dim; 8439 } while ( true ); 8440 } 8441 8442 date = this._daylightSavingAdjust( new Date( year, month - 1, day ) ); 8443 if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) { 8444 throw "Invalid date"; // E.g. 31/02/00 8445 } 8446 return date; 8447 }, 8448 8449 /* Standard date formats. */ 8450 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 8451 COOKIE: "D, dd M yy", 8452 ISO_8601: "yy-mm-dd", 8453 RFC_822: "D, d M y", 8454 RFC_850: "DD, dd-M-y", 8455 RFC_1036: "D, d M y", 8456 RFC_1123: "D, d M yy", 8457 RFC_2822: "D, d M yy", 8458 RSS: "D, d M y", // RFC 822 8459 TICKS: "!", 8460 TIMESTAMP: "@", 8461 W3C: "yy-mm-dd", // ISO 8601 8462 8463 _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) + 8464 Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ), 8465 8466 /* Format a date object into a string value. 8467 * The format can be combinations of the following: 8468 * d - day of month (no leading zero) 8469 * dd - day of month (two digit) 8470 * o - day of year (no leading zeros) 8471 * oo - day of year (three digit) 8472 * D - day name short 8473 * DD - day name long 8474 * m - month of year (no leading zero) 8475 * mm - month of year (two digit) 8476 * M - month name short 8477 * MM - month name long 8478 * y - year (two digit) 8479 * yy - year (four digit) 8480 * @ - Unix timestamp (ms since 01/01/1970) 8481 * ! - Windows ticks (100ns since 01/01/0001) 8482 * "..." - literal text 8483 * '' - single quote 8484 * 8485 * @param format string - the desired format of the date 8486 * @param date Date - the date value to format 8487 * @param settings Object - attributes include: 8488 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 8489 * dayNames string[7] - names of the days from Sunday (optional) 8490 * monthNamesShort string[12] - abbreviated names of the months (optional) 8491 * monthNames string[12] - names of the months (optional) 8492 * @return string - the date in the above format 8493 */ 8494 formatDate: function( format, date, settings ) { 8495 if ( !date ) { 8496 return ""; 8497 } 8498 8499 var iFormat, 8500 dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort, 8501 dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames, 8502 monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort, 8503 monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames, 8504 8505 // Check whether a format character is doubled 8506 lookAhead = function( match ) { 8507 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8508 if ( matches ) { 8509 iFormat++; 8510 } 8511 return matches; 8512 }, 8513 8514 // Format a number, with leading zero if necessary 8515 formatNumber = function( match, value, len ) { 8516 var num = "" + value; 8517 if ( lookAhead( match ) ) { 8518 while ( num.length < len ) { 8519 num = "0" + num; 8520 } 8521 } 8522 return num; 8523 }, 8524 8525 // Format a name, short or long as requested 8526 formatName = function( match, value, shortNames, longNames ) { 8527 return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] ); 8528 }, 8529 output = "", 8530 literal = false; 8531 8532 if ( date ) { 8533 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8534 if ( literal ) { 8535 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8536 literal = false; 8537 } else { 8538 output += format.charAt( iFormat ); 8539 } 8540 } else { 8541 switch ( format.charAt( iFormat ) ) { 8542 case "d": 8543 output += formatNumber( "d", date.getDate(), 2 ); 8544 break; 8545 case "D": 8546 output += formatName( "D", date.getDay(), dayNamesShort, dayNames ); 8547 break; 8548 case "o": 8549 output += formatNumber( "o", 8550 Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 ); 8551 break; 8552 case "m": 8553 output += formatNumber( "m", date.getMonth() + 1, 2 ); 8554 break; 8555 case "M": 8556 output += formatName( "M", date.getMonth(), monthNamesShort, monthNames ); 8557 break; 8558 case "y": 8559 output += ( lookAhead( "y" ) ? date.getFullYear() : 8560 ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 ); 8561 break; 8562 case "@": 8563 output += date.getTime(); 8564 break; 8565 case "!": 8566 output += date.getTime() * 10000 + this._ticksTo1970; 8567 break; 8568 case "'": 8569 if ( lookAhead( "'" ) ) { 8570 output += "'"; 8571 } else { 8572 literal = true; 8573 } 8574 break; 8575 default: 8576 output += format.charAt( iFormat ); 8577 } 8578 } 8579 } 8580 } 8581 return output; 8582 }, 8583 8584 /* Extract all possible characters from the date format. */ 8585 _possibleChars: function( format ) { 8586 var iFormat, 8587 chars = "", 8588 literal = false, 8589 8590 // Check whether a format character is doubled 8591 lookAhead = function( match ) { 8592 var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match ); 8593 if ( matches ) { 8594 iFormat++; 8595 } 8596 return matches; 8597 }; 8598 8599 for ( iFormat = 0; iFormat < format.length; iFormat++ ) { 8600 if ( literal ) { 8601 if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) { 8602 literal = false; 8603 } else { 8604 chars += format.charAt( iFormat ); 8605 } 8606 } else { 8607 switch ( format.charAt( iFormat ) ) { 8608 case "d": case "m": case "y": case "@": 8609 chars += "0123456789"; 8610 break; 8611 case "D": case "M": 8612 return null; // Accept anything 8613 case "'": 8614 if ( lookAhead( "'" ) ) { 8615 chars += "'"; 8616 } else { 8617 literal = true; 8618 } 8619 break; 8620 default: 8621 chars += format.charAt( iFormat ); 8622 } 8623 } 8624 } 8625 return chars; 8626 }, 8627 8628 /* Get a setting value, defaulting if necessary. */ 8629 _get: function( inst, name ) { 8630 return inst.settings[ name ] !== undefined ? 8631 inst.settings[ name ] : this._defaults[ name ]; 8632 }, 8633 8634 /* Parse existing date and initialise date picker. */ 8635 _setDateFromField: function( inst, noDefault ) { 8636 if ( inst.input.val() === inst.lastVal ) { 8637 return; 8638 } 8639 8640 var dateFormat = this._get( inst, "dateFormat" ), 8641 dates = inst.lastVal = inst.input ? inst.input.val() : null, 8642 defaultDate = this._getDefaultDate( inst ), 8643 date = defaultDate, 8644 settings = this._getFormatConfig( inst ); 8645 8646 try { 8647 date = this.parseDate( dateFormat, dates, settings ) || defaultDate; 8648 } catch ( event ) { 8649 dates = ( noDefault ? "" : dates ); 8650 } 8651 inst.selectedDay = date.getDate(); 8652 inst.drawMonth = inst.selectedMonth = date.getMonth(); 8653 inst.drawYear = inst.selectedYear = date.getFullYear(); 8654 inst.currentDay = ( dates ? date.getDate() : 0 ); 8655 inst.currentMonth = ( dates ? date.getMonth() : 0 ); 8656 inst.currentYear = ( dates ? date.getFullYear() : 0 ); 8657 this._adjustInstDate( inst ); 8658 }, 8659 8660 /* Retrieve the default date shown on opening. */ 8661 _getDefaultDate: function( inst ) { 8662 return this._restrictMinMax( inst, 8663 this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) ); 8664 }, 8665 8666 /* A date may be specified as an exact value or a relative one. */ 8667 _determineDate: function( inst, date, defaultDate ) { 8668 var offsetNumeric = function( offset ) { 8669 var date = new Date(); 8670 date.setDate( date.getDate() + offset ); 8671 return date; 8672 }, 8673 offsetString = function( offset ) { 8674 try { 8675 return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ), 8676 offset, $.datepicker._getFormatConfig( inst ) ); 8677 } catch ( e ) { 8678 8679 // Ignore 8680 } 8681 8682 var date = ( offset.toLowerCase().match( /^c/ ) ? 8683 $.datepicker._getDate( inst ) : null ) || new Date(), 8684 year = date.getFullYear(), 8685 month = date.getMonth(), 8686 day = date.getDate(), 8687 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 8688 matches = pattern.exec( offset ); 8689 8690 while ( matches ) { 8691 switch ( matches[ 2 ] || "d" ) { 8692 case "d" : case "D" : 8693 day += parseInt( matches[ 1 ], 10 ); break; 8694 case "w" : case "W" : 8695 day += parseInt( matches[ 1 ], 10 ) * 7; break; 8696 case "m" : case "M" : 8697 month += parseInt( matches[ 1 ], 10 ); 8698 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8699 break; 8700 case "y": case "Y" : 8701 year += parseInt( matches[ 1 ], 10 ); 8702 day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) ); 8703 break; 8704 } 8705 matches = pattern.exec( offset ); 8706 } 8707 return new Date( year, month, day ); 8708 }, 8709 newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) : 8710 ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) ); 8711 8712 newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate ); 8713 if ( newDate ) { 8714 newDate.setHours( 0 ); 8715 newDate.setMinutes( 0 ); 8716 newDate.setSeconds( 0 ); 8717 newDate.setMilliseconds( 0 ); 8718 } 8719 return this._daylightSavingAdjust( newDate ); 8720 }, 8721 8722 /* Handle switch to/from daylight saving. 8723 * Hours may be non-zero on daylight saving cut-over: 8724 * > 12 when midnight changeover, but then cannot generate 8725 * midnight datetime, so jump to 1AM, otherwise reset. 8726 * @param date (Date) the date to check 8727 * @return (Date) the corrected date 8728 */ 8729 _daylightSavingAdjust: function( date ) { 8730 if ( !date ) { 8731 return null; 8732 } 8733 date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 ); 8734 return date; 8735 }, 8736 8737 /* Set the date(s) directly. */ 8738 _setDate: function( inst, date, noChange ) { 8739 var clear = !date, 8740 origMonth = inst.selectedMonth, 8741 origYear = inst.selectedYear, 8742 newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) ); 8743 8744 inst.selectedDay = inst.currentDay = newDate.getDate(); 8745 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 8746 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 8747 if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) { 8748 this._notifyChange( inst ); 8749 } 8750 this._adjustInstDate( inst ); 8751 if ( inst.input ) { 8752 inst.input.val( clear ? "" : this._formatDate( inst ) ); 8753 } 8754 }, 8755 8756 /* Retrieve the date(s) directly. */ 8757 _getDate: function( inst ) { 8758 var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null : 8759 this._daylightSavingAdjust( new Date( 8760 inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 8761 return startDate; 8762 }, 8763 8764 /* Attach the onxxx handlers. These are declared statically so 8765 * they work with static code transformers like Caja. 8766 */ 8767 _attachHandlers: function( inst ) { 8768 var stepMonths = this._get( inst, "stepMonths" ), 8769 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 8770 inst.dpDiv.find( "[data-handler]" ).map( function() { 8771 var handler = { 8772 prev: function() { 8773 $.datepicker._adjustDate( id, -stepMonths, "M" ); 8774 }, 8775 next: function() { 8776 $.datepicker._adjustDate( id, +stepMonths, "M" ); 8777 }, 8778 hide: function() { 8779 $.datepicker._hideDatepicker(); 8780 }, 8781 today: function() { 8782 $.datepicker._gotoToday( id ); 8783 }, 8784 selectDay: function() { 8785 $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this ); 8786 return false; 8787 }, 8788 selectMonth: function() { 8789 $.datepicker._selectMonthYear( id, this, "M" ); 8790 return false; 8791 }, 8792 selectYear: function() { 8793 $.datepicker._selectMonthYear( id, this, "Y" ); 8794 return false; 8795 } 8796 }; 8797 $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] ); 8798 } ); 8799 }, 8800 8801 /* Generate the HTML for the current state of the date picker. */ 8802 _generateHTML: function( inst ) { 8803 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 8804 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 8805 monthNames, monthNamesShort, isHoliday, isHolidaySelectable, beforeShowDay, showOtherMonths, 8806 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 8807 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 8808 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 8809 tempDate = new Date(), 8810 today = this._daylightSavingAdjust( 8811 new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time 8812 isRTL = this._get( inst, "isRTL" ), 8813 showButtonPanel = this._get( inst, "showButtonPanel" ), 8814 hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ), 8815 navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ), 8816 numMonths = this._getNumberOfMonths( inst ), 8817 showCurrentAtPos = this._get( inst, "showCurrentAtPos" ), 8818 stepMonths = this._get( inst, "stepMonths" ), 8819 isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ), 8820 currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) : 8821 new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ), 8822 minDate = this._getMinMaxDate( inst, "min" ), 8823 maxDate = this._getMinMaxDate( inst, "max" ), 8824 drawMonth = inst.drawMonth - showCurrentAtPos, 8825 drawYear = inst.drawYear; 8826 8827 if ( drawMonth < 0 ) { 8828 drawMonth += 12; 8829 drawYear--; 8830 } 8831 if ( maxDate ) { 8832 maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(), 8833 maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) ); 8834 maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw ); 8835 while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) { 8836 drawMonth--; 8837 if ( drawMonth < 0 ) { 8838 drawMonth = 11; 8839 drawYear--; 8840 } 8841 } 8842 } 8843 inst.drawMonth = drawMonth; 8844 inst.drawYear = drawYear; 8845 8846 prevText = this._get( inst, "prevText" ); 8847 prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText, 8848 this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ), 8849 this._getFormatConfig( inst ) ) ); 8850 8851 if ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ) { 8852 prev = $( "<a>" ) 8853 .attr( { 8854 "href": "#none", 8855 "class": "ui-datepicker-prev ui-corner-all", 8856 "data-handler": "prev", 8857 "data-event": "click", 8858 title: prevText 8859 } ) 8860 .append( 8861 $( "<span>" ) 8862 .addClass( "ui-icon ui-icon-circle-triangle-" + 8863 ( isRTL ? "e" : "w" ) ) 8864 .text( prevText ) 8865 )[ 0 ].outerHTML; 8866 } else if ( hideIfNoPrevNext ) { 8867 prev = ""; 8868 } else { 8869 prev = $( "<a>" ) 8870 .attr( { 8871 "class": "ui-datepicker-prev ui-corner-all ui-state-disabled", 8872 title: prevText 8873 } ) 8874 .append( 8875 $( "<span>" ) 8876 .addClass( "ui-icon ui-icon-circle-triangle-" + 8877 ( isRTL ? "e" : "w" ) ) 8878 .text( prevText ) 8879 )[ 0 ].outerHTML; 8880 } 8881 8882 nextText = this._get( inst, "nextText" ); 8883 nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText, 8884 this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ), 8885 this._getFormatConfig( inst ) ) ); 8886 8887 if ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ) { 8888 next = $( "<a>" ) 8889 .attr( { 8890 "href": "#none", 8891 "class": "ui-datepicker-next ui-corner-all", 8892 "data-handler": "next", 8893 "data-event": "click", 8894 title: nextText 8895 } ) 8896 .append( 8897 $( "<span>" ) 8898 .addClass( "ui-icon ui-icon-circle-triangle-" + 8899 ( isRTL ? "w" : "e" ) ) 8900 .text( nextText ) 8901 )[ 0 ].outerHTML; 8902 } else if ( hideIfNoPrevNext ) { 8903 next = ""; 8904 } else { 8905 next = $( "<a>" ) 8906 .attr( { 8907 "class": "ui-datepicker-next ui-corner-all ui-state-disabled", 8908 title: nextText 8909 } ) 8910 .append( 8911 $( "<span>" ) 8912 .attr( "class", "ui-icon ui-icon-circle-triangle-" + 8913 ( isRTL ? "w" : "e" ) ) 8914 .text( nextText ) 8915 )[ 0 ].outerHTML; 8916 } 8917 8918 currentText = this._get( inst, "currentText" ); 8919 gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today ); 8920 currentText = ( !navigationAsDateFormat ? currentText : 8921 this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) ); 8922 8923 controls = ""; 8924 if ( !inst.inline ) { 8925 controls = $( "<button>" ) 8926 .attr( { 8927 type: "button", 8928 "class": "ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all", 8929 "data-handler": "hide", 8930 "data-event": "click" 8931 } ) 8932 .text( this._get( inst, "closeText" ) )[ 0 ].outerHTML; 8933 } 8934 8935 buttonPanel = ""; 8936 if ( showButtonPanel ) { 8937 buttonPanel = $( "<div class='ui-datepicker-buttonpane ui-widget-content'>" ) 8938 .append( isRTL ? controls : "" ) 8939 .append( this._isInRange( inst, gotoDate ) ? 8940 $( "<button>" ) 8941 .attr( { 8942 type: "button", 8943 "class": "ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all", 8944 "data-handler": "today", 8945 "data-event": "click" 8946 } ) 8947 .text( currentText ) : 8948 "" ) 8949 .append( isRTL ? "" : controls )[ 0 ].outerHTML; 8950 } 8951 8952 firstDay = parseInt( this._get( inst, "firstDay" ), 10 ); 8953 firstDay = ( isNaN( firstDay ) ? 0 : firstDay ); 8954 8955 showWeek = this._get( inst, "showWeek" ); 8956 dayNames = this._get( inst, "dayNames" ); 8957 dayNamesMin = this._get( inst, "dayNamesMin" ); 8958 monthNames = this._get( inst, "monthNames" ); 8959 monthNamesShort = this._get( inst, "monthNamesShort" ); 8960 isHoliday = this._get(inst, "isHoliday"); 8961 beforeShowDay = this._get( inst, "beforeShowDay" ); 8962 showOtherMonths = this._get( inst, "showOtherMonths" ); 8963 selectOtherMonths = this._get( inst, "selectOtherMonths" ); 8964 defaultDate = this._getDefaultDate( inst ); 8965 html = ""; 8966 8967 for ( row = 0; row < numMonths[ 0 ]; row++ ) { 8968 group = ""; 8969 this.maxRows = 4; 8970 for ( col = 0; col < numMonths[ 1 ]; col++ ) { 8971 selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) ); 8972 cornerClass = " ui-corner-all"; 8973 calender = ""; 8974 if ( isMultiMonth ) { 8975 calender += "<div class='ui-datepicker-group"; 8976 if ( numMonths[ 1 ] > 1 ) { 8977 switch ( col ) { 8978 case 0: calender += " ui-datepicker-group-first"; 8979 cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break; 8980 case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last"; 8981 cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break; 8982 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 8983 } 8984 } 8985 calender += "'>"; 8986 } 8987 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 8988 ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) + 8989 ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) + 8990 this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate, 8991 row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers 8992 "</div><table class='ui-datepicker-calendar' summay='ê´ëì¼ì ì í í ì ìë ë¬ë ¥ì ëë¤.'><caption class='hide'>ê´ëì¼ì í</caption><thead>" + 8993 "<tr>"; 8994 thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" ); 8995 for ( dow = 0; dow < 7; dow++ ) { // days of the week 8996 day = ( dow + firstDay ) % 7; 8997 thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" + 8998 "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>"; 8999 } 9000 calender += thead + "</tr></thead><tbody>"; 9001 daysInMonth = this._getDaysInMonth( drawYear, drawMonth ); 9002 if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) { 9003 inst.selectedDay = Math.min( inst.selectedDay, daysInMonth ); 9004 } 9005 leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7; 9006 curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate 9007 numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043) 9008 this.maxRows = numRows; 9009 printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) ); 9010 for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows 9011 calender += "<tr>"; 9012 tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 9013 this._get( inst, "calculateWeek" )( printDate ) + "</td>" ); 9014 for ( dow = 0; dow < 7; dow++ ) { // create date picker days 9015 daySettings = ( beforeShowDay ? 9016 beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] ); 9017 isHolidayValid = (isHoliday ? 9018 isHoliday.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); 9019 isHolidaySelectable = !isHolidayValid[0] ; 9020 9021 otherMonth = ( printDate.getMonth() !== drawMonth ); 9022 unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] || 9023 ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate ); 9024 tbody += "<td class='" + 9025 ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends 9026 ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months 9027 ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key 9028 ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ? 9029 9030 // or defaultDate is current printedDate and defaultDate is selectedDate 9031 " " + this._dayOverClass : "" ) + // highlight selected day 9032 ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days 9033 ( isHolidaySelectable ? " holiday ": " " ) + // add class for displaying holidays 9034 ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates 9035 ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day 9036 ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different) 9037 ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title 9038 ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions 9039 ( otherMonth && !showOtherMonths ? " " : // display for other months 9040 ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 9041 ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) + 9042 ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day 9043 ( printDate.getTime() === currentDate.getTime() ? "' title='ì íì¼" : "" ) + // introduce selected day 9044 ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months 9045 "' href='#' aria-current='" + ( printDate.getTime() === currentDate.getTime() ? "true" : "false" ) + // mark date as selected for screen reader 9046 "' data-date='" + printDate.getDate() + // store date as data 9047 "'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date 9048 printDate.setDate( printDate.getDate() + 1 ); 9049 printDate = this._daylightSavingAdjust( printDate ); 9050 } 9051 calender += tbody + "</tr>"; 9052 } 9053 drawMonth++; 9054 if ( drawMonth > 11 ) { 9055 drawMonth = 0; 9056 drawYear++; 9057 } 9058 calender += "</tbody></table>" + ( isMultiMonth ? "</div>" + 9059 ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" ); 9060 group += calender; 9061 } 9062 html += group; 9063 } 9064 html += buttonPanel; 9065 inst._keyEvent = false; 9066 return html; 9067 }, 9068 9069 /* Generate the month and year header. */ 9070 _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate, 9071 secondary, monthNames, monthNamesShort ) { 9072 9073 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 9074 changeMonth = this._get( inst, "changeMonth" ), 9075 changeYear = this._get( inst, "changeYear" ), 9076 showMonthAfterYear = this._get( inst, "showMonthAfterYear" ), 9077 selectMonthLabel = this._get( inst, "selectMonthLabel" ), 9078 selectYearLabel = this._get( inst, "selectYearLabel" ), 9079 html = "<div class='ui-datepicker-title'>", 9080 monthHtml = ""; 9081 9082 // Month selection 9083 if ( secondary || !changeMonth ) { 9084 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>"; 9085 } else { 9086 inMinYear = ( minDate && minDate.getFullYear() === drawYear ); 9087 inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear ); 9088 monthHtml += "<select class='ui-datepicker-month' aria-label='" + selectMonthLabel + "' data-handler='selectMonth' data-event='change'>"; 9089 for ( month = 0; month < 12; month++ ) { 9090 if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) { 9091 monthHtml += "<option value='" + month + "'" + 9092 ( month === drawMonth ? " selected='selected'" : "" ) + 9093 ">" + monthNamesShort[ month ] + "</option>"; 9094 } 9095 } 9096 monthHtml += "</select>"; 9097 } 9098 9099 if ( !showMonthAfterYear ) { 9100 html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" ); 9101 } 9102 9103 // Year selection 9104 if ( !inst.yearshtml ) { 9105 inst.yearshtml = ""; 9106 if ( secondary || !changeYear ) { 9107 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 9108 } else { 9109 9110 // determine range of years to display 9111 years = this._get( inst, "yearRange" ).split( ":" ); 9112 thisYear = new Date().getFullYear(); 9113 determineYear = function( value ) { 9114 var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) : 9115 ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) : 9116 parseInt( value, 10 ) ) ); 9117 return ( isNaN( year ) ? thisYear : year ); 9118 }; 9119 year = determineYear( years[ 0 ] ); 9120 endYear = Math.max( year, determineYear( years[ 1 ] || "" ) ); 9121 year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year ); 9122 endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear ); 9123 inst.yearshtml += "<select class='ui-datepicker-year' aria-label='" + selectYearLabel + "' data-handler='selectYear' data-event='change'>"; 9124 for ( ; year <= endYear; year++ ) { 9125 inst.yearshtml += "<option value='" + year + "'" + 9126 ( year === drawYear ? " selected='selected'" : "" ) + 9127 ">" + year + "</option>"; 9128 } 9129 inst.yearshtml += "</select>"; 9130 9131 html += inst.yearshtml; 9132 inst.yearshtml = null; 9133 } 9134 } 9135 9136 html += this._get( inst, "yearSuffix" ); 9137 if ( showMonthAfterYear ) { 9138 html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml; 9139 } 9140 html += "</div>"; // Close datepicker_header 9141 return html; 9142 }, 9143 9144 /* Adjust one of the date sub-fields. */ 9145 _adjustInstDate: function( inst, offset, period ) { 9146 var year = inst.selectedYear + ( period === "Y" ? offset : 0 ), 9147 month = inst.selectedMonth + ( period === "M" ? offset : 0 ), 9148 day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ), 9149 date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) ); 9150 9151 inst.selectedDay = date.getDate(); 9152 inst.drawMonth = inst.selectedMonth = date.getMonth(); 9153 inst.drawYear = inst.selectedYear = date.getFullYear(); 9154 if ( period === "M" || period === "Y" ) { 9155 this._notifyChange( inst ); 9156 } 9157 }, 9158 9159 /* Ensure a date is within any min/max bounds. */ 9160 _restrictMinMax: function( inst, date ) { 9161 var minDate = this._getMinMaxDate( inst, "min" ), 9162 maxDate = this._getMinMaxDate( inst, "max" ), 9163 newDate = ( minDate && date < minDate ? minDate : date ); 9164 return ( maxDate && newDate > maxDate ? maxDate : newDate ); 9165 }, 9166 9167 /* Notify change of month/year. */ 9168 _notifyChange: function( inst ) { 9169 var onChange = this._get( inst, "onChangeMonthYear" ); 9170 if ( onChange ) { 9171 onChange.apply( ( inst.input ? inst.input[ 0 ] : null ), 9172 [ inst.selectedYear, inst.selectedMonth + 1, inst ] ); 9173 } 9174 }, 9175 9176 /* Determine the number of months to show. */ 9177 _getNumberOfMonths: function( inst ) { 9178 var numMonths = this._get( inst, "numberOfMonths" ); 9179 return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) ); 9180 }, 9181 9182 /* Determine the current maximum date - ensure no time components are set. */ 9183 _getMinMaxDate: function( inst, minMax ) { 9184 return this._determineDate( inst, this._get( inst, minMax + "Date" ), null ); 9185 }, 9186 9187 /* Find the number of days in a given month. */ 9188 _getDaysInMonth: function( year, month ) { 9189 return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate(); 9190 }, 9191 9192 /* Find the day of the week of the first of a month. */ 9193 _getFirstDayOfMonth: function( year, month ) { 9194 return new Date( year, month, 1 ).getDay(); 9195 }, 9196 9197 /* Determines if we should allow a "next/prev" month display change. */ 9198 _canAdjustMonth: function( inst, offset, curYear, curMonth ) { 9199 var numMonths = this._getNumberOfMonths( inst ), 9200 date = this._daylightSavingAdjust( new Date( curYear, 9201 curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) ); 9202 9203 if ( offset < 0 ) { 9204 date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) ); 9205 } 9206 return this._isInRange( inst, date ); 9207 }, 9208 9209 /* Is the given date in the accepted range? */ 9210 _isInRange: function( inst, date ) { 9211 var yearSplit, currentYear, 9212 minDate = this._getMinMaxDate( inst, "min" ), 9213 maxDate = this._getMinMaxDate( inst, "max" ), 9214 minYear = null, 9215 maxYear = null, 9216 years = this._get( inst, "yearRange" ); 9217 if ( years ) { 9218 yearSplit = years.split( ":" ); 9219 currentYear = new Date().getFullYear(); 9220 minYear = parseInt( yearSplit[ 0 ], 10 ); 9221 maxYear = parseInt( yearSplit[ 1 ], 10 ); 9222 if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) { 9223 minYear += currentYear; 9224 } 9225 if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) { 9226 maxYear += currentYear; 9227 } 9228 } 9229 9230 return ( ( !minDate || date.getTime() >= minDate.getTime() ) && 9231 ( !maxDate || date.getTime() <= maxDate.getTime() ) && 9232 ( !minYear || date.getFullYear() >= minYear ) && 9233 ( !maxYear || date.getFullYear() <= maxYear ) ); 9234 }, 9235 9236 /* Provide the configuration settings for formatting/parsing. */ 9237 _getFormatConfig: function( inst ) { 9238 var shortYearCutoff = this._get( inst, "shortYearCutoff" ); 9239 shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff : 9240 new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) ); 9241 return { shortYearCutoff: shortYearCutoff, 9242 dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ), 9243 monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) }; 9244 }, 9245 9246 /* Format the given date for display. */ 9247 _formatDate: function( inst, day, month, year ) { 9248 if ( !day ) { 9249 inst.currentDay = inst.selectedDay; 9250 inst.currentMonth = inst.selectedMonth; 9251 inst.currentYear = inst.selectedYear; 9252 } 9253 var date = ( day ? ( typeof day === "object" ? day : 9254 this._daylightSavingAdjust( new Date( year, month, day ) ) ) : 9255 this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ); 9256 return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) ); 9257 } 9258} ); 9259 9260/* 9261 * Bind hover events for datepicker elements. 9262 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 9263 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 9264 */ 9265function datepicker_bindHover( dpDiv ) { 9266 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 9267 return dpDiv.on( "mouseout", selector, function() { 9268 $( this ).removeClass( "ui-state-hover" ); 9269 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9270 $( this ).removeClass( "ui-datepicker-prev-hover" ); 9271 } 9272 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9273 $( this ).removeClass( "ui-datepicker-next-hover" ); 9274 } 9275 } ) 9276 .on( "mouseover", selector, datepicker_handleMouseover ); 9277} 9278 9279function datepicker_handleMouseover() { 9280 if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) { 9281 $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" ); 9282 $( this ).addClass( "ui-state-hover" ); 9283 if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) { 9284 $( this ).addClass( "ui-datepicker-prev-hover" ); 9285 } 9286 if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) { 9287 $( this ).addClass( "ui-datepicker-next-hover" ); 9288 } 9289 } 9290} 9291 9292/* jQuery extend now ignores nulls! */ 9293function datepicker_extendRemove( target, props ) { 9294 $.extend( target, props ); 9295 for ( var name in props ) { 9296 if ( props[ name ] == null ) { 9297 target[ name ] = props[ name ]; 9298 } 9299 } 9300 return target; 9301} 9302 9303/* Invoke the datepicker functionality. 9304 @param options string - a command, optionally followed by additional parameters or 9305 Object - settings for attaching new datepicker functionality 9306 @return jQuery object */ 9307$.fn.datepicker = function( options ) { 9308 9309 /* Verify an empty collection wasn't passed - Fixes #6976 */ 9310 if ( !this.length ) { 9311 return this; 9312 } 9313 9314 /* Initialise the date picker. */ 9315 if ( !$.datepicker.initialized ) { 9316 $( document ).on( "mousedown", $.datepicker._checkExternalClick ); 9317 $.datepicker.initialized = true; 9318 } 9319 9320 /* Append datepicker main container to body if not exist. */ 9321 if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) { 9322 $( "body" ).append( $.datepicker.dpDiv ); 9323 } 9324 9325 var otherArgs = Array.prototype.slice.call( arguments, 1 ); 9326 if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) { 9327 return $.datepicker[ "_" + options + "Datepicker" ]. 9328 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9329 } 9330 if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) { 9331 return $.datepicker[ "_" + options + "Datepicker" ]. 9332 apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) ); 9333 } 9334 return this.each( function() { 9335 if ( typeof options === "string" ) { 9336 $.datepicker[ "_" + options + "Datepicker" ] 9337 .apply( $.datepicker, [ this ].concat( otherArgs ) ); 9338 } else { 9339 $.datepicker._attachDatepicker( this, options ); 9340 } 9341 } ); 9342}; 9343 9344$.datepicker = new Datepicker(); // singleton instance 9345$.datepicker.initialized = false; 9346$.datepicker.uuid = new Date().getTime(); 9347$.datepicker.version = "1.14.1"; 9348 9349var widgetsDatepicker = $.datepicker; 9350 9351 9352/*! 9353 * jQuery UI Mouse 1.14.1 9354 * https://jqueryui.com 9355 * 9356 * Copyright OpenJS Foundation and other contributors 9357 * Released under the MIT license. 9358 * https://jquery.org/license 9359 */ 9360 9361//>>label: Mouse 9362//>>group: Widgets 9363//>>description: Abstracts mouse-based interactions to assist in creating certain widgets. 9364//>>docs: https://api.jqueryui.com/mouse/ 9365 9366 9367var mouseHandled = false; 9368$( document ).on( "mouseup", function() { 9369 mouseHandled = false; 9370} ); 9371 9372var widgetsMouse = $.widget( "ui.mouse", { 9373 version: "1.14.1", 9374 options: { 9375 cancel: "input, textarea, button, select, option", 9376 distance: 1, 9377 delay: 0 9378 }, 9379 _mouseInit: function() { 9380 var that = this; 9381 9382 this.element 9383 .on( "mousedown." + this.widgetName, function( event ) { 9384 return that._mouseDown( event ); 9385 } ) 9386 .on( "click." + this.widgetName, function( event ) { 9387 if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { 9388 $.removeData( event.target, that.widgetName + ".preventClickEvent" ); 9389 event.stopImmediatePropagation(); 9390 return false; 9391 } 9392 } ); 9393 9394 this.started = false; 9395 }, 9396 9397 // TODO: make sure destroying one instance of mouse doesn't mess with 9398 // other instances of mouse 9399 _mouseDestroy: function() { 9400 this.element.off( "." + this.widgetName ); 9401 if ( this._mouseMoveDelegate ) { 9402 this.document 9403 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9404 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9405 } 9406 }, 9407 9408 _mouseDown: function( event ) { 9409 9410 // don't let more than one widget handle mouseStart 9411 if ( mouseHandled ) { 9412 return; 9413 } 9414 9415 this._mouseMoved = false; 9416 9417 // We may have missed mouseup (out of window) 9418 if ( this._mouseStarted ) { 9419 this._mouseUp( event ); 9420 } 9421 9422 this._mouseDownEvent = event; 9423 9424 var that = this, 9425 btnIsLeft = event.which === 1, 9426 elIsCancel = typeof this.options.cancel === "string" ? 9427 $( event.target ).closest( this.options.cancel ).length : 9428 false; 9429 if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) { 9430 return true; 9431 } 9432 9433 this.mouseDelayMet = !this.options.delay; 9434 if ( !this.mouseDelayMet ) { 9435 this._mouseDelayTimer = setTimeout( function() { 9436 that.mouseDelayMet = true; 9437 }, this.options.delay ); 9438 } 9439 9440 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9441 this._mouseStarted = ( this._mouseStart( event ) !== false ); 9442 if ( !this._mouseStarted ) { 9443 event.preventDefault(); 9444 return true; 9445 } 9446 } 9447 9448 // Click event may never have fired (Gecko & Opera) 9449 if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { 9450 $.removeData( event.target, this.widgetName + ".preventClickEvent" ); 9451 } 9452 9453 // These delegates are required to keep context 9454 this._mouseMoveDelegate = function( event ) { 9455 return that._mouseMove( event ); 9456 }; 9457 this._mouseUpDelegate = function( event ) { 9458 return that._mouseUp( event ); 9459 }; 9460 9461 this.document 9462 .on( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9463 .on( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9464 9465 event.preventDefault(); 9466 9467 mouseHandled = true; 9468 return true; 9469 }, 9470 9471 _mouseMove: function( event ) { 9472 9473 // Only check for mouseups outside the document if you've moved inside the document 9474 // at least once. 9475 if ( this._mouseMoved && !event.which ) { 9476 9477 // Support: Safari <=8 - 9 9478 // Safari sets which to 0 if you press any of the following keys 9479 // during a drag (#14461) 9480 if ( event.originalEvent.altKey || event.originalEvent.ctrlKey || 9481 event.originalEvent.metaKey || event.originalEvent.shiftKey ) { 9482 this.ignoreMissingWhich = true; 9483 } else if ( !this.ignoreMissingWhich ) { 9484 return this._mouseUp( event ); 9485 } 9486 } 9487 9488 if ( event.which || event.button ) { 9489 this._mouseMoved = true; 9490 } 9491 9492 if ( this._mouseStarted ) { 9493 this._mouseDrag( event ); 9494 return event.preventDefault(); 9495 } 9496 9497 if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) { 9498 this._mouseStarted = 9499 ( this._mouseStart( this._mouseDownEvent, event ) !== false ); 9500 if ( this._mouseStarted ) { 9501 this._mouseDrag( event ); 9502 } else { 9503 this._mouseUp( event ); 9504 } 9505 } 9506 9507 return !this._mouseStarted; 9508 }, 9509 9510 _mouseUp: function( event ) { 9511 this.document 9512 .off( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 9513 .off( "mouseup." + this.widgetName, this._mouseUpDelegate ); 9514 9515 if ( this._mouseStarted ) { 9516 this._mouseStarted = false; 9517 9518 if ( event.target === this._mouseDownEvent.target ) { 9519 $.data( event.target, this.widgetName + ".preventClickEvent", true ); 9520 } 9521 9522 this._mouseStop( event ); 9523 } 9524 9525 if ( this._mouseDelayTimer ) { 9526 clearTimeout( this._mouseDelayTimer ); 9527 delete this._mouseDelayTimer; 9528 } 9529 9530 this.ignoreMissingWhich = false; 9531 mouseHandled = false; 9532 event.preventDefault(); 9533 }, 9534 9535 _mouseDistanceMet: function( event ) { 9536 return ( Math.max( 9537 Math.abs( this._mouseDownEvent.pageX - event.pageX ), 9538 Math.abs( this._mouseDownEvent.pageY - event.pageY ) 9539 ) >= this.options.distance 9540 ); 9541 }, 9542 9543 _mouseDelayMet: function( /* event */ ) { 9544 return this.mouseDelayMet; 9545 }, 9546 9547 // These are placeholder methods, to be overriden by extending plugin 9548 _mouseStart: function( /* event */ ) {}, 9549 _mouseDrag: function( /* event */ ) {}, 9550 _mouseStop: function( /* event */ ) {}, 9551 _mouseCapture: function( /* event */ ) { 9552 return true; 9553 } 9554} ); 9555 9556 9557 9558// $.ui.plugin is deprecated. Use $.widget() extensions instead. 9559var plugin = $.ui.plugin = { 9560 add: function( module, option, set ) { 9561 var i, 9562 proto = $.ui[ module ].prototype; 9563 for ( i in set ) { 9564 proto.plugins[ i ] = proto.plugins[ i ] || []; 9565 proto.plugins[ i ].push( [ option, set[ i ] ] ); 9566 } 9567 }, 9568 call: function( instance, name, args, allowDisconnected ) { 9569 var i, 9570 set = instance.plugins[ name ]; 9571 9572 if ( !set ) { 9573 return; 9574 } 9575 9576 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || 9577 instance.element[ 0 ].parentNode.nodeType === 11 ) ) { 9578 return; 9579 } 9580 9581 for ( i = 0; i < set.length; i++ ) { 9582 if ( instance.options[ set[ i ][ 0 ] ] ) { 9583 set[ i ][ 1 ].apply( instance.element, args ); 9584 } 9585 } 9586 } 9587}; 9588 9589 9590/*! 9591 * jQuery UI Draggable 1.14.1 9592 * https://jqueryui.com 9593 * 9594 * Copyright OpenJS Foundation and other contributors 9595 * Released under the MIT license. 9596 * https://jquery.org/license 9597 */ 9598 9599//>>label: Draggable 9600//>>group: Interactions 9601//>>description: Enables dragging functionality for any element. 9602//>>docs: https://api.jqueryui.com/draggable/ 9603//>>demos: https://jqueryui.com/draggable/ 9604//>>css.structure: ../../themes/base/draggable.css 9605 9606 9607$.widget( "ui.draggable", $.ui.mouse, { 9608 version: "1.14.1", 9609 widgetEventPrefix: "drag", 9610 options: { 9611 addClasses: true, 9612 appendTo: "parent", 9613 axis: false, 9614 connectToSortable: false, 9615 containment: false, 9616 cursor: "auto", 9617 cursorAt: false, 9618 grid: false, 9619 handle: false, 9620 helper: "original", 9621 iframeFix: false, 9622 opacity: false, 9623 refreshPositions: false, 9624 revert: false, 9625 revertDuration: 500, 9626 scope: "default", 9627 scroll: true, 9628 scrollSensitivity: 20, 9629 scrollSpeed: 20, 9630 snap: false, 9631 snapMode: "both", 9632 snapTolerance: 20, 9633 stack: false, 9634 zIndex: false, 9635 9636 // Callbacks 9637 drag: null, 9638 start: null, 9639 stop: null 9640 }, 9641 _create: function() { 9642 9643 if ( this.options.helper === "original" ) { 9644 this._setPositionRelative(); 9645 } 9646 if ( this.options.addClasses ) { 9647 this._addClass( "ui-draggable" ); 9648 } 9649 this._setHandleClassName(); 9650 9651 this._mouseInit(); 9652 }, 9653 9654 _setOption: function( key, value ) { 9655 this._super( key, value ); 9656 if ( key === "handle" ) { 9657 this._removeHandleClassName(); 9658 this._setHandleClassName(); 9659 } 9660 }, 9661 9662 _destroy: function() { 9663 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { 9664 this.destroyOnClear = true; 9665 return; 9666 } 9667 this._removeHandleClassName(); 9668 this._mouseDestroy(); 9669 }, 9670 9671 _mouseCapture: function( event ) { 9672 var o = this.options; 9673 9674 // Among others, prevent a drag on a resizable-handle 9675 if ( this.helper || o.disabled || 9676 $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) { 9677 return false; 9678 } 9679 9680 //Quit if we're not on a valid handle 9681 this.handle = this._getHandle( event ); 9682 if ( !this.handle ) { 9683 return false; 9684 } 9685 9686 this._blurActiveElement( event ); 9687 9688 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); 9689 9690 return true; 9691 9692 }, 9693 9694 _blockFrames: function( selector ) { 9695 this.iframeBlocks = this.document.find( selector ).map( function() { 9696 var iframe = $( this ); 9697 9698 return $( "<div>" ) 9699 .css( "position", "absolute" ) 9700 .appendTo( iframe.parent() ) 9701 .outerWidth( iframe.outerWidth() ) 9702 .outerHeight( iframe.outerHeight() ) 9703 .offset( iframe.offset() )[ 0 ]; 9704 } ); 9705 }, 9706 9707 _unblockFrames: function() { 9708 if ( this.iframeBlocks ) { 9709 this.iframeBlocks.remove(); 9710 delete this.iframeBlocks; 9711 } 9712 }, 9713 9714 _blurActiveElement: function( event ) { 9715 var activeElement = this.document[ 0 ].activeElement, 9716 target = $( event.target ); 9717 9718 // Don't blur if the event occurred on an element that is within 9719 // the currently focused element 9720 // See #10527, #12472 9721 if ( target.closest( activeElement ).length ) { 9722 return; 9723 } 9724 9725 // Blur any element that currently has focus, see #4261 9726 $( activeElement ).trigger( "blur" ); 9727 }, 9728 9729 _mouseStart: function( event ) { 9730 9731 var o = this.options; 9732 9733 //Create and append the visible helper 9734 this.helper = this._createHelper( event ); 9735 9736 this._addClass( this.helper, "ui-draggable-dragging" ); 9737 9738 //Cache the helper size 9739 this._cacheHelperProportions(); 9740 9741 //If ddmanager is used for droppables, set the global draggable 9742 if ( $.ui.ddmanager ) { 9743 $.ui.ddmanager.current = this; 9744 } 9745 9746 /* 9747 * - Position generation - 9748 * This block generates everything position related - it's the core of draggables. 9749 */ 9750 9751 //Cache the margins of the original element 9752 this._cacheMargins(); 9753 9754 //Store the helper's css position 9755 this.cssPosition = this.helper.css( "position" ); 9756 this.scrollParent = this.helper.scrollParent( true ); 9757 this.offsetParent = this.helper.offsetParent(); 9758 this.hasFixedAncestor = this.helper.parents().filter( function() { 9759 return $( this ).css( "position" ) === "fixed"; 9760 } ).length > 0; 9761 9762 //The element's absolute position on the page minus margins 9763 this.positionAbs = this.element.offset(); 9764 this._refreshOffsets( event ); 9765 9766 //Generate the original position 9767 this.originalPosition = this.position = this._generatePosition( event, false ); 9768 this.originalPageX = event.pageX; 9769 this.originalPageY = event.pageY; 9770 9771 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 9772 if ( o.cursorAt ) { 9773 this._adjustOffsetFromHelper( o.cursorAt ); 9774 } 9775 9776 //Set a containment if given in the options 9777 this._setContainment(); 9778 9779 //Trigger event + callbacks 9780 if ( this._trigger( "start", event ) === false ) { 9781 this._clear(); 9782 return false; 9783 } 9784 9785 //Recache the helper size 9786 this._cacheHelperProportions(); 9787 9788 //Prepare the droppable offsets 9789 if ( $.ui.ddmanager && !o.dropBehaviour ) { 9790 $.ui.ddmanager.prepareOffsets( this, event ); 9791 } 9792 9793 // Execute the drag once - this causes the helper not to be visible before getting its 9794 // correct position 9795 this._mouseDrag( event, true ); 9796 9797 // If the ddmanager is used for droppables, inform the manager that dragging has started 9798 // (see #5003) 9799 if ( $.ui.ddmanager ) { 9800 $.ui.ddmanager.dragStart( this, event ); 9801 } 9802 9803 return true; 9804 }, 9805 9806 _refreshOffsets: function( event ) { 9807 this.offset = { 9808 top: this.positionAbs.top - this.margins.top, 9809 left: this.positionAbs.left - this.margins.left, 9810 scroll: false, 9811 parent: this._getParentOffset(), 9812 relative: this._getRelativeOffset() 9813 }; 9814 9815 this.offset.click = { 9816 left: event.pageX - this.offset.left, 9817 top: event.pageY - this.offset.top 9818 }; 9819 }, 9820 9821 _mouseDrag: function( event, noPropagation ) { 9822 9823 // reset any necessary cached properties (see #5009) 9824 if ( this.hasFixedAncestor ) { 9825 this.offset.parent = this._getParentOffset(); 9826 } 9827 9828 //Compute the helpers position 9829 this.position = this._generatePosition( event, true ); 9830 this.positionAbs = this._convertPositionTo( "absolute" ); 9831 9832 //Call plugins and callbacks and use the resulting position if something is returned 9833 if ( !noPropagation ) { 9834 var ui = this._uiHash(); 9835 if ( this._trigger( "drag", event, ui ) === false ) { 9836 this._mouseUp( new $.Event( "mouseup", event ) ); 9837 return false; 9838 } 9839 this.position = ui.position; 9840 } 9841 9842 this.helper[ 0 ].style.left = this.position.left + "px"; 9843 this.helper[ 0 ].style.top = this.position.top + "px"; 9844 9845 if ( $.ui.ddmanager ) { 9846 $.ui.ddmanager.drag( this, event ); 9847 } 9848 9849 return false; 9850 }, 9851 9852 _mouseStop: function( event ) { 9853 9854 //If we are using droppables, inform the manager about the drop 9855 var that = this, 9856 dropped = false; 9857 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 9858 dropped = $.ui.ddmanager.drop( this, event ); 9859 } 9860 9861 //if a drop comes from outside (a sortable) 9862 if ( this.dropped ) { 9863 dropped = this.dropped; 9864 this.dropped = false; 9865 } 9866 9867 if ( ( this.options.revert === "invalid" && !dropped ) || 9868 ( this.options.revert === "valid" && dropped ) || 9869 this.options.revert === true || ( typeof this.options.revert === "function" && 9870 this.options.revert.call( this.element, dropped ) ) 9871 ) { 9872 $( this.helper ).animate( 9873 this.originalPosition, 9874 parseInt( this.options.revertDuration, 10 ), 9875 function() { 9876 if ( that._trigger( "stop", event ) !== false ) { 9877 that._clear(); 9878 } 9879 } 9880 ); 9881 } else { 9882 if ( this._trigger( "stop", event ) !== false ) { 9883 this._clear(); 9884 } 9885 } 9886 9887 return false; 9888 }, 9889 9890 _mouseUp: function( event ) { 9891 this._unblockFrames(); 9892 9893 // If the ddmanager is used for droppables, inform the manager that dragging has stopped 9894 // (see #5003) 9895 if ( $.ui.ddmanager ) { 9896 $.ui.ddmanager.dragStop( this, event ); 9897 } 9898 9899 // Only need to focus if the event occurred on the draggable itself, see #10527 9900 if ( this.handleElement.is( event.target ) ) { 9901 9902 // The interaction is over; whether or not the click resulted in a drag, 9903 // focus the element 9904 this.element.trigger( "focus" ); 9905 } 9906 9907 return $.ui.mouse.prototype._mouseUp.call( this, event ); 9908 }, 9909 9910 cancel: function() { 9911 9912 if ( this.helper.is( ".ui-draggable-dragging" ) ) { 9913 this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) ); 9914 } else { 9915 this._clear(); 9916 } 9917 9918 return this; 9919 9920 }, 9921 9922 _getHandle: function( event ) { 9923 return this.options.handle ? 9924 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : 9925 true; 9926 }, 9927 9928 _setHandleClassName: function() { 9929 this.handleElement = this.options.handle ? 9930 this.element.find( this.options.handle ) : this.element; 9931 this._addClass( this.handleElement, "ui-draggable-handle" ); 9932 }, 9933 9934 _removeHandleClassName: function() { 9935 this._removeClass( this.handleElement, "ui-draggable-handle" ); 9936 }, 9937 9938 _createHelper: function( event ) { 9939 9940 var o = this.options, 9941 helperIsFunction = typeof o.helper === "function", 9942 helper = helperIsFunction ? 9943 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : 9944 ( o.helper === "clone" ? 9945 this.element.clone().removeAttr( "id" ) : 9946 this.element ); 9947 9948 if ( !helper.parents( "body" ).length ) { 9949 helper.appendTo( ( o.appendTo === "parent" ? 9950 this.element[ 0 ].parentNode : 9951 o.appendTo ) ); 9952 } 9953 9954 // https://bugs.jqueryui.com/ticket/9446 9955 // a helper function can return the original element 9956 // which wouldn't have been set to relative in _create 9957 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { 9958 this._setPositionRelative(); 9959 } 9960 9961 if ( helper[ 0 ] !== this.element[ 0 ] && 9962 !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) { 9963 helper.css( "position", "absolute" ); 9964 } 9965 9966 return helper; 9967 9968 }, 9969 9970 _setPositionRelative: function() { 9971 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { 9972 this.element[ 0 ].style.position = "relative"; 9973 } 9974 }, 9975 9976 _adjustOffsetFromHelper: function( obj ) { 9977 if ( typeof obj === "string" ) { 9978 obj = obj.split( " " ); 9979 } 9980 if ( Array.isArray( obj ) ) { 9981 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 9982 } 9983 if ( "left" in obj ) { 9984 this.offset.click.left = obj.left + this.margins.left; 9985 } 9986 if ( "right" in obj ) { 9987 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 9988 } 9989 if ( "top" in obj ) { 9990 this.offset.click.top = obj.top + this.margins.top; 9991 } 9992 if ( "bottom" in obj ) { 9993 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 9994 } 9995 }, 9996 9997 _isRootNode: function( element ) { 9998 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; 9999 }, 10000 10001 _getParentOffset: function() { 10002 10003 //Get the offsetParent and cache its position 10004 var po = this.offsetParent.offset(), 10005 document = this.document[ 0 ]; 10006 10007 // This is a special case where we need to modify a offset calculated on start, since the 10008 // following happened: 10009 // 1. The position of the helper is absolute, so it's position is calculated based on the 10010 // next positioned parent 10011 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 10012 // the document, which means that the scroll is included in the initial calculation of the 10013 // offset of the parent, and never recalculated upon drag 10014 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document && 10015 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 10016 po.left += this.scrollParent.scrollLeft(); 10017 po.top += this.scrollParent.scrollTop(); 10018 } 10019 10020 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { 10021 po = { top: 0, left: 0 }; 10022 } 10023 10024 return { 10025 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 10026 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 10027 }; 10028 10029 }, 10030 10031 _getRelativeOffset: function() { 10032 if ( this.cssPosition !== "relative" ) { 10033 return { top: 0, left: 0 }; 10034 } 10035 10036 var p = this.element.position(), 10037 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 10038 10039 return { 10040 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 10041 ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), 10042 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 10043 ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) 10044 }; 10045 10046 }, 10047 10048 _cacheMargins: function() { 10049 this.margins = { 10050 left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ), 10051 top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ), 10052 right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ), 10053 bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 ) 10054 }; 10055 }, 10056 10057 _cacheHelperProportions: function() { 10058 this.helperProportions = { 10059 width: this.helper.outerWidth(), 10060 height: this.helper.outerHeight() 10061 }; 10062 }, 10063 10064 _setContainment: function() { 10065 10066 var isUserScrollable, c, ce, 10067 o = this.options, 10068 document = this.document[ 0 ]; 10069 10070 this.relativeContainer = null; 10071 10072 if ( !o.containment ) { 10073 this.containment = null; 10074 return; 10075 } 10076 10077 if ( o.containment === "window" ) { 10078 this.containment = [ 10079 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 10080 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, 10081 $( window ).scrollLeft() + $( window ).width() - 10082 this.helperProportions.width - this.margins.left, 10083 $( window ).scrollTop() + 10084 ( $( window ).height() || document.body.parentNode.scrollHeight ) - 10085 this.helperProportions.height - this.margins.top 10086 ]; 10087 return; 10088 } 10089 10090 if ( o.containment === "document" ) { 10091 this.containment = [ 10092 0, 10093 0, 10094 $( document ).width() - this.helperProportions.width - this.margins.left, 10095 ( $( document ).height() || document.body.parentNode.scrollHeight ) - 10096 this.helperProportions.height - this.margins.top 10097 ]; 10098 return; 10099 } 10100 10101 if ( o.containment.constructor === Array ) { 10102 this.containment = o.containment; 10103 return; 10104 } 10105 10106 if ( o.containment === "parent" ) { 10107 o.containment = this.helper[ 0 ].parentNode; 10108 } 10109 10110 c = $( o.containment ); 10111 ce = c[ 0 ]; 10112 10113 if ( !ce ) { 10114 return; 10115 } 10116 10117 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); 10118 10119 this.containment = [ 10120 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + 10121 ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), 10122 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + 10123 ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), 10124 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 10125 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - 10126 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - 10127 this.helperProportions.width - 10128 this.margins.left - 10129 this.margins.right, 10130 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 10131 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - 10132 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - 10133 this.helperProportions.height - 10134 this.margins.top - 10135 this.margins.bottom 10136 ]; 10137 this.relativeContainer = c; 10138 }, 10139 10140 _convertPositionTo: function( d, pos ) { 10141 10142 if ( !pos ) { 10143 pos = this.position; 10144 } 10145 10146 var mod = d === "absolute" ? 1 : -1, 10147 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 10148 10149 return { 10150 top: ( 10151 10152 // The absolute mouse position 10153 pos.top + 10154 10155 // Only for relative positioned nodes: Relative offset from element to offset parent 10156 this.offset.relative.top * mod + 10157 10158 // The offsetParent's offset without borders (offset + border) 10159 this.offset.parent.top * mod - 10160 ( ( this.cssPosition === "fixed" ? 10161 -this.offset.scroll.top : 10162 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod ) 10163 ), 10164 left: ( 10165 10166 // The absolute mouse position 10167 pos.left + 10168 10169 // Only for relative positioned nodes: Relative offset from element to offset parent 10170 this.offset.relative.left * mod + 10171 10172 // The offsetParent's offset without borders (offset + border) 10173 this.offset.parent.left * mod - 10174 ( ( this.cssPosition === "fixed" ? 10175 -this.offset.scroll.left : 10176 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod ) 10177 ) 10178 }; 10179 10180 }, 10181 10182 _generatePosition: function( event, constrainPosition ) { 10183 10184 var containment, co, top, left, 10185 o = this.options, 10186 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), 10187 pageX = event.pageX, 10188 pageY = event.pageY; 10189 10190 // Cache the scroll 10191 if ( !scrollIsRootNode || !this.offset.scroll ) { 10192 this.offset.scroll = { 10193 top: this.scrollParent.scrollTop(), 10194 left: this.scrollParent.scrollLeft() 10195 }; 10196 } 10197 10198 /* 10199 * - Position constraining - 10200 * Constrain the position to a mix of grid, containment. 10201 */ 10202 10203 // If we are not dragging yet, we won't check for options 10204 if ( constrainPosition ) { 10205 if ( this.containment ) { 10206 if ( this.relativeContainer ) { 10207 co = this.relativeContainer.offset(); 10208 containment = [ 10209 this.containment[ 0 ] + co.left, 10210 this.containment[ 1 ] + co.top, 10211 this.containment[ 2 ] + co.left, 10212 this.containment[ 3 ] + co.top 10213 ]; 10214 } else { 10215 containment = this.containment; 10216 } 10217 10218 if ( event.pageX - this.offset.click.left < containment[ 0 ] ) { 10219 pageX = containment[ 0 ] + this.offset.click.left; 10220 } 10221 if ( event.pageY - this.offset.click.top < containment[ 1 ] ) { 10222 pageY = containment[ 1 ] + this.offset.click.top; 10223 } 10224 if ( event.pageX - this.offset.click.left > containment[ 2 ] ) { 10225 pageX = containment[ 2 ] + this.offset.click.left; 10226 } 10227 if ( event.pageY - this.offset.click.top > containment[ 3 ] ) { 10228 pageY = containment[ 3 ] + this.offset.click.top; 10229 } 10230 } 10231 10232 if ( o.grid ) { 10233 10234 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid 10235 // argument errors in IE (see ticket #6950) 10236 top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY - 10237 this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY; 10238 pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] || 10239 top - this.offset.click.top > containment[ 3 ] ) ? 10240 top : 10241 ( ( top - this.offset.click.top >= containment[ 1 ] ) ? 10242 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top; 10243 10244 left = o.grid[ 0 ] ? this.originalPageX + 10245 Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] : 10246 this.originalPageX; 10247 pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] || 10248 left - this.offset.click.left > containment[ 2 ] ) ? 10249 left : 10250 ( ( left - this.offset.click.left >= containment[ 0 ] ) ? 10251 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left; 10252 } 10253 10254 if ( o.axis === "y" ) { 10255 pageX = this.originalPageX; 10256 } 10257 10258 if ( o.axis === "x" ) { 10259 pageY = this.originalPageY; 10260 } 10261 } 10262 10263 return { 10264 top: ( 10265 10266 // The absolute mouse position 10267 pageY - 10268 10269 // Click offset (relative to the element) 10270 this.offset.click.top - 10271 10272 // Only for relative positioned nodes: Relative offset from element to offset parent 10273 this.offset.relative.top - 10274 10275 // The offsetParent's offset without borders (offset + border) 10276 this.offset.parent.top + 10277 ( this.cssPosition === "fixed" ? 10278 -this.offset.scroll.top : 10279 ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) 10280 ), 10281 left: ( 10282 10283 // The absolute mouse position 10284 pageX - 10285 10286 // Click offset (relative to the element) 10287 this.offset.click.left - 10288 10289 // Only for relative positioned nodes: Relative offset from element to offset parent 10290 this.offset.relative.left - 10291 10292 // The offsetParent's offset without borders (offset + border) 10293 this.offset.parent.left + 10294 ( this.cssPosition === "fixed" ? 10295 -this.offset.scroll.left : 10296 ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) 10297 ) 10298 }; 10299 10300 }, 10301 10302 _clear: function() { 10303 this._removeClass( this.helper, "ui-draggable-dragging" ); 10304 if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) { 10305 this.helper.remove(); 10306 } 10307 this.helper = null; 10308 this.cancelHelperRemoval = false; 10309 if ( this.destroyOnClear ) { 10310 this.destroy(); 10311 } 10312 }, 10313 10314 // From now on bulk stuff - mainly helpers 10315 10316 _trigger: function( type, event, ui ) { 10317 ui = ui || this._uiHash(); 10318 $.ui.plugin.call( this, type, [ event, ui, this ], true ); 10319 10320 // Absolute position and offset (see #6884 ) have to be recalculated after plugins 10321 if ( /^(drag|start|stop)/.test( type ) ) { 10322 this.positionAbs = this._convertPositionTo( "absolute" ); 10323 ui.offset = this.positionAbs; 10324 } 10325 return $.Widget.prototype._trigger.call( this, type, event, ui ); 10326 }, 10327 10328 plugins: {}, 10329 10330 _uiHash: function() { 10331 return { 10332 helper: this.helper, 10333 position: this.position, 10334 originalPosition: this.originalPosition, 10335 offset: this.positionAbs 10336 }; 10337 } 10338 10339} ); 10340 10341$.ui.plugin.add( "draggable", "connectToSortable", { 10342 start: function( event, ui, draggable ) { 10343 var uiSortable = $.extend( {}, ui, { 10344 item: draggable.element 10345 } ); 10346 10347 draggable.sortables = []; 10348 $( draggable.options.connectToSortable ).each( function() { 10349 var sortable = $( this ).sortable( "instance" ); 10350 10351 if ( sortable && !sortable.options.disabled ) { 10352 draggable.sortables.push( sortable ); 10353 10354 // RefreshPositions is called at drag start to refresh the containerCache 10355 // which is used in drag. This ensures it's initialized and synchronized 10356 // with any changes that might have happened on the page since initialization. 10357 sortable.refreshPositions(); 10358 sortable._trigger( "activate", event, uiSortable ); 10359 } 10360 } ); 10361 }, 10362 stop: function( event, ui, draggable ) { 10363 var uiSortable = $.extend( {}, ui, { 10364 item: draggable.element 10365 } ); 10366 10367 draggable.cancelHelperRemoval = false; 10368 10369 $.each( draggable.sortables, function() { 10370 var sortable = this; 10371 10372 if ( sortable.isOver ) { 10373 sortable.isOver = 0; 10374 10375 // Allow this sortable to handle removing the helper 10376 draggable.cancelHelperRemoval = true; 10377 sortable.cancelHelperRemoval = false; 10378 10379 // Use _storedCSS To restore properties in the sortable, 10380 // as this also handles revert (#9675) since the draggable 10381 // may have modified them in unexpected ways (#8809) 10382 sortable._storedCSS = { 10383 position: sortable.placeholder.css( "position" ), 10384 top: sortable.placeholder.css( "top" ), 10385 left: sortable.placeholder.css( "left" ) 10386 }; 10387 10388 sortable._mouseStop( event ); 10389 10390 // Once drag has ended, the sortable should return to using 10391 // its original helper, not the shared helper from draggable 10392 sortable.options.helper = sortable.options._helper; 10393 } else { 10394 10395 // Prevent this Sortable from removing the helper. 10396 // However, don't set the draggable to remove the helper 10397 // either as another connected Sortable may yet handle the removal. 10398 sortable.cancelHelperRemoval = true; 10399 10400 sortable._trigger( "deactivate", event, uiSortable ); 10401 } 10402 } ); 10403 }, 10404 drag: function( event, ui, draggable ) { 10405 $.each( draggable.sortables, function() { 10406 var innermostIntersecting = false, 10407 sortable = this; 10408 10409 // Copy over variables that sortable's _intersectsWith uses 10410 sortable.positionAbs = draggable.positionAbs; 10411 sortable.helperProportions = draggable.helperProportions; 10412 sortable.offset.click = draggable.offset.click; 10413 10414 if ( sortable._intersectsWith( sortable.containerCache ) ) { 10415 innermostIntersecting = true; 10416 10417 $.each( draggable.sortables, function() { 10418 10419 // Copy over variables that sortable's _intersectsWith uses 10420 this.positionAbs = draggable.positionAbs; 10421 this.helperProportions = draggable.helperProportions; 10422 this.offset.click = draggable.offset.click; 10423 10424 if ( this !== sortable && 10425 this._intersectsWith( this.containerCache ) && 10426 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { 10427 innermostIntersecting = false; 10428 } 10429 10430 return innermostIntersecting; 10431 } ); 10432 } 10433 10434 if ( innermostIntersecting ) { 10435 10436 // If it intersects, we use a little isOver variable and set it once, 10437 // so that the move-in stuff gets fired only once. 10438 if ( !sortable.isOver ) { 10439 sortable.isOver = 1; 10440 10441 // Store draggable's parent in case we need to reappend to it later. 10442 draggable._parent = ui.helper.parent(); 10443 10444 sortable.currentItem = ui.helper 10445 .appendTo( sortable.element ) 10446 .data( "ui-sortable-item", true ); 10447 10448 // Store helper option to later restore it 10449 sortable.options._helper = sortable.options.helper; 10450 10451 sortable.options.helper = function() { 10452 return ui.helper[ 0 ]; 10453 }; 10454 10455 // Fire the start events of the sortable with our passed browser event, 10456 // and our own helper (so it doesn't create a new one) 10457 event.target = sortable.currentItem[ 0 ]; 10458 sortable._mouseCapture( event, true ); 10459 sortable._mouseStart( event, true, true ); 10460 10461 // Because the browser event is way off the new appended portlet, 10462 // modify necessary variables to reflect the changes 10463 sortable.offset.click.top = draggable.offset.click.top; 10464 sortable.offset.click.left = draggable.offset.click.left; 10465 sortable.offset.parent.left -= draggable.offset.parent.left - 10466 sortable.offset.parent.left; 10467 sortable.offset.parent.top -= draggable.offset.parent.top - 10468 sortable.offset.parent.top; 10469 10470 draggable._trigger( "toSortable", event ); 10471 10472 // Inform draggable that the helper is in a valid drop zone, 10473 // used solely in the revert option to handle "valid/invalid". 10474 draggable.dropped = sortable.element; 10475 10476 // Need to refreshPositions of all sortables in the case that 10477 // adding to one sortable changes the location of the other sortables (#9675) 10478 $.each( draggable.sortables, function() { 10479 this.refreshPositions(); 10480 } ); 10481 10482 // Hack so receive/update callbacks work (mostly) 10483 draggable.currentItem = draggable.element; 10484 sortable.fromOutside = draggable; 10485 } 10486 10487 if ( sortable.currentItem ) { 10488 sortable._mouseDrag( event ); 10489 10490 // Copy the sortable's position because the draggable's can potentially reflect 10491 // a relative position, while sortable is always absolute, which the dragged 10492 // element has now become. (#8809) 10493 ui.position = sortable.position; 10494 } 10495 } else { 10496 10497 // If it doesn't intersect with the sortable, and it intersected before, 10498 // we fake the drag stop of the sortable, but make sure it doesn't remove 10499 // the helper by using cancelHelperRemoval. 10500 if ( sortable.isOver ) { 10501 10502 sortable.isOver = 0; 10503 sortable.cancelHelperRemoval = true; 10504 10505 // Calling sortable's mouseStop would trigger a revert, 10506 // so revert must be temporarily false until after mouseStop is called. 10507 sortable.options._revert = sortable.options.revert; 10508 sortable.options.revert = false; 10509 10510 sortable._trigger( "out", event, sortable._uiHash( sortable ) ); 10511 sortable._mouseStop( event, true ); 10512 10513 // Restore sortable behaviors that were modfied 10514 // when the draggable entered the sortable area (#9481) 10515 sortable.options.revert = sortable.options._revert; 10516 sortable.options.helper = sortable.options._helper; 10517 10518 if ( sortable.placeholder ) { 10519 sortable.placeholder.remove(); 10520 } 10521 10522 // Restore and recalculate the draggable's offset considering the sortable 10523 // may have modified them in unexpected ways. (#8809, #10669) 10524 ui.helper.appendTo( draggable._parent ); 10525 draggable._refreshOffsets( event ); 10526 ui.position = draggable._generatePosition( event, true ); 10527 10528 draggable._trigger( "fromSortable", event ); 10529 10530 // Inform draggable that the helper is no longer in a valid drop zone 10531 draggable.dropped = false; 10532 10533 // Need to refreshPositions of all sortables just in case removing 10534 // from one sortable changes the location of other sortables (#9675) 10535 $.each( draggable.sortables, function() { 10536 this.refreshPositions(); 10537 } ); 10538 } 10539 } 10540 } ); 10541 } 10542} ); 10543 10544$.ui.plugin.add( "draggable", "cursor", { 10545 start: function( event, ui, instance ) { 10546 var t = $( "body" ), 10547 o = instance.options; 10548 10549 if ( t.css( "cursor" ) ) { 10550 o._cursor = t.css( "cursor" ); 10551 } 10552 t.css( "cursor", o.cursor ); 10553 }, 10554 stop: function( event, ui, instance ) { 10555 var o = instance.options; 10556 if ( o._cursor ) { 10557 $( "body" ).css( "cursor", o._cursor ); 10558 } 10559 } 10560} ); 10561 10562$.ui.plugin.add( "draggable", "opacity", { 10563 start: function( event, ui, instance ) { 10564 var t = $( ui.helper ), 10565 o = instance.options; 10566 if ( t.css( "opacity" ) ) { 10567 o._opacity = t.css( "opacity" ); 10568 } 10569 t.css( "opacity", o.opacity ); 10570 }, 10571 stop: function( event, ui, instance ) { 10572 var o = instance.options; 10573 if ( o._opacity ) { 10574 $( ui.helper ).css( "opacity", o._opacity ); 10575 } 10576 } 10577} ); 10578 10579$.ui.plugin.add( "draggable", "scroll", { 10580 start: function( event, ui, i ) { 10581 if ( !i.scrollParentNotHidden ) { 10582 i.scrollParentNotHidden = i.helper.scrollParent( false ); 10583 } 10584 10585 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && 10586 i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { 10587 i.overflowOffset = i.scrollParentNotHidden.offset(); 10588 } 10589 }, 10590 drag: function( event, ui, i ) { 10591 10592 var o = i.options, 10593 scrolled = false, 10594 scrollParent = i.scrollParentNotHidden[ 0 ], 10595 document = i.document[ 0 ]; 10596 10597 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { 10598 if ( !o.axis || o.axis !== "x" ) { 10599 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < 10600 o.scrollSensitivity ) { 10601 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; 10602 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { 10603 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; 10604 } 10605 } 10606 10607 if ( !o.axis || o.axis !== "y" ) { 10608 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < 10609 o.scrollSensitivity ) { 10610 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; 10611 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { 10612 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; 10613 } 10614 } 10615 10616 } else { 10617 10618 if ( !o.axis || o.axis !== "x" ) { 10619 if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) { 10620 scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed ); 10621 } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) < 10622 o.scrollSensitivity ) { 10623 scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed ); 10624 } 10625 } 10626 10627 if ( !o.axis || o.axis !== "y" ) { 10628 if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) { 10629 scrolled = $( document ).scrollLeft( 10630 $( document ).scrollLeft() - o.scrollSpeed 10631 ); 10632 } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) < 10633 o.scrollSensitivity ) { 10634 scrolled = $( document ).scrollLeft( 10635 $( document ).scrollLeft() + o.scrollSpeed 10636 ); 10637 } 10638 } 10639 10640 } 10641 10642 if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) { 10643 $.ui.ddmanager.prepareOffsets( i, event ); 10644 } 10645 10646 } 10647} ); 10648 10649$.ui.plugin.add( "draggable", "snap", { 10650 start: function( event, ui, i ) { 10651 10652 var o = i.options; 10653 10654 i.snapElements = []; 10655 10656 $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap ) 10657 .each( function() { 10658 var $t = $( this ), 10659 $o = $t.offset(); 10660 if ( this !== i.element[ 0 ] ) { 10661 i.snapElements.push( { 10662 item: this, 10663 width: $t.outerWidth(), height: $t.outerHeight(), 10664 top: $o.top, left: $o.left 10665 } ); 10666 } 10667 } ); 10668 10669 }, 10670 drag: function( event, ui, inst ) { 10671 10672 var ts, bs, ls, rs, l, r, t, b, i, first, 10673 o = inst.options, 10674 d = o.snapTolerance, 10675 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 10676 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 10677 10678 for ( i = inst.snapElements.length - 1; i >= 0; i-- ) { 10679 10680 l = inst.snapElements[ i ].left - inst.margins.left; 10681 r = l + inst.snapElements[ i ].width; 10682 t = inst.snapElements[ i ].top - inst.margins.top; 10683 b = t + inst.snapElements[ i ].height; 10684 10685 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || 10686 !$.contains( inst.snapElements[ i ].item.ownerDocument, 10687 inst.snapElements[ i ].item ) ) { 10688 if ( inst.snapElements[ i ].snapping ) { 10689 if ( inst.options.snap.release ) { 10690 inst.options.snap.release.call( 10691 inst.element, 10692 event, 10693 $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } ) 10694 ); 10695 } 10696 } 10697 inst.snapElements[ i ].snapping = false; 10698 continue; 10699 } 10700 10701 if ( o.snapMode !== "inner" ) { 10702 ts = Math.abs( t - y2 ) <= d; 10703 bs = Math.abs( b - y1 ) <= d; 10704 ls = Math.abs( l - x2 ) <= d; 10705 rs = Math.abs( r - x1 ) <= d; 10706 if ( ts ) { 10707 ui.position.top = inst._convertPositionTo( "relative", { 10708 top: t - inst.helperProportions.height, 10709 left: 0 10710 } ).top; 10711 } 10712 if ( bs ) { 10713 ui.position.top = inst._convertPositionTo( "relative", { 10714 top: b, 10715 left: 0 10716 } ).top; 10717 } 10718 if ( ls ) { 10719 ui.position.left = inst._convertPositionTo( "relative", { 10720 top: 0, 10721 left: l - inst.helperProportions.width 10722 } ).left; 10723 } 10724 if ( rs ) { 10725 ui.position.left = inst._convertPositionTo( "relative", { 10726 top: 0, 10727 left: r 10728 } ).left; 10729 } 10730 } 10731 10732 first = ( ts || bs || ls || rs ); 10733 10734 if ( o.snapMode !== "outer" ) { 10735 ts = Math.abs( t - y1 ) <= d; 10736 bs = Math.abs( b - y2 ) <= d; 10737 ls = Math.abs( l - x1 ) <= d; 10738 rs = Math.abs( r - x2 ) <= d; 10739 if ( ts ) { 10740 ui.position.top = inst._convertPositionTo( "relative", { 10741 top: t, 10742 left: 0 10743 } ).top; 10744 } 10745 if ( bs ) { 10746 ui.position.top = inst._convertPositionTo( "relative", { 10747 top: b - inst.helperProportions.height, 10748 left: 0 10749 } ).top; 10750 } 10751 if ( ls ) { 10752 ui.position.left = inst._convertPositionTo( "relative", { 10753 top: 0, 10754 left: l 10755 } ).left; 10756 } 10757 if ( rs ) { 10758 ui.position.left = inst._convertPositionTo( "relative", { 10759 top: 0, 10760 left: r - inst.helperProportions.width 10761 } ).left; 10762 } 10763 } 10764 10765 if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) { 10766 if ( inst.options.snap.snap ) { 10767 inst.options.snap.snap.call( 10768 inst.element, 10769 event, 10770 $.extend( inst._uiHash(), { 10771 snapItem: inst.snapElements[ i ].item 10772 } ) ); 10773 } 10774 } 10775 inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first ); 10776 10777 } 10778 10779 } 10780} ); 10781 10782$.ui.plugin.add( "draggable", "stack", { 10783 start: function( event, ui, instance ) { 10784 var min, 10785 o = instance.options, 10786 group = $.makeArray( $( o.stack ) ).sort( function( a, b ) { 10787 return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) - 10788 ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 ); 10789 } ); 10790 10791 if ( !group.length ) { 10792 return; 10793 } 10794 10795 min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0; 10796 $( group ).each( function( i ) { 10797 $( this ).css( "zIndex", min + i ); 10798 } ); 10799 this.css( "zIndex", ( min + group.length ) ); 10800 } 10801} ); 10802 10803$.ui.plugin.add( "draggable", "zIndex", { 10804 start: function( event, ui, instance ) { 10805 var t = $( ui.helper ), 10806 o = instance.options; 10807 10808 if ( t.css( "zIndex" ) ) { 10809 o._zIndex = t.css( "zIndex" ); 10810 } 10811 t.css( "zIndex", o.zIndex ); 10812 }, 10813 stop: function( event, ui, instance ) { 10814 var o = instance.options; 10815 10816 if ( o._zIndex ) { 10817 $( ui.helper ).css( "zIndex", o._zIndex ); 10818 } 10819 } 10820} ); 10821 10822var widgetsDraggable = $.ui.draggable; 10823 10824 10825/*! 10826 * jQuery UI Resizable 1.14.1 10827 * https://jqueryui.com 10828 * 10829 * Copyright OpenJS Foundation and other contributors 10830 * Released under the MIT license. 10831 * https://jquery.org/license 10832 */ 10833 10834//>>label: Resizable 10835//>>group: Interactions 10836//>>description: Enables resize functionality for any element. 10837//>>docs: https://api.jqueryui.com/resizable/ 10838//>>demos: https://jqueryui.com/resizable/ 10839//>>css.structure: ../../themes/base/core.css 10840//>>css.structure: ../../themes/base/resizable.css 10841//>>css.theme: ../../themes/base/theme.css 10842 10843 10844$.widget( "ui.resizable", $.ui.mouse, { 10845 version: "1.14.1", 10846 widgetEventPrefix: "resize", 10847 options: { 10848 alsoResize: false, 10849 animate: false, 10850 animateDuration: "slow", 10851 animateEasing: "swing", 10852 aspectRatio: false, 10853 autoHide: false, 10854 classes: { 10855 "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se" 10856 }, 10857 containment: false, 10858 ghost: false, 10859 grid: false, 10860 handles: "e,s,se", 10861 helper: false, 10862 maxHeight: null, 10863 maxWidth: null, 10864 minHeight: 10, 10865 minWidth: 10, 10866 10867 // See #7960 10868 zIndex: 90, 10869 10870 // Callbacks 10871 resize: null, 10872 start: null, 10873 stop: null 10874 }, 10875 10876 _num: function( value ) { 10877 return parseFloat( value ) || 0; 10878 }, 10879 10880 _isNumber: function( value ) { 10881 return !isNaN( parseFloat( value ) ); 10882 }, 10883 10884 _hasScroll: function( el, a ) { 10885 10886 var scroll, 10887 has = false, 10888 overflow = $( el ).css( "overflow" ); 10889 10890 if ( overflow === "hidden" ) { 10891 return false; 10892 } 10893 if ( overflow === "scroll" ) { 10894 return true; 10895 } 10896 10897 scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop"; 10898 10899 if ( el[ scroll ] > 0 ) { 10900 return true; 10901 } 10902 10903 // TODO: determine which cases actually cause this to happen 10904 // if the element doesn't have the scroll set, see if it's possible to 10905 // set the scroll 10906 try { 10907 el[ scroll ] = 1; 10908 has = ( el[ scroll ] > 0 ); 10909 el[ scroll ] = 0; 10910 } catch ( e ) { 10911 10912 // `el` might be a string, then setting `scroll` will throw 10913 // an error in strict mode; ignore it. 10914 } 10915 return has; 10916 }, 10917 10918 _create: function() { 10919 10920 var margins, 10921 o = this.options, 10922 that = this; 10923 this._addClass( "ui-resizable" ); 10924 10925 $.extend( this, { 10926 _aspectRatio: !!( o.aspectRatio ), 10927 aspectRatio: o.aspectRatio, 10928 originalElement: this.element, 10929 _proportionallyResizeElements: [], 10930 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null 10931 } ); 10932 10933 // Wrap the element if it cannot hold child nodes 10934 if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) { 10935 10936 this.element.wrap( 10937 $( "<div class='ui-wrapper'></div>" ).css( { 10938 overflow: "hidden", 10939 position: this.element.css( "position" ), 10940 width: this.element.outerWidth(), 10941 height: this.element.outerHeight(), 10942 top: this.element.css( "top" ), 10943 left: this.element.css( "left" ) 10944 } ) 10945 ); 10946 10947 this.element = this.element.parent().data( 10948 "ui-resizable", this.element.resizable( "instance" ) 10949 ); 10950 10951 this.elementIsWrapper = true; 10952 10953 margins = { 10954 marginTop: this.originalElement.css( "marginTop" ), 10955 marginRight: this.originalElement.css( "marginRight" ), 10956 marginBottom: this.originalElement.css( "marginBottom" ), 10957 marginLeft: this.originalElement.css( "marginLeft" ) 10958 }; 10959 10960 this.element.css( margins ); 10961 10962 // Support: Safari 10963 // Prevent Safari textarea resize 10964 this.originalResizeStyle = this.originalElement.css( "resize" ); 10965 this.originalElement.css( "resize", "none" ); 10966 10967 this._proportionallyResizeElements.push( this.originalElement.css( { 10968 position: "static", 10969 zoom: 1, 10970 display: "block" 10971 } ) ); 10972 10973 this._proportionallyResize(); 10974 } 10975 10976 this._setupHandles(); 10977 10978 if ( o.autoHide ) { 10979 $( this.element ) 10980 .on( "mouseenter", function() { 10981 if ( o.disabled ) { 10982 return; 10983 } 10984 that._removeClass( "ui-resizable-autohide" ); 10985 that._handles.show(); 10986 } ) 10987 .on( "mouseleave", function() { 10988 if ( o.disabled ) { 10989 return; 10990 } 10991 if ( !that.resizing ) { 10992 that._addClass( "ui-resizable-autohide" ); 10993 that._handles.hide(); 10994 } 10995 } ); 10996 } 10997 10998 this._mouseInit(); 10999 }, 11000 11001 _destroy: function() { 11002 11003 this._mouseDestroy(); 11004 this._addedHandles.remove(); 11005 11006 var wrapper, 11007 _destroy = function( exp ) { 11008 $( exp ) 11009 .removeData( "resizable" ) 11010 .removeData( "ui-resizable" ) 11011 .off( ".resizable" ); 11012 }; 11013 11014 // TODO: Unwrap at same DOM position 11015 if ( this.elementIsWrapper ) { 11016 _destroy( this.element ); 11017 wrapper = this.element; 11018 this.originalElement.css( { 11019 position: wrapper.css( "position" ), 11020 width: wrapper.outerWidth(), 11021 height: wrapper.outerHeight(), 11022 top: wrapper.css( "top" ), 11023 left: wrapper.css( "left" ) 11024 } ).insertAfter( wrapper ); 11025 wrapper.remove(); 11026 } 11027 11028 this.originalElement.css( "resize", this.originalResizeStyle ); 11029 _destroy( this.originalElement ); 11030 11031 return this; 11032 }, 11033 11034 _setOption: function( key, value ) { 11035 this._super( key, value ); 11036 11037 switch ( key ) { 11038 case "handles": 11039 this._removeHandles(); 11040 this._setupHandles(); 11041 break; 11042 case "aspectRatio": 11043 this._aspectRatio = !!value; 11044 break; 11045 default: 11046 break; 11047 } 11048 }, 11049 11050 _setupHandles: function() { 11051 var o = this.options, handle, i, n, hname, axis, that = this; 11052 this.handles = o.handles || 11053 ( !$( ".ui-resizable-handle", this.element ).length ? 11054 "e,s,se" : { 11055 n: ".ui-resizable-n", 11056 e: ".ui-resizable-e", 11057 s: ".ui-resizable-s", 11058 w: ".ui-resizable-w", 11059 se: ".ui-resizable-se", 11060 sw: ".ui-resizable-sw", 11061 ne: ".ui-resizable-ne", 11062 nw: ".ui-resizable-nw" 11063 } ); 11064 11065 this._handles = $(); 11066 this._addedHandles = $(); 11067 if ( this.handles.constructor === String ) { 11068 11069 if ( this.handles === "all" ) { 11070 this.handles = "n,e,s,w,se,sw,ne,nw"; 11071 } 11072 11073 n = this.handles.split( "," ); 11074 this.handles = {}; 11075 11076 for ( i = 0; i < n.length; i++ ) { 11077 11078 handle = String.prototype.trim.call( n[ i ] ); 11079 hname = "ui-resizable-" + handle; 11080 axis = $( "<div>" ); 11081 this._addClass( axis, "ui-resizable-handle " + hname ); 11082 11083 axis.css( { zIndex: o.zIndex } ); 11084 11085 this.handles[ handle ] = ".ui-resizable-" + handle; 11086 if ( !this.element.children( this.handles[ handle ] ).length ) { 11087 this.element.append( axis ); 11088 this._addedHandles = this._addedHandles.add( axis ); 11089 } 11090 } 11091 11092 } 11093 11094 this._renderAxis = function( target ) { 11095 11096 var i, axis, padPos, padWrapper; 11097 11098 target = target || this.element; 11099 11100 for ( i in this.handles ) { 11101 11102 if ( this.handles[ i ].constructor === String ) { 11103 this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show(); 11104 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { 11105 this.handles[ i ] = $( this.handles[ i ] ); 11106 this._on( this.handles[ i ], { "mousedown": that._mouseDown } ); 11107 } 11108 11109 if ( this.elementIsWrapper && 11110 this.originalElement[ 0 ] 11111 .nodeName 11112 .match( /^(textarea|input|select|button)$/i ) ) { 11113 axis = $( this.handles[ i ], this.element ); 11114 11115 padWrapper = /sw|ne|nw|se|n|s/.test( i ) ? 11116 axis.outerHeight() : 11117 axis.outerWidth(); 11118 11119 padPos = [ "padding", 11120 /ne|nw|n/.test( i ) ? "Top" : 11121 /se|sw|s/.test( i ) ? "Bottom" : 11122 /^e$/.test( i ) ? "Right" : "Left" ].join( "" ); 11123 11124 target.css( padPos, padWrapper ); 11125 11126 this._proportionallyResize(); 11127 } 11128 11129 this._handles = this._handles.add( this.handles[ i ] ); 11130 } 11131 }; 11132 11133 // TODO: make renderAxis a prototype function 11134 this._renderAxis( this.element ); 11135 11136 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); 11137 this._handles.disableSelection(); 11138 11139 this._handles.on( "mouseover", function() { 11140 if ( !that.resizing ) { 11141 if ( this.className ) { 11142 axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i ); 11143 } 11144 that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se"; 11145 } 11146 } ); 11147 11148 if ( o.autoHide ) { 11149 this._handles.hide(); 11150 this._addClass( "ui-resizable-autohide" ); 11151 } 11152 }, 11153 11154 _removeHandles: function() { 11155 this._addedHandles.remove(); 11156 }, 11157 11158 _mouseCapture: function( event ) { 11159 var i, handle, 11160 capture = false; 11161 11162 for ( i in this.handles ) { 11163 handle = $( this.handles[ i ] )[ 0 ]; 11164 if ( handle === event.target || $.contains( handle, event.target ) ) { 11165 capture = true; 11166 } 11167 } 11168 11169 return !this.options.disabled && capture; 11170 }, 11171 11172 _mouseStart: function( event ) { 11173 11174 var curleft, curtop, cursor, calculatedSize, 11175 o = this.options, 11176 el = this.element; 11177 11178 this.resizing = true; 11179 11180 this._renderProxy(); 11181 11182 curleft = this._num( this.helper.css( "left" ) ); 11183 curtop = this._num( this.helper.css( "top" ) ); 11184 11185 if ( o.containment ) { 11186 curleft += $( o.containment ).scrollLeft() || 0; 11187 curtop += $( o.containment ).scrollTop() || 0; 11188 } 11189 11190 this.offset = this.helper.offset(); 11191 this.position = { left: curleft, top: curtop }; 11192 11193 if ( !this._helper ) { 11194 calculatedSize = this._calculateAdjustedElementDimensions( el ); 11195 } 11196 11197 this.size = this._helper ? { 11198 width: this.helper.width(), 11199 height: this.helper.height() 11200 } : { 11201 width: calculatedSize.width, 11202 height: calculatedSize.height 11203 }; 11204 11205 this.originalSize = this._helper ? { 11206 width: el.outerWidth(), 11207 height: el.outerHeight() 11208 } : { 11209 width: calculatedSize.width, 11210 height: calculatedSize.height 11211 }; 11212 11213 this.sizeDiff = { 11214 width: el.outerWidth() - el.width(), 11215 height: el.outerHeight() - el.height() 11216 }; 11217 11218 this.originalPosition = { left: curleft, top: curtop }; 11219 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 11220 11221 this.aspectRatio = ( typeof o.aspectRatio === "number" ) ? 11222 o.aspectRatio : 11223 ( ( this.originalSize.width / this.originalSize.height ) || 1 ); 11224 11225 cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" ); 11226 $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor ); 11227 11228 this._addClass( "ui-resizable-resizing" ); 11229 this._propagate( "start", event ); 11230 return true; 11231 }, 11232 11233 _mouseDrag: function( event ) { 11234 11235 var data, props, 11236 smp = this.originalMousePosition, 11237 a = this.axis, 11238 dx = ( event.pageX - smp.left ) || 0, 11239 dy = ( event.pageY - smp.top ) || 0, 11240 trigger = this._change[ a ]; 11241 11242 this._updatePrevProperties(); 11243 11244 if ( !trigger ) { 11245 return false; 11246 } 11247 11248 data = trigger.apply( this, [ event, dx, dy ] ); 11249 11250 this._updateVirtualBoundaries( event.shiftKey ); 11251 if ( this._aspectRatio || event.shiftKey ) { 11252 data = this._updateRatio( data, event ); 11253 } 11254 11255 data = this._respectSize( data, event ); 11256 11257 this._updateCache( data ); 11258 11259 this._propagate( "resize", event ); 11260 11261 props = this._applyChanges(); 11262 11263 if ( !this._helper && this._proportionallyResizeElements.length ) { 11264 this._proportionallyResize(); 11265 } 11266 11267 if ( !$.isEmptyObject( props ) ) { 11268 this._updatePrevProperties(); 11269 this._trigger( "resize", event, this.ui() ); 11270 this._applyChanges(); 11271 } 11272 11273 return false; 11274 }, 11275 11276 _mouseStop: function( event ) { 11277 11278 this.resizing = false; 11279 var pr, ista, soffseth, soffsetw, s, left, top, 11280 o = this.options, that = this; 11281 11282 if ( this._helper ) { 11283 11284 pr = this._proportionallyResizeElements; 11285 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ); 11286 soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height; 11287 soffsetw = ista ? 0 : that.sizeDiff.width; 11288 11289 s = { 11290 width: ( that.helper.width() - soffsetw ), 11291 height: ( that.helper.height() - soffseth ) 11292 }; 11293 left = ( parseFloat( that.element.css( "left" ) ) + 11294 ( that.position.left - that.originalPosition.left ) ) || null; 11295 top = ( parseFloat( that.element.css( "top" ) ) + 11296 ( that.position.top - that.originalPosition.top ) ) || null; 11297 11298 if ( !o.animate ) { 11299 this.element.css( $.extend( s, { top: top, left: left } ) ); 11300 } 11301 11302 that.helper.height( that.size.height ); 11303 that.helper.width( that.size.width ); 11304 11305 if ( this._helper && !o.animate ) { 11306 this._proportionallyResize(); 11307 } 11308 } 11309 11310 $( "body" ).css( "cursor", "auto" ); 11311 11312 this._removeClass( "ui-resizable-resizing" ); 11313 11314 this._propagate( "stop", event ); 11315 11316 if ( this._helper ) { 11317 this.helper.remove(); 11318 } 11319 11320 return false; 11321 11322 }, 11323 11324 _updatePrevProperties: function() { 11325 this.prevPosition = { 11326 top: this.position.top, 11327 left: this.position.left 11328 }; 11329 this.prevSize = { 11330 width: this.size.width, 11331 height: this.size.height 11332 }; 11333 }, 11334 11335 _applyChanges: function() { 11336 var props = {}; 11337 11338 if ( this.position.top !== this.prevPosition.top ) { 11339 props.top = this.position.top + "px"; 11340 } 11341 if ( this.position.left !== this.prevPosition.left ) { 11342 props.left = this.position.left + "px"; 11343 } 11344 11345 this.helper.css( props ); 11346 11347 if ( this.size.width !== this.prevSize.width ) { 11348 props.width = this.size.width + "px"; 11349 this.helper.width( props.width ); 11350 } 11351 if ( this.size.height !== this.prevSize.height ) { 11352 props.height = this.size.height + "px"; 11353 this.helper.height( props.height ); 11354 } 11355 11356 return props; 11357 }, 11358 11359 _updateVirtualBoundaries: function( forceAspectRatio ) { 11360 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, 11361 o = this.options; 11362 11363 b = { 11364 minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0, 11365 maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity, 11366 minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0, 11367 maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity 11368 }; 11369 11370 if ( this._aspectRatio || forceAspectRatio ) { 11371 pMinWidth = b.minHeight * this.aspectRatio; 11372 pMinHeight = b.minWidth / this.aspectRatio; 11373 pMaxWidth = b.maxHeight * this.aspectRatio; 11374 pMaxHeight = b.maxWidth / this.aspectRatio; 11375 11376 if ( pMinWidth > b.minWidth ) { 11377 b.minWidth = pMinWidth; 11378 } 11379 if ( pMinHeight > b.minHeight ) { 11380 b.minHeight = pMinHeight; 11381 } 11382 if ( pMaxWidth < b.maxWidth ) { 11383 b.maxWidth = pMaxWidth; 11384 } 11385 if ( pMaxHeight < b.maxHeight ) { 11386 b.maxHeight = pMaxHeight; 11387 } 11388 } 11389 this._vBoundaries = b; 11390 }, 11391 11392 _updateCache: function( data ) { 11393 this.offset = this.helper.offset(); 11394 if ( this._isNumber( data.left ) ) { 11395 this.position.left = data.left; 11396 } 11397 if ( this._isNumber( data.top ) ) { 11398 this.position.top = data.top; 11399 } 11400 if ( this._isNumber( data.height ) ) { 11401 this.size.height = data.height; 11402 } 11403 if ( this._isNumber( data.width ) ) { 11404 this.size.width = data.width; 11405 } 11406 }, 11407 11408 _updateRatio: function( data ) { 11409 11410 var cpos = this.position, 11411 csize = this.size, 11412 a = this.axis; 11413 11414 if ( this._isNumber( data.height ) ) { 11415 data.width = ( data.height * this.aspectRatio ); 11416 } else if ( this._isNumber( data.width ) ) { 11417 data.height = ( data.width / this.aspectRatio ); 11418 } 11419 11420 if ( a === "sw" ) { 11421 data.left = cpos.left + ( csize.width - data.width ); 11422 data.top = null; 11423 } 11424 if ( a === "nw" ) { 11425 data.top = cpos.top + ( csize.height - data.height ); 11426 data.left = cpos.left + ( csize.width - data.width ); 11427 } 11428 11429 return data; 11430 }, 11431 11432 _respectSize: function( data ) { 11433 11434 var o = this._vBoundaries, 11435 a = this.axis, 11436 ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ), 11437 ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ), 11438 isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ), 11439 isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ), 11440 dw = this.originalPosition.left + this.originalSize.width, 11441 dh = this.originalPosition.top + this.originalSize.height, 11442 cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a ); 11443 if ( isminw ) { 11444 data.width = o.minWidth; 11445 } 11446 if ( isminh ) { 11447 data.height = o.minHeight; 11448 } 11449 if ( ismaxw ) { 11450 data.width = o.maxWidth; 11451 } 11452 if ( ismaxh ) { 11453 data.height = o.maxHeight; 11454 } 11455 11456 if ( isminw && cw ) { 11457 data.left = dw - o.minWidth; 11458 } 11459 if ( ismaxw && cw ) { 11460 data.left = dw - o.maxWidth; 11461 } 11462 if ( isminh && ch ) { 11463 data.top = dh - o.minHeight; 11464 } 11465 if ( ismaxh && ch ) { 11466 data.top = dh - o.maxHeight; 11467 } 11468 11469 // Fixing jump error on top/left - bug #2330 11470 if ( !data.width && !data.height && !data.left && data.top ) { 11471 data.top = null; 11472 } else if ( !data.width && !data.height && !data.top && data.left ) { 11473 data.left = null; 11474 } 11475 11476 return data; 11477 }, 11478 11479 _getPaddingPlusBorderDimensions: function( element ) { 11480 var i = 0, 11481 widths = [], 11482 borders = [ 11483 element.css( "borderTopWidth" ), 11484 element.css( "borderRightWidth" ), 11485 element.css( "borderBottomWidth" ), 11486 element.css( "borderLeftWidth" ) 11487 ], 11488 paddings = [ 11489 element.css( "paddingTop" ), 11490 element.css( "paddingRight" ), 11491 element.css( "paddingBottom" ), 11492 element.css( "paddingLeft" ) 11493 ]; 11494 11495 for ( ; i < 4; i++ ) { 11496 widths[ i ] = ( parseFloat( borders[ i ] ) || 0 ); 11497 widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 ); 11498 } 11499 11500 return { 11501 height: widths[ 0 ] + widths[ 2 ], 11502 width: widths[ 1 ] + widths[ 3 ] 11503 }; 11504 }, 11505 11506 _calculateAdjustedElementDimensions: function( element ) { 11507 var elWidth, elHeight, paddingBorder, 11508 ce = element.get( 0 ); 11509 11510 if ( element.css( "box-sizing" ) !== "content-box" || 11511 ( !this._hasScroll( ce ) && !this._hasScroll( ce, "left" ) ) ) { 11512 return { 11513 height: parseFloat( element.css( "height" ) ), 11514 width: parseFloat( element.css( "width" ) ) 11515 }; 11516 } 11517 11518 // Check if CSS inline styles are set and use those (usually from previous resizes) 11519 elWidth = parseFloat( ce.style.width ); 11520 elHeight = parseFloat( ce.style.height ); 11521 11522 paddingBorder = this._getPaddingPlusBorderDimensions( element ); 11523 elWidth = isNaN( elWidth ) ? 11524 this._getElementTheoreticalSize( element, paddingBorder, "width" ) : 11525 elWidth; 11526 elHeight = isNaN( elHeight ) ? 11527 this._getElementTheoreticalSize( element, paddingBorder, "height" ) : 11528 elHeight; 11529 11530 return { 11531 height: elHeight, 11532 width: elWidth 11533 }; 11534 }, 11535 11536 _getElementTheoreticalSize: function( element, extraSize, dimension ) { 11537 11538 // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border 11539 var size = Math.max( 0, Math.ceil( 11540 element.get( 0 )[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - 11541 extraSize[ dimension ] - 11542 0.5 11543 11544 // If offsetWidth/offsetHeight is unknown, then we can't determine theoretical size. 11545 // Use an explicit zero to avoid NaN. 11546 // See https://github.com/jquery/jquery/issues/3964 11547 ) ) || 0; 11548 11549 return size; 11550 }, 11551 11552 _proportionallyResize: function() { 11553 11554 if ( !this._proportionallyResizeElements.length ) { 11555 return; 11556 } 11557 11558 var prel, 11559 i = 0, 11560 element = this.helper || this.element; 11561 11562 for ( ; i < this._proportionallyResizeElements.length; i++ ) { 11563 11564 prel = this._proportionallyResizeElements[ i ]; 11565 11566 // TODO: Seems like a bug to cache this.outerDimensions 11567 // considering that we are in a loop. 11568 if ( !this.outerDimensions ) { 11569 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); 11570 } 11571 11572 prel.css( { 11573 height: ( element.height() - this.outerDimensions.height ) || 0, 11574 width: ( element.width() - this.outerDimensions.width ) || 0 11575 } ); 11576 11577 } 11578 11579 }, 11580 11581 _renderProxy: function() { 11582 11583 var el = this.element, o = this.options; 11584 this.elementOffset = el.offset(); 11585 11586 if ( this._helper ) { 11587 11588 this.helper = this.helper || $( "<div></div>" ).css( { overflow: "hidden" } ); 11589 11590 this._addClass( this.helper, this._helper ); 11591 this.helper.css( { 11592 width: this.element.outerWidth(), 11593 height: this.element.outerHeight(), 11594 position: "absolute", 11595 left: this.elementOffset.left + "px", 11596 top: this.elementOffset.top + "px", 11597 zIndex: ++o.zIndex //TODO: Don't modify option 11598 } ); 11599 11600 this.helper 11601 .appendTo( "body" ) 11602 .disableSelection(); 11603 11604 } else { 11605 this.helper = this.element; 11606 } 11607 11608 }, 11609 11610 _change: { 11611 e: function( event, dx ) { 11612 return { width: this.originalSize.width + dx }; 11613 }, 11614 w: function( event, dx ) { 11615 var cs = this.originalSize, sp = this.originalPosition; 11616 return { left: sp.left + dx, width: cs.width - dx }; 11617 }, 11618 n: function( event, dx, dy ) { 11619 var cs = this.originalSize, sp = this.originalPosition; 11620 return { top: sp.top + dy, height: cs.height - dy }; 11621 }, 11622 s: function( event, dx, dy ) { 11623 return { height: this.originalSize.height + dy }; 11624 }, 11625 se: function( event, dx, dy ) { 11626 return $.extend( this._change.s.apply( this, arguments ), 11627 this._change.e.apply( this, [ event, dx, dy ] ) ); 11628 }, 11629 sw: function( event, dx, dy ) { 11630 return $.extend( this._change.s.apply( this, arguments ), 11631 this._change.w.apply( this, [ event, dx, dy ] ) ); 11632 }, 11633 ne: function( event, dx, dy ) { 11634 return $.extend( this._change.n.apply( this, arguments ), 11635 this._change.e.apply( this, [ event, dx, dy ] ) ); 11636 }, 11637 nw: function( event, dx, dy ) { 11638 return $.extend( this._change.n.apply( this, arguments ), 11639 this._change.w.apply( this, [ event, dx, dy ] ) ); 11640 } 11641 }, 11642 11643 _propagate: function( n, event ) { 11644 $.ui.plugin.call( this, n, [ event, this.ui() ] ); 11645 if ( n !== "resize" ) { 11646 this._trigger( n, event, this.ui() ); 11647 } 11648 }, 11649 11650 plugins: {}, 11651 11652 ui: function() { 11653 return { 11654 originalElement: this.originalElement, 11655 element: this.element, 11656 helper: this.helper, 11657 position: this.position, 11658 size: this.size, 11659 originalSize: this.originalSize, 11660 originalPosition: this.originalPosition 11661 }; 11662 } 11663 11664} ); 11665 11666/* 11667 * Resizable Extensions 11668 */ 11669 11670$.ui.plugin.add( "resizable", "animate", { 11671 11672 stop: function( event ) { 11673 var that = $( this ).resizable( "instance" ), 11674 o = that.options, 11675 pr = that._proportionallyResizeElements, 11676 ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ), 11677 soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height, 11678 soffsetw = ista ? 0 : that.sizeDiff.width, 11679 style = { 11680 width: ( that.size.width - soffsetw ), 11681 height: ( that.size.height - soffseth ) 11682 }, 11683 left = ( parseFloat( that.element.css( "left" ) ) + 11684 ( that.position.left - that.originalPosition.left ) ) || null, 11685 top = ( parseFloat( that.element.css( "top" ) ) + 11686 ( that.position.top - that.originalPosition.top ) ) || null; 11687 11688 that.element.animate( 11689 $.extend( style, top && left ? { top: top, left: left } : {} ), { 11690 duration: o.animateDuration, 11691 easing: o.animateEasing, 11692 step: function() { 11693 11694 var data = { 11695 width: parseFloat( that.element.css( "width" ) ), 11696 height: parseFloat( that.element.css( "height" ) ), 11697 top: parseFloat( that.element.css( "top" ) ), 11698 left: parseFloat( that.element.css( "left" ) ) 11699 }; 11700 11701 if ( pr && pr.length ) { 11702 $( pr[ 0 ] ).css( { width: data.width, height: data.height } ); 11703 } 11704 11705 // Propagating resize, and updating values for each animation step 11706 that._updateCache( data ); 11707 that._propagate( "resize", event ); 11708 11709 } 11710 } 11711 ); 11712 } 11713 11714} ); 11715 11716$.ui.plugin.add( "resizable", "containment", { 11717 11718 start: function() { 11719 var element, p, co, ch, cw, width, height, 11720 that = $( this ).resizable( "instance" ), 11721 o = that.options, 11722 el = that.element, 11723 oc = o.containment, 11724 ce = ( oc instanceof $ ) ? 11725 oc.get( 0 ) : 11726 ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; 11727 11728 if ( !ce ) { 11729 return; 11730 } 11731 11732 that.containerElement = $( ce ); 11733 11734 if ( /document/.test( oc ) || oc === document ) { 11735 that.containerOffset = { 11736 left: 0, 11737 top: 0 11738 }; 11739 that.containerPosition = { 11740 left: 0, 11741 top: 0 11742 }; 11743 11744 that.parentData = { 11745 element: $( document ), 11746 left: 0, 11747 top: 0, 11748 width: $( document ).width(), 11749 height: $( document ).height() || document.body.parentNode.scrollHeight 11750 }; 11751 } else { 11752 element = $( ce ); 11753 p = []; 11754 $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) { 11755 p[ i ] = that._num( element.css( "padding" + name ) ); 11756 } ); 11757 11758 that.containerOffset = element.offset(); 11759 that.containerPosition = element.position(); 11760 that.containerSize = { 11761 height: ( element.innerHeight() - p[ 3 ] ), 11762 width: ( element.innerWidth() - p[ 1 ] ) 11763 }; 11764 11765 co = that.containerOffset; 11766 ch = that.containerSize.height; 11767 cw = that.containerSize.width; 11768 width = ( that._hasScroll( ce, "left" ) ? ce.scrollWidth : cw ); 11769 height = ( that._hasScroll( ce ) ? ce.scrollHeight : ch ); 11770 11771 that.parentData = { 11772 element: ce, 11773 left: co.left, 11774 top: co.top, 11775 width: width, 11776 height: height 11777 }; 11778 } 11779 }, 11780 11781 resize: function( event ) { 11782 var woset, hoset, isParent, isOffsetRelative, 11783 that = $( this ).resizable( "instance" ), 11784 o = that.options, 11785 co = that.containerOffset, 11786 cp = that.position, 11787 pRatio = that._aspectRatio || event.shiftKey, 11788 cop = { 11789 top: 0, 11790 left: 0 11791 }, 11792 ce = that.containerElement, 11793 continueResize = true; 11794 11795 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { 11796 cop = co; 11797 } 11798 11799 if ( cp.left < ( that._helper ? co.left : 0 ) ) { 11800 that.size.width = that.size.width + 11801 ( that._helper ? 11802 ( that.position.left - co.left ) : 11803 ( that.position.left - cop.left ) ); 11804 11805 if ( pRatio ) { 11806 that.size.height = that.size.width / that.aspectRatio; 11807 continueResize = false; 11808 } 11809 that.position.left = o.helper ? co.left : 0; 11810 } 11811 11812 if ( cp.top < ( that._helper ? co.top : 0 ) ) { 11813 that.size.height = that.size.height + 11814 ( that._helper ? 11815 ( that.position.top - co.top ) : 11816 that.position.top ); 11817 11818 if ( pRatio ) { 11819 that.size.width = that.size.height * that.aspectRatio; 11820 continueResize = false; 11821 } 11822 that.position.top = that._helper ? co.top : 0; 11823 } 11824 11825 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); 11826 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); 11827 11828 if ( isParent && isOffsetRelative ) { 11829 that.offset.left = that.parentData.left + that.position.left; 11830 that.offset.top = that.parentData.top + that.position.top; 11831 } else { 11832 that.offset.left = that.element.offset().left; 11833 that.offset.top = that.element.offset().top; 11834 } 11835 11836 woset = Math.abs( that.sizeDiff.width + 11837 ( that._helper ? 11838 that.offset.left - cop.left : 11839 ( that.offset.left - co.left ) ) ); 11840 11841 hoset = Math.abs( that.sizeDiff.height + 11842 ( that._helper ? 11843 that.offset.top - cop.top : 11844 ( that.offset.top - co.top ) ) ); 11845 11846 if ( woset + that.size.width >= that.parentData.width ) { 11847 that.size.width = that.parentData.width - woset; 11848 if ( pRatio ) { 11849 that.size.height = that.size.width / that.aspectRatio; 11850 continueResize = false; 11851 } 11852 } 11853 11854 if ( hoset + that.size.height >= that.parentData.height ) { 11855 that.size.height = that.parentData.height - hoset; 11856 if ( pRatio ) { 11857 that.size.width = that.size.height * that.aspectRatio; 11858 continueResize = false; 11859 } 11860 } 11861 11862 if ( !continueResize ) { 11863 that.position.left = that.prevPosition.left; 11864 that.position.top = that.prevPosition.top; 11865 that.size.width = that.prevSize.width; 11866 that.size.height = that.prevSize.height; 11867 } 11868 }, 11869 11870 stop: function() { 11871 var that = $( this ).resizable( "instance" ), 11872 o = that.options, 11873 co = that.containerOffset, 11874 cop = that.containerPosition, 11875 ce = that.containerElement, 11876 helper = $( that.helper ), 11877 ho = helper.offset(), 11878 w = helper.outerWidth() - that.sizeDiff.width, 11879 h = helper.outerHeight() - that.sizeDiff.height; 11880 11881 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { 11882 $( this ).css( { 11883 left: ho.left - cop.left - co.left, 11884 width: w, 11885 height: h 11886 } ); 11887 } 11888 11889 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { 11890 $( this ).css( { 11891 left: ho.left - cop.left - co.left, 11892 width: w, 11893 height: h 11894 } ); 11895 } 11896 } 11897} ); 11898 11899$.ui.plugin.add( "resizable", "alsoResize", { 11900 11901 start: function() { 11902 var that = $( this ).resizable( "instance" ), 11903 o = that.options; 11904 11905 $( o.alsoResize ).each( function() { 11906 var el = $( this ), 11907 elSize = that._calculateAdjustedElementDimensions( el ); 11908 11909 el.data( "ui-resizable-alsoresize", { 11910 width: elSize.width, height: elSize.height, 11911 left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) ) 11912 } ); 11913 } ); 11914 }, 11915 11916 resize: function( event, ui ) { 11917 var that = $( this ).resizable( "instance" ), 11918 o = that.options, 11919 os = that.originalSize, 11920 op = that.originalPosition, 11921 delta = { 11922 height: ( that.size.height - os.height ) || 0, 11923 width: ( that.size.width - os.width ) || 0, 11924 top: ( that.position.top - op.top ) || 0, 11925 left: ( that.position.left - op.left ) || 0 11926 }; 11927 11928 $( o.alsoResize ).each( function() { 11929 var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {}, 11930 css = el.parents( ui.originalElement[ 0 ] ).length ? 11931 [ "width", "height" ] : 11932 [ "width", "height", "top", "left" ]; 11933 11934 $.each( css, function( i, prop ) { 11935 var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 ); 11936 if ( sum && sum >= 0 ) { 11937 style[ prop ] = sum || null; 11938 } 11939 } ); 11940 11941 el.css( style ); 11942 } ); 11943 }, 11944 11945 stop: function() { 11946 $( this ).removeData( "ui-resizable-alsoresize" ); 11947 } 11948} ); 11949 11950$.ui.plugin.add( "resizable", "ghost", { 11951 11952 start: function() { 11953 11954 var that = $( this ).resizable( "instance" ), cs = that.size; 11955 11956 that.ghost = that.originalElement.clone(); 11957 that.ghost.css( { 11958 opacity: 0.25, 11959 display: "block", 11960 position: "relative", 11961 height: cs.height, 11962 width: cs.width, 11963 margin: 0, 11964 left: 0, 11965 top: 0 11966 } ); 11967 11968 that._addClass( that.ghost, "ui-resizable-ghost" ); 11969 11970 // DEPRECATED 11971 // TODO: remove after 1.12 11972 if ( $.uiBackCompat === true && typeof that.options.ghost === "string" ) { 11973 11974 // Ghost option 11975 that.ghost.addClass( this.options.ghost ); 11976 } 11977 11978 that.ghost.appendTo( that.helper ); 11979 11980 }, 11981 11982 resize: function() { 11983 var that = $( this ).resizable( "instance" ); 11984 if ( that.ghost ) { 11985 that.ghost.css( { 11986 position: "relative", 11987 height: that.size.height, 11988 width: that.size.width 11989 } ); 11990 } 11991 }, 11992 11993 stop: function() { 11994 var that = $( this ).resizable( "instance" ); 11995 if ( that.ghost && that.helper ) { 11996 that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) ); 11997 } 11998 } 11999 12000} ); 12001 12002$.ui.plugin.add( "resizable", "grid", { 12003 12004 resize: function() { 12005 var outerDimensions, 12006 that = $( this ).resizable( "instance" ), 12007 o = that.options, 12008 cs = that.size, 12009 os = that.originalSize, 12010 op = that.originalPosition, 12011 a = that.axis, 12012 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, 12013 gridX = ( grid[ 0 ] || 1 ), 12014 gridY = ( grid[ 1 ] || 1 ), 12015 ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX, 12016 oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY, 12017 newWidth = os.width + ox, 12018 newHeight = os.height + oy, 12019 isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ), 12020 isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ), 12021 isMinWidth = o.minWidth && ( o.minWidth > newWidth ), 12022 isMinHeight = o.minHeight && ( o.minHeight > newHeight ); 12023 12024 o.grid = grid; 12025 12026 if ( isMinWidth ) { 12027 newWidth += gridX; 12028 } 12029 if ( isMinHeight ) { 12030 newHeight += gridY; 12031 } 12032 if ( isMaxWidth ) { 12033 newWidth -= gridX; 12034 } 12035 if ( isMaxHeight ) { 12036 newHeight -= gridY; 12037 } 12038 12039 if ( /^(se|s|e)$/.test( a ) ) { 12040 that.size.width = newWidth; 12041 that.size.height = newHeight; 12042 } else if ( /^(ne)$/.test( a ) ) { 12043 that.size.width = newWidth; 12044 that.size.height = newHeight; 12045 that.position.top = op.top - oy; 12046 } else if ( /^(sw)$/.test( a ) ) { 12047 that.size.width = newWidth; 12048 that.size.height = newHeight; 12049 that.position.left = op.left - ox; 12050 } else { 12051 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) { 12052 outerDimensions = that._getPaddingPlusBorderDimensions( this ); 12053 } 12054 12055 if ( newHeight - gridY > 0 ) { 12056 that.size.height = newHeight; 12057 that.position.top = op.top - oy; 12058 } else { 12059 newHeight = gridY - outerDimensions.height; 12060 that.size.height = newHeight; 12061 that.position.top = op.top + os.height - newHeight; 12062 } 12063 if ( newWidth - gridX > 0 ) { 12064 that.size.width = newWidth; 12065 that.position.left = op.left - ox; 12066 } else { 12067 newWidth = gridX - outerDimensions.width; 12068 that.size.width = newWidth; 12069 that.position.left = op.left + os.width - newWidth; 12070 } 12071 } 12072 } 12073 12074} ); 12075 12076var widgetsResizable = $.ui.resizable; 12077 12078 12079/*! 12080 * jQuery UI Dialog 1.14.1 12081 * https://jqueryui.com 12082 * 12083 * Copyright OpenJS Foundation and other contributors 12084 * Released under the MIT license. 12085 * https://jquery.org/license 12086 */ 12087 12088//>>label: Dialog 12089//>>group: Widgets 12090//>>description: Displays customizable dialog windows. 12091//>>docs: https://api.jqueryui.com/dialog/ 12092//>>demos: https://jqueryui.com/dialog/ 12093//>>css.structure: ../../themes/base/core.css 12094//>>css.structure: ../../themes/base/dialog.css 12095//>>css.theme: ../../themes/base/theme.css 12096 12097 12098$.widget( "ui.dialog", { 12099 version: "1.14.1", 12100 options: { 12101 appendTo: "body", 12102 autoOpen: true, 12103 buttons: [], 12104 classes: { 12105 "ui-dialog": "ui-corner-all", 12106 "ui-dialog-titlebar": "ui-corner-all" 12107 }, 12108 closeOnEscape: true, 12109 closeText: "Close", 12110 draggable: true, 12111 hide: null, 12112 height: "auto", 12113 maxHeight: null, 12114 maxWidth: null, 12115 minHeight: 150, 12116 minWidth: 150, 12117 modal: false, 12118 position: { 12119 my: "center", 12120 at: "center", 12121 of: window, 12122 collision: "fit", 12123 12124 // Ensure the titlebar is always visible 12125 using: function( pos ) { 12126 var topOffset = $( this ).css( pos ).offset().top; 12127 if ( topOffset < 0 ) { 12128 $( this ).css( "top", pos.top - topOffset ); 12129 } 12130 } 12131 }, 12132 resizable: true, 12133 show: null, 12134 title: null, 12135 uiDialogTitleHeadingLevel: 0, 12136 width: 300, 12137 12138 // Callbacks 12139 beforeClose: null, 12140 close: null, 12141 drag: null, 12142 dragStart: null, 12143 dragStop: null, 12144 focus: null, 12145 open: null, 12146 resize: null, 12147 resizeStart: null, 12148 resizeStop: null 12149 }, 12150 12151 sizeRelatedOptions: { 12152 buttons: true, 12153 height: true, 12154 maxHeight: true, 12155 maxWidth: true, 12156 minHeight: true, 12157 minWidth: true, 12158 width: true 12159 }, 12160 12161 resizableRelatedOptions: { 12162 maxHeight: true, 12163 maxWidth: true, 12164 minHeight: true, 12165 minWidth: true 12166 }, 12167 12168 _create: function() { 12169 this.originalCss = { 12170 display: this.element[ 0 ].style.display, 12171 width: this.element[ 0 ].style.width, 12172 minHeight: this.element[ 0 ].style.minHeight, 12173 maxHeight: this.element[ 0 ].style.maxHeight, 12174 height: this.element[ 0 ].style.height 12175 }; 12176 this.originalPosition = { 12177 parent: this.element.parent(), 12178 index: this.element.parent().children().index( this.element ) 12179 }; 12180 this.originalTitle = this.element.attr( "title" ); 12181 if ( this.options.title == null && this.originalTitle != null ) { 12182 this.options.title = this.originalTitle; 12183 } 12184 12185 // Dialogs can't be disabled 12186 if ( this.options.disabled ) { 12187 this.options.disabled = false; 12188 } 12189 12190 this._createWrapper(); 12191 12192 this.element 12193 .show() 12194 .removeAttr( "title" ) 12195 .appendTo( this.uiDialog ); 12196 12197 this._addClass( "ui-dialog-content", "ui-widget-content" ); 12198 12199 this._createTitlebar(); 12200 this._createButtonPane(); 12201 12202 if ( this.options.draggable && $.fn.draggable ) { 12203 this._makeDraggable(); 12204 } 12205 if ( this.options.resizable && $.fn.resizable ) { 12206 this._makeResizable(); 12207 } 12208 12209 this._isOpen = false; 12210 12211 this._trackFocus(); 12212 }, 12213 12214 _init: function() { 12215 if ( this.options.autoOpen ) { 12216 this.open(); 12217 } 12218 }, 12219 12220 _appendTo: function() { 12221 var element = this.options.appendTo; 12222 if ( element && ( element.jquery || element.nodeType ) ) { 12223 return $( element ); 12224 } 12225 return this.document.find( element || "body" ).eq( 0 ); 12226 }, 12227 12228 _destroy: function() { 12229 var next, 12230 originalPosition = this.originalPosition; 12231 12232 this._untrackInstance(); 12233 this._destroyOverlay(); 12234 12235 this.element 12236 .removeUniqueId() 12237 .css( this.originalCss ) 12238 12239 // Without detaching first, the following becomes really slow 12240 .detach(); 12241 12242 this.uiDialog.remove(); 12243 12244 if ( this.originalTitle ) { 12245 this.element.attr( "title", this.originalTitle ); 12246 } 12247 12248 next = originalPosition.parent.children().eq( originalPosition.index ); 12249 12250 // Don't try to place the dialog next to itself (#8613) 12251 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { 12252 next.before( this.element ); 12253 } else { 12254 originalPosition.parent.append( this.element ); 12255 } 12256 }, 12257 12258 widget: function() { 12259 return this.uiDialog; 12260 }, 12261 12262 disable: $.noop, 12263 enable: $.noop, 12264 12265 close: function( event ) { 12266 var that = this; 12267 12268 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { 12269 return; 12270 } 12271 12272 this._isOpen = false; 12273 this._focusedElement = null; 12274 this._destroyOverlay(); 12275 this._untrackInstance(); 12276 12277 if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) { 12278 12279 // Hiding a focused element doesn't trigger blur in WebKit 12280 // so in case we have nothing to focus on, explicitly blur the active element 12281 // https://bugs.webkit.org/show_bug.cgi?id=47182 12282 $( this.document[ 0 ].activeElement ).trigger( "blur" ); 12283 } 12284 12285 this._hide( this.uiDialog, this.options.hide, function() { 12286 that._trigger( "close", event ); 12287 } ); 12288 }, 12289 12290 isOpen: function() { 12291 return this._isOpen; 12292 }, 12293 12294 moveToTop: function() { 12295 this._moveToTop(); 12296 }, 12297 12298 _moveToTop: function( event, silent ) { 12299 var moved = false, 12300 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() { 12301 return +$( this ).css( "z-index" ); 12302 } ).get(), 12303 zIndexMax = Math.max.apply( null, zIndices ); 12304 12305 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { 12306 this.uiDialog.css( "z-index", zIndexMax + 1 ); 12307 moved = true; 12308 } 12309 12310 if ( moved && !silent ) { 12311 this._trigger( "focus", event ); 12312 } 12313 return moved; 12314 }, 12315 12316 open: function() { 12317 var that = this; 12318 if ( this._isOpen ) { 12319 if ( this._moveToTop() ) { 12320 this._focusTabbable(); 12321 } 12322 return; 12323 } 12324 12325 this._isOpen = true; 12326 this.opener = $( this.document[ 0 ].activeElement ); 12327 12328 this._size(); 12329 this._position(); 12330 this._createOverlay(); 12331 this._moveToTop( null, true ); 12332 12333 // Ensure the overlay is moved to the top with the dialog, but only when 12334 // opening. The overlay shouldn't move after the dialog is open so that 12335 // modeless dialogs opened after the modal dialog stack properly. 12336 if ( this.overlay ) { 12337 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); 12338 } 12339 12340 this._show( this.uiDialog, this.options.show, function() { 12341 that._focusTabbable(); 12342 that._trigger( "focus" ); 12343 } ); 12344 12345 // Track the dialog immediately upon opening in case a focus event 12346 // somehow occurs outside of the dialog before an element inside the 12347 // dialog is focused (#10152) 12348 this._makeFocusTarget(); 12349 12350 this._trigger( "open" ); 12351 }, 12352 12353 _focusTabbable: function() { 12354 12355 // Set focus to the first match: 12356 // 1. An element that was focused previously 12357 // 2. First element inside the dialog matching [autofocus] 12358 // 3. Tabbable element inside the content element 12359 // 4. Tabbable element inside the buttonpane 12360 // 5. The close button 12361 // 6. The dialog itself 12362 var hasFocus = this._focusedElement; 12363 if ( !hasFocus ) { 12364 hasFocus = this.element.find( "[autofocus]" ); 12365 } 12366 if ( !hasFocus.length ) { 12367 hasFocus = this.element.find( ":tabbable" ); 12368 } 12369 if ( !hasFocus.length ) { 12370 hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); 12371 } 12372 if ( !hasFocus.length ) { 12373 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); 12374 } 12375 if ( !hasFocus.length ) { 12376 hasFocus = this.uiDialog; 12377 } 12378 hasFocus.eq( 0 ).trigger( "focus" ); 12379 }, 12380 12381 _restoreTabbableFocus: function() { 12382 var activeElement = this.document[ 0 ].activeElement, 12383 isActive = this.uiDialog[ 0 ] === activeElement || 12384 $.contains( this.uiDialog[ 0 ], activeElement ); 12385 if ( !isActive ) { 12386 this._focusTabbable(); 12387 } 12388 }, 12389 12390 _keepFocus: function( event ) { 12391 event.preventDefault(); 12392 this._restoreTabbableFocus(); 12393 }, 12394 12395 _createWrapper: function() { 12396 this.uiDialog = $( "<div>" ) 12397 .hide() 12398 .attr( { 12399 12400 // Setting tabIndex makes the div focusable 12401 tabIndex: -1, 12402 role: "dialog", 12403 "aria-modal": this.options.modal ? "true" : null 12404 } ) 12405 .appendTo( this._appendTo() ); 12406 12407 this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" ); 12408 this._on( this.uiDialog, { 12409 keydown: function( event ) { 12410 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 12411 event.keyCode === $.ui.keyCode.ESCAPE ) { 12412 event.preventDefault(); 12413 this.close( event ); 12414 return; 12415 } 12416 12417 // Prevent tabbing out of dialogs 12418 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { 12419 return; 12420 } 12421 var tabbables = this.uiDialog.find( ":tabbable" ), 12422 first = tabbables.first(), 12423 last = tabbables.last(); 12424 12425 if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) && 12426 !event.shiftKey ) { 12427 this._delay( function() { 12428 first.trigger( "focus" ); 12429 } ); 12430 event.preventDefault(); 12431 } else if ( ( event.target === first[ 0 ] || 12432 event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) { 12433 this._delay( function() { 12434 last.trigger( "focus" ); 12435 } ); 12436 event.preventDefault(); 12437 } 12438 }, 12439 mousedown: function( event ) { 12440 if ( this._moveToTop( event ) ) { 12441 this._focusTabbable(); 12442 } 12443 } 12444 } ); 12445 12446 // We assume that any existing aria-describedby attribute means 12447 // that the dialog content is marked up properly 12448 // otherwise we brute force the content as the description 12449 if ( !this.element.find( "[aria-describedby]" ).length ) { 12450 this.uiDialog.attr( { 12451 "aria-describedby": this.element.uniqueId().attr( "id" ) 12452 } ); 12453 } 12454 }, 12455 12456 _createTitlebar: function() { 12457 var uiDialogTitle; 12458 12459 this.uiDialogTitlebar = $( "<div>" ); 12460 this._addClass( this.uiDialogTitlebar, 12461 "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" ); 12462 this._on( this.uiDialogTitlebar, { 12463 mousedown: function( event ) { 12464 12465 // Don't prevent click on close button (#8838) 12466 // Focusing a dialog that is partially scrolled out of view 12467 // causes the browser to scroll it into view, preventing the click event 12468 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { 12469 12470 // Dialog isn't getting focus when dragging (#8063) 12471 this.uiDialog.trigger( "focus" ); 12472 } 12473 } 12474 } ); 12475 12476 this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) 12477 .button( { 12478 label: $( "<a>" ).text( this.options.closeText ).html(), 12479 icon: "ui-icon-closethick", 12480 showLabel: false 12481 } ) 12482 .appendTo( this.uiDialogTitlebar ); 12483 12484 this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" ); 12485 this._on( this.uiDialogTitlebarClose, { 12486 click: function( event ) { 12487 event.preventDefault(); 12488 this.close( event ); 12489 } 12490 } ); 12491 12492 var uiDialogHeadingLevel = Number.isInteger( this.options.uiDialogTitleHeadingLevel ) && 12493 this.options.uiDialogTitleHeadingLevel > 0 && 12494 this.options.uiDialogTitleHeadingLevel <= 6 ? 12495 "h" + this.options.uiDialogTitleHeadingLevel : "span"; 12496 12497 uiDialogTitle = $( "<" + uiDialogHeadingLevel + ">" ) 12498 .uniqueId().prependTo( this.uiDialogTitlebar ); 12499 this._addClass( uiDialogTitle, "ui-dialog-title" ); 12500 this._title( uiDialogTitle ); 12501 12502 this.uiDialogTitlebar.prependTo( this.uiDialog ); 12503 12504 this.uiDialog.attr( { 12505 "aria-labelledby": uiDialogTitle.attr( "id" ) 12506 } ); 12507 }, 12508 12509 _title: function( title ) { 12510 if ( this.options.title ) { 12511 title.text( this.options.title ); 12512 } else { 12513 title.html( " " ); 12514 } 12515 }, 12516 12517 _createButtonPane: function() { 12518 this.uiDialogButtonPane = $( "<div>" ); 12519 this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane", 12520 "ui-widget-content ui-helper-clearfix" ); 12521 12522 this.uiButtonSet = $( "<div>" ) 12523 .appendTo( this.uiDialogButtonPane ); 12524 this._addClass( this.uiButtonSet, "ui-dialog-buttonset" ); 12525 12526 this._createButtons(); 12527 }, 12528 12529 _createButtons: function() { 12530 var that = this, 12531 buttons = this.options.buttons; 12532 12533 // If we already have a button pane, remove it 12534 this.uiDialogButtonPane.remove(); 12535 this.uiButtonSet.empty(); 12536 12537 if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) { 12538 this._removeClass( this.uiDialog, "ui-dialog-buttons" ); 12539 return; 12540 } 12541 12542 $.each( buttons, function( name, props ) { 12543 var click, buttonOptions; 12544 props = typeof props === "function" ? 12545 { click: props, text: name } : 12546 props; 12547 12548 // Default to a non-submitting button 12549 props = $.extend( { type: "button" }, props ); 12550 12551 // Change the context for the click callback to be the main element 12552 click = props.click; 12553 buttonOptions = { 12554 icon: props.icon, 12555 iconPosition: props.iconPosition, 12556 showLabel: props.showLabel, 12557 12558 // Deprecated options 12559 icons: props.icons, 12560 text: props.text 12561 }; 12562 12563 delete props.click; 12564 delete props.icon; 12565 delete props.iconPosition; 12566 delete props.showLabel; 12567 12568 // Deprecated options 12569 delete props.icons; 12570 if ( typeof props.text === "boolean" ) { 12571 delete props.text; 12572 } 12573 12574 $( "<button></button>", props ) 12575 .button( buttonOptions ) 12576 .appendTo( that.uiButtonSet ) 12577 .on( "click", function() { 12578 click.apply( that.element[ 0 ], arguments ); 12579 } ); 12580 } ); 12581 this._addClass( this.uiDialog, "ui-dialog-buttons" ); 12582 this.uiDialogButtonPane.appendTo( this.uiDialog ); 12583 }, 12584 12585 _makeDraggable: function() { 12586 var that = this, 12587 options = this.options; 12588 12589 function filteredUi( ui ) { 12590 return { 12591 position: ui.position, 12592 offset: ui.offset 12593 }; 12594 } 12595 12596 this.uiDialog.draggable( { 12597 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", 12598 handle: ".ui-dialog-titlebar", 12599 containment: "document", 12600 start: function( event, ui ) { 12601 that._addClass( $( this ), "ui-dialog-dragging" ); 12602 that._blockFrames(); 12603 that._trigger( "dragStart", event, filteredUi( ui ) ); 12604 }, 12605 drag: function( event, ui ) { 12606 that._trigger( "drag", event, filteredUi( ui ) ); 12607 }, 12608 stop: function( event, ui ) { 12609 var left = ui.offset.left - that.document.scrollLeft(), 12610 top = ui.offset.top - that.document.scrollTop(); 12611 12612 options.position = { 12613 my: "left top", 12614 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12615 "top" + ( top >= 0 ? "+" : "" ) + top, 12616 of: that.window 12617 }; 12618 that._removeClass( $( this ), "ui-dialog-dragging" ); 12619 that._unblockFrames(); 12620 that._trigger( "dragStop", event, filteredUi( ui ) ); 12621 } 12622 } ); 12623 }, 12624 12625 _makeResizable: function() { 12626 var that = this, 12627 options = this.options, 12628 handles = options.resizable, 12629 12630 // .ui-resizable has position: relative defined in the stylesheet 12631 // but dialogs have to use absolute or fixed positioning 12632 position = this.uiDialog.css( "position" ), 12633 resizeHandles = typeof handles === "string" ? 12634 handles : 12635 "n,e,s,w,se,sw,ne,nw"; 12636 12637 function filteredUi( ui ) { 12638 return { 12639 originalPosition: ui.originalPosition, 12640 originalSize: ui.originalSize, 12641 position: ui.position, 12642 size: ui.size 12643 }; 12644 } 12645 12646 this.uiDialog.resizable( { 12647 cancel: ".ui-dialog-content", 12648 containment: "document", 12649 alsoResize: this.element, 12650 maxWidth: options.maxWidth, 12651 maxHeight: options.maxHeight, 12652 minWidth: options.minWidth, 12653 minHeight: this._minHeight(), 12654 handles: resizeHandles, 12655 start: function( event, ui ) { 12656 that._addClass( $( this ), "ui-dialog-resizing" ); 12657 that._blockFrames(); 12658 that._trigger( "resizeStart", event, filteredUi( ui ) ); 12659 }, 12660 resize: function( event, ui ) { 12661 that._trigger( "resize", event, filteredUi( ui ) ); 12662 }, 12663 stop: function( event, ui ) { 12664 var offset = that.uiDialog.offset(), 12665 left = offset.left - that.document.scrollLeft(), 12666 top = offset.top - that.document.scrollTop(); 12667 12668 options.height = that.uiDialog.height(); 12669 options.width = that.uiDialog.width(); 12670 options.position = { 12671 my: "left top", 12672 at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + 12673 "top" + ( top >= 0 ? "+" : "" ) + top, 12674 of: that.window 12675 }; 12676 that._removeClass( $( this ), "ui-dialog-resizing" ); 12677 that._unblockFrames(); 12678 that._trigger( "resizeStop", event, filteredUi( ui ) ); 12679 } 12680 } ) 12681 .css( "position", position ); 12682 }, 12683 12684 _trackFocus: function() { 12685 this._on( this.widget(), { 12686 focusin: function( event ) { 12687 this._makeFocusTarget(); 12688 this._focusedElement = $( event.target ); 12689 } 12690 } ); 12691 }, 12692 12693 _makeFocusTarget: function() { 12694 this._untrackInstance(); 12695 this._trackingInstances().unshift( this ); 12696 }, 12697 12698 _untrackInstance: function() { 12699 var instances = this._trackingInstances(), 12700 exists = $.inArray( this, instances ); 12701 if ( exists !== -1 ) { 12702 instances.splice( exists, 1 ); 12703 } 12704 }, 12705 12706 _trackingInstances: function() { 12707 var instances = this.document.data( "ui-dialog-instances" ); 12708 if ( !instances ) { 12709 instances = []; 12710 this.document.data( "ui-dialog-instances", instances ); 12711 } 12712 return instances; 12713 }, 12714 12715 _minHeight: function() { 12716 var options = this.options; 12717 12718 return options.height === "auto" ? 12719 options.minHeight : 12720 Math.min( options.minHeight, options.height ); 12721 }, 12722 12723 _position: function() { 12724 12725 // Need to show the dialog to get the actual offset in the position plugin 12726 var isVisible = this.uiDialog.is( ":visible" ); 12727 if ( !isVisible ) { 12728 this.uiDialog.show(); 12729 } 12730 this.uiDialog.position( this.options.position ); 12731 if ( !isVisible ) { 12732 this.uiDialog.hide(); 12733 } 12734 }, 12735 12736 _setOptions: function( options ) { 12737 var that = this, 12738 resize = false, 12739 resizableOptions = {}; 12740 12741 $.each( options, function( key, value ) { 12742 that._setOption( key, value ); 12743 12744 if ( key in that.sizeRelatedOptions ) { 12745 resize = true; 12746 } 12747 if ( key in that.resizableRelatedOptions ) { 12748 resizableOptions[ key ] = value; 12749 } 12750 } ); 12751 12752 if ( resize ) { 12753 this._size(); 12754 this._position(); 12755 } 12756 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12757 this.uiDialog.resizable( "option", resizableOptions ); 12758 } 12759 }, 12760 12761 _setOption: function( key, value ) { 12762 var isDraggable, isResizable, 12763 uiDialog = this.uiDialog; 12764 12765 if ( key === "disabled" ) { 12766 return; 12767 } 12768 12769 this._super( key, value ); 12770 12771 if ( key === "appendTo" ) { 12772 this.uiDialog.appendTo( this._appendTo() ); 12773 } 12774 12775 if ( key === "buttons" ) { 12776 this._createButtons(); 12777 } 12778 12779 if ( key === "closeText" ) { 12780 this.uiDialogTitlebarClose.button( { 12781 12782 // Ensure that we always pass a string 12783 label: $( "<a>" ).text( "" + this.options.closeText ).html() 12784 } ); 12785 } 12786 12787 if ( key === "draggable" ) { 12788 isDraggable = uiDialog.is( ":data(ui-draggable)" ); 12789 if ( isDraggable && !value ) { 12790 uiDialog.draggable( "destroy" ); 12791 } 12792 12793 if ( !isDraggable && value ) { 12794 this._makeDraggable(); 12795 } 12796 } 12797 12798 if ( key === "position" ) { 12799 this._position(); 12800 } 12801 12802 if ( key === "resizable" ) { 12803 12804 // currently resizable, becoming non-resizable 12805 isResizable = uiDialog.is( ":data(ui-resizable)" ); 12806 if ( isResizable && !value ) { 12807 uiDialog.resizable( "destroy" ); 12808 } 12809 12810 // Currently resizable, changing handles 12811 if ( isResizable && typeof value === "string" ) { 12812 uiDialog.resizable( "option", "handles", value ); 12813 } 12814 12815 // Currently non-resizable, becoming resizable 12816 if ( !isResizable && value !== false ) { 12817 this._makeResizable(); 12818 } 12819 } 12820 12821 if ( key === "title" ) { 12822 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); 12823 } 12824 12825 if ( key === "modal" ) { 12826 uiDialog.attr( "aria-modal", value ? "true" : null ); 12827 } 12828 }, 12829 12830 _size: function() { 12831 12832 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 12833 // divs will both have width and height set, so we need to reset them 12834 var nonContentHeight, minContentHeight, maxContentHeight, 12835 options = this.options; 12836 12837 // Reset content sizing 12838 this.element.show().css( { 12839 width: "auto", 12840 minHeight: 0, 12841 maxHeight: "none", 12842 height: 0 12843 } ); 12844 12845 if ( options.minWidth > options.width ) { 12846 options.width = options.minWidth; 12847 } 12848 12849 // Reset wrapper sizing 12850 // determine the height of all the non-content elements 12851 nonContentHeight = this.uiDialog.css( { 12852 height: "auto", 12853 width: options.width 12854 } ) 12855 .outerHeight(); 12856 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 12857 maxContentHeight = typeof options.maxHeight === "number" ? 12858 Math.max( 0, options.maxHeight - nonContentHeight ) : 12859 "none"; 12860 12861 if ( options.height === "auto" ) { 12862 this.element.css( { 12863 minHeight: minContentHeight, 12864 maxHeight: maxContentHeight, 12865 height: "auto" 12866 } ); 12867 } else { 12868 this.element.height( Math.max( 0, options.height - nonContentHeight ) ); 12869 } 12870 12871 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 12872 this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); 12873 } 12874 }, 12875 12876 _blockFrames: function() { 12877 this.iframeBlocks = this.document.find( "iframe" ).map( function() { 12878 var iframe = $( this ); 12879 12880 return $( "<div>" ) 12881 .css( { 12882 position: "absolute", 12883 width: iframe.outerWidth(), 12884 height: iframe.outerHeight() 12885 } ) 12886 .appendTo( iframe.parent() ) 12887 .offset( iframe.offset() )[ 0 ]; 12888 } ); 12889 }, 12890 12891 _unblockFrames: function() { 12892 if ( this.iframeBlocks ) { 12893 this.iframeBlocks.remove(); 12894 delete this.iframeBlocks; 12895 } 12896 }, 12897 12898 _allowInteraction: function( event ) { 12899 if ( $( event.target ).closest( ".ui-dialog" ).length ) { 12900 return true; 12901 } 12902 12903 // TODO: Remove hack when datepicker implements 12904 // the .ui-front logic (#8989) 12905 return !!$( event.target ).closest( ".ui-datepicker" ).length; 12906 }, 12907 12908 _createOverlay: function() { 12909 if ( !this.options.modal ) { 12910 return; 12911 } 12912 12913 // We use a delay in case the overlay is created from an 12914 // event that we're going to be cancelling (#2804) 12915 var isOpening = true; 12916 this._delay( function() { 12917 isOpening = false; 12918 } ); 12919 12920 if ( !this.document.data( "ui-dialog-overlays" ) ) { 12921 12922 // Prevent use of anchors and inputs 12923 // This doesn't use `_on()` because it is a shared event handler 12924 // across all open modal dialogs. 12925 this.document.on( "focusin.ui-dialog", function( event ) { 12926 if ( isOpening ) { 12927 return; 12928 } 12929 12930 var instance = this._trackingInstances()[ 0 ]; 12931 if ( !instance._allowInteraction( event ) ) { 12932 event.preventDefault(); 12933 instance._focusTabbable(); 12934 } 12935 }.bind( this ) ); 12936 } 12937 12938 this.overlay = $( "<div>" ) 12939 .appendTo( this._appendTo() ); 12940 12941 this._addClass( this.overlay, null, "ui-widget-overlay ui-front" ); 12942 this._on( this.overlay, { 12943 mousedown: "_keepFocus" 12944 } ); 12945 this.document.data( "ui-dialog-overlays", 12946 ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 ); 12947 }, 12948 12949 _destroyOverlay: function() { 12950 if ( !this.options.modal ) { 12951 return; 12952 } 12953 12954 if ( this.overlay ) { 12955 var overlays = this.document.data( "ui-dialog-overlays" ) - 1; 12956 12957 if ( !overlays ) { 12958 this.document.off( "focusin.ui-dialog" ); 12959 this.document.removeData( "ui-dialog-overlays" ); 12960 } else { 12961 this.document.data( "ui-dialog-overlays", overlays ); 12962 } 12963 12964 this.overlay.remove(); 12965 this.overlay = null; 12966 } 12967 } 12968} ); 12969 12970// DEPRECATED 12971// TODO: switch return back to widget declaration at top of file when this is removed 12972if ( $.uiBackCompat === true ) { 12973 12974 // Backcompat for dialogClass option 12975 $.widget( "ui.dialog", $.ui.dialog, { 12976 options: { 12977 dialogClass: "" 12978 }, 12979 _createWrapper: function() { 12980 this._super(); 12981 this.uiDialog.addClass( this.options.dialogClass ); 12982 }, 12983 _setOption: function( key, value ) { 12984 if ( key === "dialogClass" ) { 12985 this.uiDialog 12986 .removeClass( this.options.dialogClass ) 12987 .addClass( value ); 12988 } 12989 this._superApply( arguments ); 12990 } 12991 } ); 12992} 12993 12994var widgetsDialog = $.ui.dialog; 12995 12996 12997/*! 12998 * jQuery UI Droppable 1.14.1 12999 * https://jqueryui.com 13000 * 13001 * Copyright OpenJS Foundation and other contributors 13002 * Released under the MIT license. 13003 * https://jquery.org/license 13004 */ 13005 13006//>>label: Droppable 13007//>>group: Interactions 13008//>>description: Enables drop targets for draggable elements. 13009//>>docs: https://api.jqueryui.com/droppable/ 13010//>>demos: https://jqueryui.com/droppable/ 13011 13012 13013$.widget( "ui.droppable", { 13014 version: "1.14.1", 13015 widgetEventPrefix: "drop", 13016 options: { 13017 accept: "*", 13018 addClasses: true, 13019 greedy: false, 13020 scope: "default", 13021 tolerance: "intersect", 13022 13023 // Callbacks 13024 activate: null, 13025 deactivate: null, 13026 drop: null, 13027 out: null, 13028 over: null 13029 }, 13030 _create: function() { 13031 13032 var proportions, 13033 o = this.options, 13034 accept = o.accept; 13035 13036 this.isover = false; 13037 this.isout = true; 13038 13039 this.accept = typeof accept === "function" ? accept : function( d ) { 13040 return d.is( accept ); 13041 }; 13042 13043 this.proportions = function( /* valueToWrite */ ) { 13044 if ( arguments.length ) { 13045 13046 // Store the droppable's proportions 13047 proportions = arguments[ 0 ]; 13048 } else { 13049 13050 // Retrieve or derive the droppable's proportions 13051 return proportions ? 13052 proportions : 13053 proportions = { 13054 width: this.element[ 0 ].offsetWidth, 13055 height: this.element[ 0 ].offsetHeight 13056 }; 13057 } 13058 }; 13059 13060 this._addToManager( o.scope ); 13061 13062 if ( o.addClasses ) { 13063 this._addClass( "ui-droppable" ); 13064 } 13065 13066 }, 13067 13068 _addToManager: function( scope ) { 13069 13070 // Add the reference and positions to the manager 13071 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; 13072 $.ui.ddmanager.droppables[ scope ].push( this ); 13073 }, 13074 13075 _splice: function( drop ) { 13076 var i = 0; 13077 for ( ; i < drop.length; i++ ) { 13078 if ( drop[ i ] === this ) { 13079 drop.splice( i, 1 ); 13080 } 13081 } 13082 }, 13083 13084 _destroy: function() { 13085 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 13086 13087 this._splice( drop ); 13088 }, 13089 13090 _setOption: function( key, value ) { 13091 13092 if ( key === "accept" ) { 13093 this.accept = typeof value === "function" ? value : function( d ) { 13094 return d.is( value ); 13095 }; 13096 } else if ( key === "scope" ) { 13097 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 13098 13099 this._splice( drop ); 13100 this._addToManager( value ); 13101 } 13102 13103 this._super( key, value ); 13104 }, 13105 13106 _activate: function( event ) { 13107 var draggable = $.ui.ddmanager.current; 13108 13109 this._addActiveClass(); 13110 if ( draggable ) { 13111 this._trigger( "activate", event, this.ui( draggable ) ); 13112 } 13113 }, 13114 13115 _deactivate: function( event ) { 13116 var draggable = $.ui.ddmanager.current; 13117 13118 this._removeActiveClass(); 13119 if ( draggable ) { 13120 this._trigger( "deactivate", event, this.ui( draggable ) ); 13121 } 13122 }, 13123 13124 _over: function( event ) { 13125 13126 var draggable = $.ui.ddmanager.current; 13127 13128 // Bail if draggable and droppable are same element 13129 if ( !draggable || ( draggable.currentItem || 13130 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13131 return; 13132 } 13133 13134 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 13135 draggable.element ) ) ) { 13136 this._addHoverClass(); 13137 this._trigger( "over", event, this.ui( draggable ) ); 13138 } 13139 13140 }, 13141 13142 _out: function( event ) { 13143 13144 var draggable = $.ui.ddmanager.current; 13145 13146 // Bail if draggable and droppable are same element 13147 if ( !draggable || ( draggable.currentItem || 13148 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13149 return; 13150 } 13151 13152 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || 13153 draggable.element ) ) ) { 13154 this._removeHoverClass(); 13155 this._trigger( "out", event, this.ui( draggable ) ); 13156 } 13157 13158 }, 13159 13160 _drop: function( event, custom ) { 13161 13162 var draggable = custom || $.ui.ddmanager.current, 13163 childrenIntersection = false; 13164 13165 // Bail if draggable and droppable are same element 13166 if ( !draggable || ( draggable.currentItem || 13167 draggable.element )[ 0 ] === this.element[ 0 ] ) { 13168 return false; 13169 } 13170 13171 this.element 13172 .find( ":data(ui-droppable)" ) 13173 .not( ".ui-draggable-dragging" ) 13174 .each( function() { 13175 var inst = $( this ).droppable( "instance" ); 13176 if ( 13177 inst.options.greedy && 13178 !inst.options.disabled && 13179 inst.options.scope === draggable.options.scope && 13180 inst.accept.call( 13181 inst.element[ 0 ], ( draggable.currentItem || draggable.element ) 13182 ) && 13183 $.ui.intersect( 13184 draggable, 13185 $.extend( inst, { offset: inst.element.offset() } ), 13186 inst.options.tolerance, event 13187 ) 13188 ) { 13189 childrenIntersection = true; 13190 return false; 13191 } 13192 } ); 13193 if ( childrenIntersection ) { 13194 return false; 13195 } 13196 13197 if ( this.accept.call( this.element[ 0 ], 13198 ( draggable.currentItem || draggable.element ) ) ) { 13199 this._removeActiveClass(); 13200 this._removeHoverClass(); 13201 13202 this._trigger( "drop", event, this.ui( draggable ) ); 13203 return this.element; 13204 } 13205 13206 return false; 13207 13208 }, 13209 13210 ui: function( c ) { 13211 return { 13212 draggable: ( c.currentItem || c.element ), 13213 helper: c.helper, 13214 position: c.position, 13215 offset: c.positionAbs 13216 }; 13217 }, 13218 13219 // Extension points just to make backcompat sane and avoid duplicating logic 13220 // TODO: Remove in 1.14 along with call to it below 13221 _addHoverClass: function() { 13222 this._addClass( "ui-droppable-hover" ); 13223 }, 13224 13225 _removeHoverClass: function() { 13226 this._removeClass( "ui-droppable-hover" ); 13227 }, 13228 13229 _addActiveClass: function() { 13230 this._addClass( "ui-droppable-active" ); 13231 }, 13232 13233 _removeActiveClass: function() { 13234 this._removeClass( "ui-droppable-active" ); 13235 } 13236} ); 13237 13238$.ui.intersect = ( function() { 13239 function isOverAxis( x, reference, size ) { 13240 return ( x >= reference ) && ( x < ( reference + size ) ); 13241 } 13242 13243 return function( draggable, droppable, toleranceMode, event ) { 13244 13245 if ( !droppable.offset ) { 13246 return false; 13247 } 13248 13249 var x1 = ( draggable.positionAbs || 13250 draggable.position.absolute ).left + draggable.margins.left, 13251 y1 = ( draggable.positionAbs || 13252 draggable.position.absolute ).top + draggable.margins.top, 13253 x2 = x1 + draggable.helperProportions.width, 13254 y2 = y1 + draggable.helperProportions.height, 13255 l = droppable.offset.left, 13256 t = droppable.offset.top, 13257 r = l + droppable.proportions().width, 13258 b = t + droppable.proportions().height; 13259 13260 switch ( toleranceMode ) { 13261 case "fit": 13262 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); 13263 case "intersect": 13264 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half 13265 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half 13266 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half 13267 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half 13268 case "pointer": 13269 return isOverAxis( event.pageY, t, droppable.proportions().height ) && 13270 isOverAxis( event.pageX, l, droppable.proportions().width ); 13271 case "touch": 13272 return ( 13273 ( y1 >= t && y1 <= b ) || // Top edge touching 13274 ( y2 >= t && y2 <= b ) || // Bottom edge touching 13275 ( y1 < t && y2 > b ) // Surrounded vertically 13276 ) && ( 13277 ( x1 >= l && x1 <= r ) || // Left edge touching 13278 ( x2 >= l && x2 <= r ) || // Right edge touching 13279 ( x1 < l && x2 > r ) // Surrounded horizontally 13280 ); 13281 default: 13282 return false; 13283 } 13284 }; 13285} )(); 13286 13287/* 13288 This manager tracks offsets of draggables and droppables 13289*/ 13290$.ui.ddmanager = { 13291 current: null, 13292 droppables: { "default": [] }, 13293 prepareOffsets: function( t, event ) { 13294 13295 var i, j, 13296 m = $.ui.ddmanager.droppables[ t.options.scope ] || [], 13297 type = event ? event.type : null, // workaround for #2317 13298 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); 13299 13300 droppablesLoop: for ( i = 0; i < m.length; i++ ) { 13301 13302 // No disabled and non-accepted 13303 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], 13304 ( t.currentItem || t.element ) ) ) ) { 13305 continue; 13306 } 13307 13308 // Filter out elements in the current dragged item 13309 for ( j = 0; j < list.length; j++ ) { 13310 if ( list[ j ] === m[ i ].element[ 0 ] ) { 13311 m[ i ].proportions().height = 0; 13312 continue droppablesLoop; 13313 } 13314 } 13315 13316 m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; 13317 if ( !m[ i ].visible ) { 13318 continue; 13319 } 13320 13321 // Activate the droppable if used directly from draggables 13322 if ( type === "mousedown" ) { 13323 m[ i ]._activate.call( m[ i ], event ); 13324 } 13325 13326 m[ i ].offset = m[ i ].element.offset(); 13327 m[ i ].proportions( { 13328 width: m[ i ].element[ 0 ].offsetWidth, 13329 height: m[ i ].element[ 0 ].offsetHeight 13330 } ); 13331 13332 } 13333 13334 }, 13335 drop: function( draggable, event ) { 13336 13337 var dropped = false; 13338 13339 // Create a copy of the droppables in case the list changes during the drop (#9116) 13340 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { 13341 13342 if ( !this.options ) { 13343 return; 13344 } 13345 if ( !this.options.disabled && this.visible && 13346 $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { 13347 dropped = this._drop.call( this, event ) || dropped; 13348 } 13349 13350 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], 13351 ( draggable.currentItem || draggable.element ) ) ) { 13352 this.isout = true; 13353 this.isover = false; 13354 this._deactivate.call( this, event ); 13355 } 13356 13357 } ); 13358 return dropped; 13359 13360 }, 13361 dragStart: function( draggable, event ) { 13362 13363 // Listen for scrolling so that if the dragging causes scrolling the position of the 13364 // droppables can be recalculated (see #5003) 13365 draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() { 13366 if ( !draggable.options.refreshPositions ) { 13367 $.ui.ddmanager.prepareOffsets( draggable, event ); 13368 } 13369 } ); 13370 }, 13371 drag: function( draggable, event ) { 13372 13373 // If you have a highly dynamic page, you might try this option. It renders positions 13374 // every time you move the mouse. 13375 if ( draggable.options.refreshPositions ) { 13376 $.ui.ddmanager.prepareOffsets( draggable, event ); 13377 } 13378 13379 // Run through all droppables and check their positions based on specific tolerance options 13380 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { 13381 13382 if ( this.options.disabled || this.greedyChild || !this.visible ) { 13383 return; 13384 } 13385 13386 var parentInstance, scope, parent, 13387 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), 13388 c = !intersects && this.isover ? 13389 "isout" : 13390 ( intersects && !this.isover ? "isover" : null ); 13391 if ( !c ) { 13392 return; 13393 } 13394 13395 if ( this.options.greedy ) { 13396 13397 // find droppable parents with same scope 13398 scope = this.options.scope; 13399 parent = this.element.parents( ":data(ui-droppable)" ).filter( function() { 13400 return $( this ).droppable( "instance" ).options.scope === scope; 13401 } ); 13402 13403 if ( parent.length ) { 13404 parentInstance = $( parent[ 0 ] ).droppable( "instance" ); 13405 parentInstance.greedyChild = ( c === "isover" ); 13406 } 13407 } 13408 13409 // We just moved into a greedy child 13410 if ( parentInstance && c === "isover" ) { 13411 parentInstance.isover = false; 13412 parentInstance.isout = true; 13413 parentInstance._out.call( parentInstance, event ); 13414 } 13415 13416 this[ c ] = true; 13417 this[ c === "isout" ? "isover" : "isout" ] = false; 13418 this[ c === "isover" ? "_over" : "_out" ].call( this, event ); 13419 13420 // We just moved out of a greedy child 13421 if ( parentInstance && c === "isout" ) { 13422 parentInstance.isout = false; 13423 parentInstance.isover = true; 13424 parentInstance._over.call( parentInstance, event ); 13425 } 13426 } ); 13427 13428 }, 13429 dragStop: function( draggable, event ) { 13430 draggable.element.parentsUntil( "body" ).off( "scroll.droppable" ); 13431 13432 // Call prepareOffsets one final time since IE does not fire return scroll events when 13433 // overflow was caused by drag (see #5003) 13434 if ( !draggable.options.refreshPositions ) { 13435 $.ui.ddmanager.prepareOffsets( draggable, event ); 13436 } 13437 } 13438}; 13439 13440// DEPRECATED 13441// TODO: switch return back to widget declaration at top of file when this is removed 13442if ( $.uiBackCompat === true ) { 13443 13444 // Backcompat for activeClass and hoverClass options 13445 $.widget( "ui.droppable", $.ui.droppable, { 13446 options: { 13447 hoverClass: false, 13448 activeClass: false 13449 }, 13450 _addActiveClass: function() { 13451 this._super(); 13452 if ( this.options.activeClass ) { 13453 this.element.addClass( this.options.activeClass ); 13454 } 13455 }, 13456 _removeActiveClass: function() { 13457 this._super(); 13458 if ( this.options.activeClass ) { 13459 this.element.removeClass( this.options.activeClass ); 13460 } 13461 }, 13462 _addHoverClass: function() { 13463 this._super(); 13464 if ( this.options.hoverClass ) { 13465 this.element.addClass( this.options.hoverClass ); 13466 } 13467 }, 13468 _removeHoverClass: function() { 13469 this._super(); 13470 if ( this.options.hoverClass ) { 13471 this.element.removeClass( this.options.hoverClass ); 13472 } 13473 } 13474 } ); 13475} 13476 13477var widgetsDroppable = $.ui.droppable; 13478 13479 13480/*! 13481 * jQuery UI Progressbar 1.14.1 13482 * https://jqueryui.com 13483 * 13484 * Copyright OpenJS Foundation and other contributors 13485 * Released under the MIT license. 13486 * https://jquery.org/license 13487 */ 13488 13489//>>label: Progressbar 13490//>>group: Widgets 13491/* eslint-disable max-len */ 13492//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators. 13493/* eslint-enable max-len */ 13494//>>docs: https://api.jqueryui.com/progressbar/ 13495//>>demos: https://jqueryui.com/progressbar/ 13496//>>css.structure: ../../themes/base/core.css 13497//>>css.structure: ../../themes/base/progressbar.css 13498//>>css.theme: ../../themes/base/theme.css 13499 13500 13501var widgetsProgressbar = $.widget( "ui.progressbar", { 13502 version: "1.14.1", 13503 options: { 13504 classes: { 13505 "ui-progressbar": "ui-corner-all", 13506 "ui-progressbar-value": "ui-corner-left", 13507 "ui-progressbar-complete": "ui-corner-right" 13508 }, 13509 max: 100, 13510 value: 0, 13511 13512 change: null, 13513 complete: null 13514 }, 13515 13516 min: 0, 13517 13518 _create: function() { 13519 13520 // Constrain initial value 13521 this.oldValue = this.options.value = this._constrainedValue(); 13522 13523 this.element.attr( { 13524 13525 // Only set static values; aria-valuenow and aria-valuemax are 13526 // set inside _refreshValue() 13527 role: "progressbar", 13528 "aria-valuemin": this.min 13529 } ); 13530 this._addClass( "ui-progressbar", "ui-widget ui-widget-content" ); 13531 13532 this.valueDiv = $( "<div>" ).appendTo( this.element ); 13533 this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" ); 13534 this._refreshValue(); 13535 }, 13536 13537 _destroy: function() { 13538 this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" ); 13539 13540 this.valueDiv.remove(); 13541 }, 13542 13543 value: function( newValue ) { 13544 if ( newValue === undefined ) { 13545 return this.options.value; 13546 } 13547 13548 this.options.value = this._constrainedValue( newValue ); 13549 this._refreshValue(); 13550 }, 13551 13552 _constrainedValue: function( newValue ) { 13553 if ( newValue === undefined ) { 13554 newValue = this.options.value; 13555 } 13556 13557 this.indeterminate = newValue === false; 13558 13559 // Sanitize value 13560 if ( typeof newValue !== "number" ) { 13561 newValue = 0; 13562 } 13563 13564 return this.indeterminate ? false : 13565 Math.min( this.options.max, Math.max( this.min, newValue ) ); 13566 }, 13567 13568 _setOptions: function( options ) { 13569 13570 // Ensure "value" option is set after other values (like max) 13571 var value = options.value; 13572 delete options.value; 13573 13574 this._super( options ); 13575 13576 this.options.value = this._constrainedValue( value ); 13577 this._refreshValue(); 13578 }, 13579 13580 _setOption: function( key, value ) { 13581 if ( key === "max" ) { 13582 13583 // Don't allow a max less than min 13584 value = Math.max( this.min, value ); 13585 } 13586 this._super( key, value ); 13587 }, 13588 13589 _setOptionDisabled: function( value ) { 13590 this._super( value ); 13591 13592 this.element.attr( "aria-disabled", value ); 13593 this._toggleClass( null, "ui-state-disabled", !!value ); 13594 }, 13595 13596 _percentage: function() { 13597 return this.indeterminate ? 13598 100 : 13599 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); 13600 }, 13601 13602 _refreshValue: function() { 13603 var value = this.options.value, 13604 percentage = this._percentage(); 13605 13606 this.valueDiv 13607 .toggle( this.indeterminate || value > this.min ) 13608 .width( percentage.toFixed( 0 ) + "%" ); 13609 13610 this 13611 ._toggleClass( this.valueDiv, "ui-progressbar-complete", null, 13612 value === this.options.max ) 13613 ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate ); 13614 13615 if ( this.indeterminate ) { 13616 this.element.removeAttr( "aria-valuenow" ); 13617 if ( !this.overlayDiv ) { 13618 this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv ); 13619 this._addClass( this.overlayDiv, "ui-progressbar-overlay" ); 13620 } 13621 } else { 13622 this.element.attr( { 13623 "aria-valuemax": this.options.max, 13624 "aria-valuenow": value 13625 } ); 13626 if ( this.overlayDiv ) { 13627 this.overlayDiv.remove(); 13628 this.overlayDiv = null; 13629 } 13630 } 13631 13632 if ( this.oldValue !== value ) { 13633 this.oldValue = value; 13634 this._trigger( "change" ); 13635 } 13636 if ( value === this.options.max ) { 13637 this._trigger( "complete" ); 13638 } 13639 } 13640} ); 13641 13642 13643/*! 13644 * jQuery UI Selectable 1.14.1 13645 * https://jqueryui.com 13646 * 13647 * Copyright OpenJS Foundation and other contributors 13648 * Released under the MIT license. 13649 * https://jquery.org/license 13650 */ 13651 13652//>>label: Selectable 13653//>>group: Interactions 13654//>>description: Allows groups of elements to be selected with the mouse. 13655//>>docs: https://api.jqueryui.com/selectable/ 13656//>>demos: https://jqueryui.com/selectable/ 13657//>>css.structure: ../../themes/base/selectable.css 13658 13659 13660var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, { 13661 version: "1.14.1", 13662 options: { 13663 appendTo: "body", 13664 autoRefresh: true, 13665 distance: 0, 13666 filter: "*", 13667 tolerance: "touch", 13668 13669 // Callbacks 13670 selected: null, 13671 selecting: null, 13672 start: null, 13673 stop: null, 13674 unselected: null, 13675 unselecting: null 13676 }, 13677 _create: function() { 13678 var that = this; 13679 13680 this._addClass( "ui-selectable" ); 13681 13682 this.dragged = false; 13683 13684 // Cache selectee children based on filter 13685 this.refresh = function() { 13686 that.elementPos = $( that.element[ 0 ] ).offset(); 13687 that.selectees = $( that.options.filter, that.element[ 0 ] ); 13688 that._addClass( that.selectees, "ui-selectee" ); 13689 that.selectees.each( function() { 13690 var $this = $( this ), 13691 selecteeOffset = $this.offset(), 13692 pos = { 13693 left: selecteeOffset.left - that.elementPos.left, 13694 top: selecteeOffset.top - that.elementPos.top 13695 }; 13696 $.data( this, "selectable-item", { 13697 element: this, 13698 $element: $this, 13699 left: pos.left, 13700 top: pos.top, 13701 right: pos.left + $this.outerWidth(), 13702 bottom: pos.top + $this.outerHeight(), 13703 startselected: false, 13704 selected: $this.hasClass( "ui-selected" ), 13705 selecting: $this.hasClass( "ui-selecting" ), 13706 unselecting: $this.hasClass( "ui-unselecting" ) 13707 } ); 13708 } ); 13709 }; 13710 this.refresh(); 13711 13712 this._mouseInit(); 13713 13714 this.helper = $( "<div>" ); 13715 this._addClass( this.helper, "ui-selectable-helper" ); 13716 }, 13717 13718 _destroy: function() { 13719 this.selectees.removeData( "selectable-item" ); 13720 this._mouseDestroy(); 13721 }, 13722 13723 _mouseStart: function( event ) { 13724 var that = this, 13725 options = this.options; 13726 13727 this.opos = [ event.pageX, event.pageY ]; 13728 this.elementPos = $( this.element[ 0 ] ).offset(); 13729 13730 if ( this.options.disabled ) { 13731 return; 13732 } 13733 13734 this.selectees = $( options.filter, this.element[ 0 ] ); 13735 13736 this._trigger( "start", event ); 13737 13738 $( options.appendTo ).append( this.helper ); 13739 13740 // position helper (lasso) 13741 this.helper.css( { 13742 "left": event.pageX, 13743 "top": event.pageY, 13744 "width": 0, 13745 "height": 0 13746 } ); 13747 13748 if ( options.autoRefresh ) { 13749 this.refresh(); 13750 } 13751 13752 this.selectees.filter( ".ui-selected" ).each( function() { 13753 var selectee = $.data( this, "selectable-item" ); 13754 selectee.startselected = true; 13755 if ( !event.metaKey && !event.ctrlKey ) { 13756 that._removeClass( selectee.$element, "ui-selected" ); 13757 selectee.selected = false; 13758 that._addClass( selectee.$element, "ui-unselecting" ); 13759 selectee.unselecting = true; 13760 13761 // selectable UNSELECTING callback 13762 that._trigger( "unselecting", event, { 13763 unselecting: selectee.element 13764 } ); 13765 } 13766 } ); 13767 13768 $( event.target ).parents().addBack().each( function() { 13769 var doSelect, 13770 selectee = $.data( this, "selectable-item" ); 13771 if ( selectee ) { 13772 doSelect = ( !event.metaKey && !event.ctrlKey ) || 13773 !selectee.$element.hasClass( "ui-selected" ); 13774 that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" ) 13775 ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" ); 13776 selectee.unselecting = !doSelect; 13777 selectee.selecting = doSelect; 13778 selectee.selected = doSelect; 13779 13780 // selectable (UN)SELECTING callback 13781 if ( doSelect ) { 13782 that._trigger( "selecting", event, { 13783 selecting: selectee.element 13784 } ); 13785 } else { 13786 that._trigger( "unselecting", event, { 13787 unselecting: selectee.element 13788 } ); 13789 } 13790 return false; 13791 } 13792 } ); 13793 13794 }, 13795 13796 _mouseDrag: function( event ) { 13797 13798 this.dragged = true; 13799 13800 if ( this.options.disabled ) { 13801 return; 13802 } 13803 13804 var tmp, 13805 that = this, 13806 options = this.options, 13807 x1 = this.opos[ 0 ], 13808 y1 = this.opos[ 1 ], 13809 x2 = event.pageX, 13810 y2 = event.pageY; 13811 13812 if ( x1 > x2 ) { 13813 tmp = x2; x2 = x1; x1 = tmp; 13814 } 13815 if ( y1 > y2 ) { 13816 tmp = y2; y2 = y1; y1 = tmp; 13817 } 13818 this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } ); 13819 13820 this.selectees.each( function() { 13821 var selectee = $.data( this, "selectable-item" ), 13822 hit = false, 13823 offset = {}; 13824 13825 //prevent helper from being selected if appendTo: selectable 13826 if ( !selectee || selectee.element === that.element[ 0 ] ) { 13827 return; 13828 } 13829 13830 offset.left = selectee.left + that.elementPos.left; 13831 offset.right = selectee.right + that.elementPos.left; 13832 offset.top = selectee.top + that.elementPos.top; 13833 offset.bottom = selectee.bottom + that.elementPos.top; 13834 13835 if ( options.tolerance === "touch" ) { 13836 hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 || 13837 offset.bottom < y1 ) ); 13838 } else if ( options.tolerance === "fit" ) { 13839 hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 && 13840 offset.bottom < y2 ); 13841 } 13842 13843 if ( hit ) { 13844 13845 // SELECT 13846 if ( selectee.selected ) { 13847 that._removeClass( selectee.$element, "ui-selected" ); 13848 selectee.selected = false; 13849 } 13850 if ( selectee.unselecting ) { 13851 that._removeClass( selectee.$element, "ui-unselecting" ); 13852 selectee.unselecting = false; 13853 } 13854 if ( !selectee.selecting ) { 13855 that._addClass( selectee.$element, "ui-selecting" ); 13856 selectee.selecting = true; 13857 13858 // selectable SELECTING callback 13859 that._trigger( "selecting", event, { 13860 selecting: selectee.element 13861 } ); 13862 } 13863 } else { 13864 13865 // UNSELECT 13866 if ( selectee.selecting ) { 13867 if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) { 13868 that._removeClass( selectee.$element, "ui-selecting" ); 13869 selectee.selecting = false; 13870 that._addClass( selectee.$element, "ui-selected" ); 13871 selectee.selected = true; 13872 } else { 13873 that._removeClass( selectee.$element, "ui-selecting" ); 13874 selectee.selecting = false; 13875 if ( selectee.startselected ) { 13876 that._addClass( selectee.$element, "ui-unselecting" ); 13877 selectee.unselecting = true; 13878 } 13879 13880 // selectable UNSELECTING callback 13881 that._trigger( "unselecting", event, { 13882 unselecting: selectee.element 13883 } ); 13884 } 13885 } 13886 if ( selectee.selected ) { 13887 if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) { 13888 that._removeClass( selectee.$element, "ui-selected" ); 13889 selectee.selected = false; 13890 13891 that._addClass( selectee.$element, "ui-unselecting" ); 13892 selectee.unselecting = true; 13893 13894 // selectable UNSELECTING callback 13895 that._trigger( "unselecting", event, { 13896 unselecting: selectee.element 13897 } ); 13898 } 13899 } 13900 } 13901 } ); 13902 13903 return false; 13904 }, 13905 13906 _mouseStop: function( event ) { 13907 var that = this; 13908 13909 this.dragged = false; 13910 13911 $( ".ui-unselecting", this.element[ 0 ] ).each( function() { 13912 var selectee = $.data( this, "selectable-item" ); 13913 that._removeClass( selectee.$element, "ui-unselecting" ); 13914 selectee.unselecting = false; 13915 selectee.startselected = false; 13916 that._trigger( "unselected", event, { 13917 unselected: selectee.element 13918 } ); 13919 } ); 13920 $( ".ui-selecting", this.element[ 0 ] ).each( function() { 13921 var selectee = $.data( this, "selectable-item" ); 13922 that._removeClass( selectee.$element, "ui-selecting" ) 13923 ._addClass( selectee.$element, "ui-selected" ); 13924 selectee.selecting = false; 13925 selectee.selected = true; 13926 selectee.startselected = true; 13927 that._trigger( "selected", event, { 13928 selected: selectee.element 13929 } ); 13930 } ); 13931 this._trigger( "stop", event ); 13932 13933 this.helper.remove(); 13934 13935 return false; 13936 } 13937 13938} ); 13939 13940 13941/*! 13942 * jQuery UI Selectmenu 1.14.1 13943 * https://jqueryui.com 13944 * 13945 * Copyright OpenJS Foundation and other contributors 13946 * Released under the MIT license. 13947 * https://jquery.org/license 13948 */ 13949 13950//>>label: Selectmenu 13951//>>group: Widgets 13952/* eslint-disable max-len */ 13953//>>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. 13954/* eslint-enable max-len */ 13955//>>docs: https://api.jqueryui.com/selectmenu/ 13956//>>demos: https://jqueryui.com/selectmenu/ 13957//>>css.structure: ../../themes/base/core.css 13958//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css 13959//>>css.theme: ../../themes/base/theme.css 13960 13961 13962var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, { 13963 version: "1.14.1", 13964 defaultElement: "<select>", 13965 options: { 13966 appendTo: null, 13967 classes: { 13968 "ui-selectmenu-button-open": "ui-corner-top", 13969 "ui-selectmenu-button-closed": "ui-corner-all" 13970 }, 13971 disabled: null, 13972 icons: { 13973 button: "ui-icon-triangle-1-s" 13974 }, 13975 position: { 13976 my: "left top", 13977 at: "left bottom", 13978 collision: "none" 13979 }, 13980 width: false, 13981 13982 // Callbacks 13983 change: null, 13984 close: null, 13985 focus: null, 13986 open: null, 13987 select: null 13988 }, 13989 13990 _create: function() { 13991 var selectmenuId = this.element.uniqueId().attr( "id" ); 13992 this.ids = { 13993 element: selectmenuId, 13994 button: selectmenuId + "-button", 13995 menu: selectmenuId + "-menu" 13996 }; 13997 13998 this._drawButton(); 13999 this._drawMenu(); 14000 this._bindFormResetHandler(); 14001 14002 this._rendered = false; 14003 this.menuItems = $(); 14004 }, 14005 14006 _drawButton: function() { 14007 var icon, 14008 that = this, 14009 item = this._parseOption( 14010 this.element.find( "option:selected" ), 14011 this.element[ 0 ].selectedIndex 14012 ); 14013 14014 // Associate existing label with the new button 14015 this.labels = this.element.labels().attr( "for", this.ids.button ); 14016 this._on( this.labels, { 14017 click: function( event ) { 14018 this.button.trigger( "focus" ); 14019 event.preventDefault(); 14020 } 14021 } ); 14022 14023 // Hide original select element 14024 this.element.hide(); 14025 14026 // Create button 14027 this.button = $( "<span>", { 14028 tabindex: this.options.disabled ? -1 : 0, 14029 id: this.ids.button, 14030 role: "combobox", 14031 "aria-expanded": "false", 14032 "aria-autocomplete": "list", 14033 "aria-owns": this.ids.menu, 14034 "aria-haspopup": "true", 14035 title: this.element.attr( "title" ) 14036 } ) 14037 .insertAfter( this.element ); 14038 14039 this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed", 14040 "ui-button ui-widget" ); 14041 14042 icon = $( "<span>" ).appendTo( this.button ); 14043 this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button ); 14044 this.buttonItem = this._renderButtonItem( item ) 14045 .appendTo( this.button ); 14046 14047 if ( this.options.width !== false ) { 14048 this._resizeButton(); 14049 } 14050 14051 this._on( this.button, this._buttonEvents ); 14052 this.button.one( "focusin", function() { 14053 14054 // Delay rendering the menu items until the button receives focus. 14055 // The menu may have already been rendered via a programmatic open. 14056 if ( !that._rendered ) { 14057 that._refreshMenu(); 14058 } 14059 } ); 14060 }, 14061 14062 _drawMenu: function() { 14063 var that = this; 14064 14065 // Create menu 14066 this.menu = $( "<ul>", { 14067 "aria-hidden": "true", 14068 "aria-labelledby": this.ids.button, 14069 id: this.ids.menu 14070 } ); 14071 14072 // Wrap menu 14073 this.menuWrap = $( "<div>" ).append( this.menu ); 14074 this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" ); 14075 this.menuWrap.appendTo( this._appendTo() ); 14076 14077 // Initialize menu widget 14078 this.menuInstance = this.menu 14079 .menu( { 14080 classes: { 14081 "ui-menu": "ui-corner-bottom" 14082 }, 14083 role: "listbox", 14084 select: function( event, ui ) { 14085 event.preventDefault(); 14086 that._select( ui.item.data( "ui-selectmenu-item" ), event ); 14087 }, 14088 focus: function( event, ui ) { 14089 var item = ui.item.data( "ui-selectmenu-item" ); 14090 14091 // Prevent inital focus from firing and check if its a newly focused item 14092 if ( that.focusIndex != null && item.index !== that.focusIndex ) { 14093 that._trigger( "focus", event, { item: item } ); 14094 if ( !that.isOpen ) { 14095 that._select( item, event ); 14096 } 14097 } 14098 that.focusIndex = item.index; 14099 14100 that.button.attr( "aria-activedescendant", 14101 that.menuItems.eq( item.index ).attr( "id" ) ); 14102 } 14103 } ) 14104 .menu( "instance" ); 14105 14106 // Don't close the menu on mouseleave 14107 this.menuInstance._off( this.menu, "mouseleave" ); 14108 14109 // Cancel the menu's collapseAll on document click 14110 this.menuInstance._closeOnDocumentClick = function() { 14111 return false; 14112 }; 14113 14114 // Selects often contain empty items, but never contain dividers 14115 this.menuInstance._isDivider = function() { 14116 return false; 14117 }; 14118 }, 14119 14120 refresh: function() { 14121 this._refreshMenu(); 14122 this.buttonItem.replaceWith( 14123 this.buttonItem = this._renderButtonItem( 14124 14125 // Fall back to an empty object in case there are no options 14126 this._getSelectedItem().data( "ui-selectmenu-item" ) || {} 14127 ) 14128 ); 14129 if ( this.options.width === null ) { 14130 this._resizeButton(); 14131 } 14132 }, 14133 14134 _refreshMenu: function() { 14135 var item, 14136 options = this.element.find( "option" ); 14137 14138 this.menu.empty(); 14139 14140 this._parseOptions( options ); 14141 this._renderMenu( this.menu, this.items ); 14142 14143 this.menuInstance.refresh(); 14144 this.menuItems = this.menu.find( "li" ) 14145 .not( ".ui-selectmenu-optgroup" ) 14146 .find( ".ui-menu-item-wrapper" ); 14147 14148 this._rendered = true; 14149 14150 if ( !options.length ) { 14151 return; 14152 } 14153 14154 item = this._getSelectedItem(); 14155 14156 // Update the menu to have the correct item focused 14157 this.menuInstance.focus( null, item ); 14158 this._setAria( item.data( "ui-selectmenu-item" ) ); 14159 14160 // Set disabled state 14161 this._setOption( "disabled", this.element.prop( "disabled" ) ); 14162 }, 14163 14164 open: function( event ) { 14165 if ( this.options.disabled ) { 14166 return; 14167 } 14168 14169 // If this is the first time the menu is being opened, render the items 14170 if ( !this._rendered ) { 14171 this._refreshMenu(); 14172 } else { 14173 14174 // Menu clears focus on close, reset focus to selected item 14175 this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" ); 14176 this.menuInstance.focus( null, this._getSelectedItem() ); 14177 } 14178 14179 // If there are no options, don't open the menu 14180 if ( !this.menuItems.length ) { 14181 return; 14182 } 14183 14184 this.isOpen = true; 14185 this._toggleAttr(); 14186 this._resizeMenu(); 14187 this._position(); 14188 14189 this._on( this.document, this._documentClick ); 14190 14191 this._trigger( "open", event ); 14192 }, 14193 14194 _position: function() { 14195 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); 14196 }, 14197 14198 close: function( event ) { 14199 if ( !this.isOpen ) { 14200 return; 14201 } 14202 14203 this.isOpen = false; 14204 this._toggleAttr(); 14205 14206 this.range = null; 14207 this._off( this.document ); 14208 14209 this._trigger( "close", event ); 14210 }, 14211 14212 widget: function() { 14213 return this.button; 14214 }, 14215 14216 menuWidget: function() { 14217 return this.menu; 14218 }, 14219 14220 _renderButtonItem: function( item ) { 14221 var buttonItem = $( "<span>" ); 14222 14223 this._setText( buttonItem, item.label ); 14224 this._addClass( buttonItem, "ui-selectmenu-text" ); 14225 14226 return buttonItem; 14227 }, 14228 14229 _renderMenu: function( ul, items ) { 14230 var that = this, 14231 currentOptgroup = ""; 14232 14233 $.each( items, function( index, item ) { 14234 var li; 14235 14236 if ( item.optgroup !== currentOptgroup ) { 14237 li = $( "<li>", { 14238 text: item.optgroup 14239 } ); 14240 that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" + 14241 ( item.element.parent( "optgroup" ).prop( "disabled" ) ? 14242 " ui-state-disabled" : 14243 "" ) ); 14244 14245 li.appendTo( ul ); 14246 14247 currentOptgroup = item.optgroup; 14248 } 14249 14250 that._renderItemData( ul, item ); 14251 } ); 14252 }, 14253 14254 _renderItemData: function( ul, item ) { 14255 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); 14256 }, 14257 14258 _renderItem: function( ul, item ) { 14259 var li = $( "<li>" ), 14260 wrapper = $( "<div>", { 14261 title: item.element.attr( "title" ) 14262 } ); 14263 14264 if ( item.disabled ) { 14265 this._addClass( li, null, "ui-state-disabled" ); 14266 } 14267 14268 if ( item.hidden ) { 14269 li.prop( "hidden", true ); 14270 } else { 14271 this._setText( wrapper, item.label ); 14272 } 14273 14274 return li.append( wrapper ).appendTo( ul ); 14275 }, 14276 14277 _setText: function( element, value ) { 14278 if ( value ) { 14279 element.text( value ); 14280 } else { 14281 element.html( " " ); 14282 } 14283 }, 14284 14285 _move: function( direction, event ) { 14286 var item, next, 14287 filter = ".ui-menu-item"; 14288 14289 if ( this.isOpen ) { 14290 item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14291 } else { 14292 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14293 filter += ":not(.ui-state-disabled)"; 14294 } 14295 14296 if ( direction === "first" || direction === "last" ) { 14297 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); 14298 } else { 14299 next = item[ direction + "All" ]( filter ).eq( 0 ); 14300 } 14301 14302 if ( next.length ) { 14303 this.menuInstance.focus( event, next ); 14304 } 14305 }, 14306 14307 _getSelectedItem: function() { 14308 return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" ); 14309 }, 14310 14311 _toggle: function( event ) { 14312 this[ this.isOpen ? "close" : "open" ]( event ); 14313 }, 14314 14315 _setSelection: function() { 14316 var selection; 14317 14318 if ( !this.range ) { 14319 return; 14320 } 14321 14322 selection = window.getSelection(); 14323 selection.removeAllRanges(); 14324 selection.addRange( this.range ); 14325 }, 14326 14327 _documentClick: { 14328 mousedown: function( event ) { 14329 if ( !this.isOpen ) { 14330 return; 14331 } 14332 14333 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + 14334 CSS.escape( this.ids.button ) ).length ) { 14335 this.close( event ); 14336 } 14337 } 14338 }, 14339 14340 _buttonEvents: { 14341 14342 // Prevent text selection from being reset when interacting with the selectmenu (#10144) 14343 mousedown: function() { 14344 var selection = window.getSelection(); 14345 if ( selection.rangeCount ) { 14346 this.range = selection.getRangeAt( 0 ); 14347 } 14348 }, 14349 14350 click: function( event ) { 14351 this._setSelection(); 14352 this._toggle( event ); 14353 }, 14354 14355 keydown: function( event ) { 14356 var preventDefault = true; 14357 switch ( event.keyCode ) { 14358 case $.ui.keyCode.TAB: 14359 case $.ui.keyCode.ESCAPE: 14360 this.close( event ); 14361 preventDefault = false; 14362 break; 14363 case $.ui.keyCode.ENTER: 14364 if ( this.isOpen ) { 14365 this._selectFocusedItem( event ); 14366 } 14367 break; 14368 case $.ui.keyCode.UP: 14369 if ( event.altKey ) { 14370 this._toggle( event ); 14371 } else { 14372 this._move( "prev", event ); 14373 } 14374 break; 14375 case $.ui.keyCode.DOWN: 14376 if ( event.altKey ) { 14377 this._toggle( event ); 14378 } else { 14379 this._move( "next", event ); 14380 } 14381 break; 14382 case $.ui.keyCode.SPACE: 14383 if ( this.isOpen ) { 14384 this._selectFocusedItem( event ); 14385 } else { 14386 this._toggle( event ); 14387 } 14388 break; 14389 case $.ui.keyCode.LEFT: 14390 this._move( "prev", event ); 14391 break; 14392 case $.ui.keyCode.RIGHT: 14393 this._move( "next", event ); 14394 break; 14395 case $.ui.keyCode.HOME: 14396 case $.ui.keyCode.PAGE_UP: 14397 this._move( "first", event ); 14398 break; 14399 case $.ui.keyCode.END: 14400 case $.ui.keyCode.PAGE_DOWN: 14401 this._move( "last", event ); 14402 break; 14403 default: 14404 this.menu.trigger( event ); 14405 preventDefault = false; 14406 } 14407 14408 if ( preventDefault ) { 14409 event.preventDefault(); 14410 } 14411 } 14412 }, 14413 14414 _selectFocusedItem: function( event ) { 14415 var item = this.menuItems.eq( this.focusIndex ).parent( "li" ); 14416 if ( !item.hasClass( "ui-state-disabled" ) ) { 14417 this._select( item.data( "ui-selectmenu-item" ), event ); 14418 } 14419 }, 14420 14421 _select: function( item, event ) { 14422 var oldIndex = this.element[ 0 ].selectedIndex; 14423 14424 // Change native select element 14425 this.element[ 0 ].selectedIndex = item.index; 14426 this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) ); 14427 this._setAria( item ); 14428 this._trigger( "select", event, { item: item } ); 14429 14430 if ( item.index !== oldIndex ) { 14431 this._trigger( "change", event, { item: item } ); 14432 } 14433 14434 this.close( event ); 14435 }, 14436 14437 _setAria: function( item ) { 14438 var id = this.menuItems.eq( item.index ).attr( "id" ); 14439 14440 this.button.attr( { 14441 "aria-labelledby": id, 14442 "aria-activedescendant": id 14443 } ); 14444 this.menu.attr( "aria-activedescendant", id ); 14445 }, 14446 14447 _setOption: function( key, value ) { 14448 if ( key === "icons" ) { 14449 var icon = this.button.find( "span.ui-icon" ); 14450 this._removeClass( icon, null, this.options.icons.button ) 14451 ._addClass( icon, null, value.button ); 14452 } 14453 14454 this._super( key, value ); 14455 14456 if ( key === "appendTo" ) { 14457 this.menuWrap.appendTo( this._appendTo() ); 14458 } 14459 14460 if ( key === "width" ) { 14461 this._resizeButton(); 14462 } 14463 }, 14464 14465 _setOptionDisabled: function( value ) { 14466 this._super( value ); 14467 14468 this.menuInstance.option( "disabled", value ); 14469 this.button.attr( "aria-disabled", value ); 14470 this._toggleClass( this.button, null, "ui-state-disabled", value ); 14471 14472 this.element.prop( "disabled", value ); 14473 if ( value ) { 14474 this.button.attr( "tabindex", -1 ); 14475 this.close(); 14476 } else { 14477 this.button.attr( "tabindex", 0 ); 14478 } 14479 }, 14480 14481 _appendTo: function() { 14482 var element = this.options.appendTo; 14483 14484 if ( element ) { 14485 element = element.jquery || element.nodeType ? 14486 $( element ) : 14487 this.document.find( element ).eq( 0 ); 14488 } 14489 14490 if ( !element || !element[ 0 ] ) { 14491 element = this.element.closest( ".ui-front, dialog" ); 14492 } 14493 14494 if ( !element.length ) { 14495 element = this.document[ 0 ].body; 14496 } 14497 14498 return element; 14499 }, 14500 14501 _toggleAttr: function() { 14502 this.button.attr( "aria-expanded", this.isOpen ); 14503 14504 // We can't use two _toggleClass() calls here, because we need to make sure 14505 // we always remove classes first and add them second, otherwise if both classes have the 14506 // same theme class, it will be removed after we add it. 14507 this._removeClass( this.button, "ui-selectmenu-button-" + 14508 ( this.isOpen ? "closed" : "open" ) ) 14509 ._addClass( this.button, "ui-selectmenu-button-" + 14510 ( this.isOpen ? "open" : "closed" ) ) 14511 ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen ); 14512 14513 this.menu.attr( "aria-hidden", !this.isOpen ); 14514 }, 14515 14516 _resizeButton: function() { 14517 var width = this.options.width; 14518 14519 // For `width: false`, just remove inline style and stop 14520 if ( width === false ) { 14521 this.button.css( "width", "" ); 14522 return; 14523 } 14524 14525 // For `width: null`, match the width of the original element 14526 if ( width === null ) { 14527 width = this.element.show().outerWidth(); 14528 this.element.hide(); 14529 } 14530 14531 this.button.outerWidth( width ); 14532 }, 14533 14534 _resizeMenu: function() { 14535 this.menu.outerWidth( Math.max( 14536 this.button.outerWidth(), 14537 this.menu.width( "" ).outerWidth() 14538 ) ); 14539 }, 14540 14541 _getCreateOptions: function() { 14542 var options = this._super(); 14543 14544 options.disabled = this.element.prop( "disabled" ); 14545 14546 return options; 14547 }, 14548 14549 _parseOptions: function( options ) { 14550 var that = this, 14551 data = []; 14552 options.each( function( index, item ) { 14553 data.push( that._parseOption( $( item ), index ) ); 14554 } ); 14555 this.items = data; 14556 }, 14557 14558 _parseOption: function( option, index ) { 14559 var optgroup = option.parent( "optgroup" ); 14560 14561 return { 14562 element: option, 14563 index: index, 14564 value: option.val(), 14565 label: option.text(), 14566 hidden: optgroup.prop( "hidden" ) || option.prop( "hidden" ), 14567 optgroup: optgroup.attr( "label" ) || "", 14568 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) 14569 }; 14570 }, 14571 14572 _destroy: function() { 14573 this._unbindFormResetHandler(); 14574 this.menuWrap.remove(); 14575 this.button.remove(); 14576 this.element.show(); 14577 this.element.removeUniqueId(); 14578 this.labels.attr( "for", this.ids.element ); 14579 } 14580} ] ); 14581 14582 14583/*! 14584 * jQuery UI Slider 1.14.1 14585 * https://jqueryui.com 14586 * 14587 * Copyright OpenJS Foundation and other contributors 14588 * Released under the MIT license. 14589 * https://jquery.org/license 14590 */ 14591 14592//>>label: Slider 14593//>>group: Widgets 14594//>>description: Displays a flexible slider with ranges and accessibility via keyboard. 14595//>>docs: https://api.jqueryui.com/slider/ 14596//>>demos: https://jqueryui.com/slider/ 14597//>>css.structure: ../../themes/base/core.css 14598//>>css.structure: ../../themes/base/slider.css 14599//>>css.theme: ../../themes/base/theme.css 14600 14601 14602var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, { 14603 version: "1.14.1", 14604 widgetEventPrefix: "slide", 14605 14606 options: { 14607 animate: false, 14608 classes: { 14609 "ui-slider": "ui-corner-all", 14610 "ui-slider-handle": "ui-corner-all", 14611 14612 // Note: ui-widget-header isn't the most fittingly semantic framework class for this 14613 // element, but worked best visually with a variety of themes 14614 "ui-slider-range": "ui-corner-all ui-widget-header" 14615 }, 14616 distance: 0, 14617 max: 100, 14618 min: 0, 14619 orientation: "horizontal", 14620 range: false, 14621 step: 1, 14622 value: 0, 14623 values: null, 14624 14625 // Callbacks 14626 change: null, 14627 slide: null, 14628 start: null, 14629 stop: null 14630 }, 14631 14632 // Number of pages in a slider 14633 // (how many times can you page up/down to go through the whole range) 14634 numPages: 5, 14635 14636 _create: function() { 14637 this._keySliding = false; 14638 this._mouseSliding = false; 14639 this._animateOff = true; 14640 this._handleIndex = null; 14641 this._detectOrientation(); 14642 this._mouseInit(); 14643 this._calculateNewMax(); 14644 14645 this._addClass( "ui-slider ui-slider-" + this.orientation, 14646 "ui-widget ui-widget-content" ); 14647 14648 this._refresh(); 14649 14650 this._animateOff = false; 14651 }, 14652 14653 _refresh: function() { 14654 this._createRange(); 14655 this._createHandles(); 14656 this._setupEvents(); 14657 this._refreshValue(); 14658 }, 14659 14660 _createHandles: function() { 14661 var i, handleCount, 14662 options = this.options, 14663 existingHandles = this.element.find( ".ui-slider-handle" ), 14664 handle = "<span tabindex='0'></span>", 14665 handles = []; 14666 14667 handleCount = ( options.values && options.values.length ) || 1; 14668 14669 if ( existingHandles.length > handleCount ) { 14670 existingHandles.slice( handleCount ).remove(); 14671 existingHandles = existingHandles.slice( 0, handleCount ); 14672 } 14673 14674 for ( i = existingHandles.length; i < handleCount; i++ ) { 14675 handles.push( handle ); 14676 } 14677 14678 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 14679 14680 this._addClass( this.handles, "ui-slider-handle", "ui-state-default" ); 14681 14682 this.handle = this.handles.eq( 0 ); 14683 14684 this.handles.each( function( i ) { 14685 $( this ) 14686 .data( "ui-slider-handle-index", i ) 14687 .attr( "tabIndex", 0 ); 14688 } ); 14689 }, 14690 14691 _createRange: function() { 14692 var options = this.options; 14693 14694 if ( options.range ) { 14695 if ( options.range === true ) { 14696 if ( !options.values ) { 14697 options.values = [ this._valueMin(), this._valueMin() ]; 14698 } else if ( options.values.length && options.values.length !== 2 ) { 14699 options.values = [ options.values[ 0 ], options.values[ 0 ] ]; 14700 } else if ( Array.isArray( options.values ) ) { 14701 options.values = options.values.slice( 0 ); 14702 } 14703 } 14704 14705 if ( !this.range || !this.range.length ) { 14706 this.range = $( "<div>" ) 14707 .appendTo( this.element ); 14708 14709 this._addClass( this.range, "ui-slider-range" ); 14710 } else { 14711 this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" ); 14712 14713 // Handle range switching from true to min/max 14714 this.range.css( { 14715 "left": "", 14716 "bottom": "" 14717 } ); 14718 } 14719 if ( options.range === "min" || options.range === "max" ) { 14720 this._addClass( this.range, "ui-slider-range-" + options.range ); 14721 } 14722 } else { 14723 if ( this.range ) { 14724 this.range.remove(); 14725 } 14726 this.range = null; 14727 } 14728 }, 14729 14730 _setupEvents: function() { 14731 this._off( this.handles ); 14732 this._on( this.handles, this._handleEvents ); 14733 this._hoverable( this.handles ); 14734 this._focusable( this.handles ); 14735 }, 14736 14737 _destroy: function() { 14738 this.handles.remove(); 14739 if ( this.range ) { 14740 this.range.remove(); 14741 } 14742 14743 this._mouseDestroy(); 14744 }, 14745 14746 _mouseCapture: function( event ) { 14747 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 14748 that = this, 14749 o = this.options; 14750 14751 if ( o.disabled ) { 14752 return false; 14753 } 14754 14755 this.elementSize = { 14756 width: this.element.outerWidth(), 14757 height: this.element.outerHeight() 14758 }; 14759 this.elementOffset = this.element.offset(); 14760 14761 position = { x: event.pageX, y: event.pageY }; 14762 normValue = this._normValueFromMouse( position ); 14763 distance = this._valueMax() - this._valueMin() + 1; 14764 this.handles.each( function( i ) { 14765 var thisDistance = Math.abs( normValue - that.values( i ) ); 14766 if ( ( distance > thisDistance ) || 14767 ( distance === thisDistance && 14768 ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) { 14769 distance = thisDistance; 14770 closestHandle = $( this ); 14771 index = i; 14772 } 14773 } ); 14774 14775 allowed = this._start( event, index ); 14776 if ( allowed === false ) { 14777 return false; 14778 } 14779 this._mouseSliding = true; 14780 14781 this._handleIndex = index; 14782 14783 this._addClass( closestHandle, null, "ui-state-active" ); 14784 closestHandle.trigger( "focus" ); 14785 14786 offset = closestHandle.offset(); 14787 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 14788 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 14789 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 14790 top: event.pageY - offset.top - 14791 ( closestHandle.height() / 2 ) - 14792 ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) - 14793 ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) + 14794 ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 ) 14795 }; 14796 14797 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 14798 this._slide( event, index, normValue ); 14799 } 14800 this._animateOff = true; 14801 return true; 14802 }, 14803 14804 _mouseStart: function() { 14805 return true; 14806 }, 14807 14808 _mouseDrag: function( event ) { 14809 var position = { x: event.pageX, y: event.pageY }, 14810 normValue = this._normValueFromMouse( position ); 14811 14812 this._slide( event, this._handleIndex, normValue ); 14813 14814 return false; 14815 }, 14816 14817 _mouseStop: function( event ) { 14818 this._removeClass( this.handles, null, "ui-state-active" ); 14819 this._mouseSliding = false; 14820 14821 this._stop( event, this._handleIndex ); 14822 this._change( event, this._handleIndex ); 14823 14824 this._handleIndex = null; 14825 this._clickOffset = null; 14826 this._animateOff = false; 14827 14828 return false; 14829 }, 14830 14831 _detectOrientation: function() { 14832 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 14833 }, 14834 14835 _normValueFromMouse: function( position ) { 14836 var pixelTotal, 14837 pixelMouse, 14838 percentMouse, 14839 valueTotal, 14840 valueMouse; 14841 14842 if ( this.orientation === "horizontal" ) { 14843 pixelTotal = this.elementSize.width; 14844 pixelMouse = position.x - this.elementOffset.left - 14845 ( this._clickOffset ? this._clickOffset.left : 0 ); 14846 } else { 14847 pixelTotal = this.elementSize.height; 14848 pixelMouse = position.y - this.elementOffset.top - 14849 ( this._clickOffset ? this._clickOffset.top : 0 ); 14850 } 14851 14852 percentMouse = ( pixelMouse / pixelTotal ); 14853 if ( percentMouse > 1 ) { 14854 percentMouse = 1; 14855 } 14856 if ( percentMouse < 0 ) { 14857 percentMouse = 0; 14858 } 14859 if ( this.orientation === "vertical" ) { 14860 percentMouse = 1 - percentMouse; 14861 } 14862 14863 valueTotal = this._valueMax() - this._valueMin(); 14864 valueMouse = this._valueMin() + percentMouse * valueTotal; 14865 14866 return this._trimAlignValue( valueMouse ); 14867 }, 14868 14869 _uiHash: function( index, value, values ) { 14870 var uiHash = { 14871 handle: this.handles[ index ], 14872 handleIndex: index, 14873 value: value !== undefined ? value : this.value() 14874 }; 14875 14876 if ( this._hasMultipleValues() ) { 14877 uiHash.value = value !== undefined ? value : this.values( index ); 14878 uiHash.values = values || this.values(); 14879 } 14880 14881 return uiHash; 14882 }, 14883 14884 _hasMultipleValues: function() { 14885 return this.options.values && this.options.values.length; 14886 }, 14887 14888 _start: function( event, index ) { 14889 return this._trigger( "start", event, this._uiHash( index ) ); 14890 }, 14891 14892 _slide: function( event, index, newVal ) { 14893 var allowed, otherVal, 14894 currentValue = this.value(), 14895 newValues = this.values(); 14896 14897 if ( this._hasMultipleValues() ) { 14898 otherVal = this.values( index ? 0 : 1 ); 14899 currentValue = this.values( index ); 14900 14901 if ( this.options.values.length === 2 && this.options.range === true ) { 14902 newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal ); 14903 } 14904 14905 newValues[ index ] = newVal; 14906 } 14907 14908 if ( newVal === currentValue ) { 14909 return; 14910 } 14911 14912 allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) ); 14913 14914 // A slide can be canceled by returning false from the slide callback 14915 if ( allowed === false ) { 14916 return; 14917 } 14918 14919 if ( this._hasMultipleValues() ) { 14920 this.values( index, newVal ); 14921 } else { 14922 this.value( newVal ); 14923 } 14924 }, 14925 14926 _stop: function( event, index ) { 14927 this._trigger( "stop", event, this._uiHash( index ) ); 14928 }, 14929 14930 _change: function( event, index ) { 14931 if ( !this._keySliding && !this._mouseSliding ) { 14932 14933 //store the last changed value index for reference when handles overlap 14934 this._lastChangedValue = index; 14935 this._trigger( "change", event, this._uiHash( index ) ); 14936 } 14937 }, 14938 14939 value: function( newValue ) { 14940 if ( arguments.length ) { 14941 this.options.value = this._trimAlignValue( newValue ); 14942 this._refreshValue(); 14943 this._change( null, 0 ); 14944 return; 14945 } 14946 14947 return this._value(); 14948 }, 14949 14950 values: function( index, newValue ) { 14951 var vals, 14952 newValues, 14953 i; 14954 14955 if ( arguments.length > 1 ) { 14956 this.options.values[ index ] = this._trimAlignValue( newValue ); 14957 this._refreshValue(); 14958 this._change( null, index ); 14959 return; 14960 } 14961 14962 if ( arguments.length ) { 14963 if ( Array.isArray( arguments[ 0 ] ) ) { 14964 vals = this.options.values; 14965 newValues = arguments[ 0 ]; 14966 for ( i = 0; i < vals.length; i += 1 ) { 14967 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 14968 this._change( null, i ); 14969 } 14970 this._refreshValue(); 14971 } else { 14972 if ( this._hasMultipleValues() ) { 14973 return this._values( index ); 14974 } else { 14975 return this.value(); 14976 } 14977 } 14978 } else { 14979 return this._values(); 14980 } 14981 }, 14982 14983 _setOption: function( key, value ) { 14984 var i, 14985 valsLength = 0; 14986 14987 if ( key === "range" && this.options.range === true ) { 14988 if ( value === "min" ) { 14989 this.options.value = this._values( 0 ); 14990 this.options.values = null; 14991 } else if ( value === "max" ) { 14992 this.options.value = this._values( this.options.values.length - 1 ); 14993 this.options.values = null; 14994 } 14995 } 14996 14997 if ( Array.isArray( this.options.values ) ) { 14998 valsLength = this.options.values.length; 14999 } 15000 15001 this._super( key, value ); 15002 15003 switch ( key ) { 15004 case "orientation": 15005 this._detectOrientation(); 15006 this._removeClass( "ui-slider-horizontal ui-slider-vertical" ) 15007 ._addClass( "ui-slider-" + this.orientation ); 15008 this._refreshValue(); 15009 if ( this.options.range ) { 15010 this._refreshRange( value ); 15011 } 15012 15013 // Reset positioning from previous orientation 15014 this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); 15015 break; 15016 case "value": 15017 this._animateOff = true; 15018 this._refreshValue(); 15019 this._change( null, 0 ); 15020 this._animateOff = false; 15021 break; 15022 case "values": 15023 this._animateOff = true; 15024 this._refreshValue(); 15025 15026 // Start from the last handle to prevent unreachable handles (#9046) 15027 for ( i = valsLength - 1; i >= 0; i-- ) { 15028 this._change( null, i ); 15029 } 15030 this._animateOff = false; 15031 break; 15032 case "step": 15033 case "min": 15034 case "max": 15035 this._animateOff = true; 15036 this._calculateNewMax(); 15037 this._refreshValue(); 15038 this._animateOff = false; 15039 break; 15040 case "range": 15041 this._animateOff = true; 15042 this._refresh(); 15043 this._animateOff = false; 15044 break; 15045 } 15046 }, 15047 15048 _setOptionDisabled: function( value ) { 15049 this._super( value ); 15050 15051 this._toggleClass( null, "ui-state-disabled", !!value ); 15052 }, 15053 15054 //internal value getter 15055 // _value() returns value trimmed by min and max, aligned by step 15056 _value: function() { 15057 var val = this.options.value; 15058 val = this._trimAlignValue( val ); 15059 15060 return val; 15061 }, 15062 15063 //internal values getter 15064 // _values() returns array of values trimmed by min and max, aligned by step 15065 // _values( index ) returns single value trimmed by min and max, aligned by step 15066 _values: function( index ) { 15067 var val, 15068 vals, 15069 i; 15070 15071 if ( arguments.length ) { 15072 val = this.options.values[ index ]; 15073 val = this._trimAlignValue( val ); 15074 15075 return val; 15076 } else if ( this._hasMultipleValues() ) { 15077 15078 // .slice() creates a copy of the array 15079 // this copy gets trimmed by min and max and then returned 15080 vals = this.options.values.slice(); 15081 for ( i = 0; i < vals.length; i += 1 ) { 15082 vals[ i ] = this._trimAlignValue( vals[ i ] ); 15083 } 15084 15085 return vals; 15086 } else { 15087 return []; 15088 } 15089 }, 15090 15091 // Returns the step-aligned value that val is closest to, between (inclusive) min and max 15092 _trimAlignValue: function( val ) { 15093 if ( val <= this._valueMin() ) { 15094 return this._valueMin(); 15095 } 15096 if ( val >= this._valueMax() ) { 15097 return this._valueMax(); 15098 } 15099 var step = ( this.options.step > 0 ) ? this.options.step : 1, 15100 valModStep = ( val - this._valueMin() ) % step, 15101 alignValue = val - valModStep; 15102 15103 if ( Math.abs( valModStep ) * 2 >= step ) { 15104 alignValue += ( valModStep > 0 ) ? step : ( -step ); 15105 } 15106 15107 // Since JavaScript has problems with large floats, round 15108 // the final value to 5 digits after the decimal point (see #4124) 15109 return parseFloat( alignValue.toFixed( 5 ) ); 15110 }, 15111 15112 _calculateNewMax: function() { 15113 var max = this.options.max, 15114 min = this._valueMin(), 15115 step = this.options.step, 15116 aboveMin = Math.round( ( max - min ) / step ) * step; 15117 max = aboveMin + min; 15118 if ( max > this.options.max ) { 15119 15120 //If max is not divisible by step, rounding off may increase its value 15121 max -= step; 15122 } 15123 this.max = parseFloat( max.toFixed( this._precision() ) ); 15124 }, 15125 15126 _precision: function() { 15127 var precision = this._precisionOf( this.options.step ); 15128 if ( this.options.min !== null ) { 15129 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 15130 } 15131 return precision; 15132 }, 15133 15134 _precisionOf: function( num ) { 15135 var str = num.toString(), 15136 decimal = str.indexOf( "." ); 15137 return decimal === -1 ? 0 : str.length - decimal - 1; 15138 }, 15139 15140 _valueMin: function() { 15141 return this.options.min; 15142 }, 15143 15144 _valueMax: function() { 15145 return this.max; 15146 }, 15147 15148 _refreshRange: function( orientation ) { 15149 if ( orientation === "vertical" ) { 15150 this.range.css( { "width": "", "left": "" } ); 15151 } 15152 if ( orientation === "horizontal" ) { 15153 this.range.css( { "height": "", "bottom": "" } ); 15154 } 15155 }, 15156 15157 _refreshValue: function() { 15158 var lastValPercent, valPercent, value, valueMin, valueMax, 15159 oRange = this.options.range, 15160 o = this.options, 15161 that = this, 15162 animate = ( !this._animateOff ) ? o.animate : false, 15163 _set = {}; 15164 15165 if ( this._hasMultipleValues() ) { 15166 this.handles.each( function( i ) { 15167 valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() - 15168 that._valueMin() ) * 100; 15169 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15170 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15171 if ( that.options.range === true ) { 15172 if ( that.orientation === "horizontal" ) { 15173 if ( i === 0 ) { 15174 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15175 left: valPercent + "%" 15176 }, o.animate ); 15177 } 15178 if ( i === 1 ) { 15179 that.range[ animate ? "animate" : "css" ]( { 15180 width: ( valPercent - lastValPercent ) + "%" 15181 }, { 15182 queue: false, 15183 duration: o.animate 15184 } ); 15185 } 15186 } else { 15187 if ( i === 0 ) { 15188 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15189 bottom: ( valPercent ) + "%" 15190 }, o.animate ); 15191 } 15192 if ( i === 1 ) { 15193 that.range[ animate ? "animate" : "css" ]( { 15194 height: ( valPercent - lastValPercent ) + "%" 15195 }, { 15196 queue: false, 15197 duration: o.animate 15198 } ); 15199 } 15200 } 15201 } 15202 lastValPercent = valPercent; 15203 } ); 15204 } else { 15205 value = this.value(); 15206 valueMin = this._valueMin(); 15207 valueMax = this._valueMax(); 15208 valPercent = ( valueMax !== valueMin ) ? 15209 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 15210 0; 15211 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 15212 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 15213 15214 if ( oRange === "min" && this.orientation === "horizontal" ) { 15215 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15216 width: valPercent + "%" 15217 }, o.animate ); 15218 } 15219 if ( oRange === "max" && this.orientation === "horizontal" ) { 15220 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15221 width: ( 100 - valPercent ) + "%" 15222 }, o.animate ); 15223 } 15224 if ( oRange === "min" && this.orientation === "vertical" ) { 15225 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15226 height: valPercent + "%" 15227 }, o.animate ); 15228 } 15229 if ( oRange === "max" && this.orientation === "vertical" ) { 15230 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { 15231 height: ( 100 - valPercent ) + "%" 15232 }, o.animate ); 15233 } 15234 } 15235 }, 15236 15237 _handleEvents: { 15238 keydown: function( event ) { 15239 var allowed, curVal, newVal, step, 15240 index = $( event.target ).data( "ui-slider-handle-index" ); 15241 15242 switch ( event.keyCode ) { 15243 case $.ui.keyCode.HOME: 15244 case $.ui.keyCode.END: 15245 case $.ui.keyCode.PAGE_UP: 15246 case $.ui.keyCode.PAGE_DOWN: 15247 case $.ui.keyCode.UP: 15248 case $.ui.keyCode.RIGHT: 15249 case $.ui.keyCode.DOWN: 15250 case $.ui.keyCode.LEFT: 15251 event.preventDefault(); 15252 if ( !this._keySliding ) { 15253 this._keySliding = true; 15254 this._addClass( $( event.target ), null, "ui-state-active" ); 15255 allowed = this._start( event, index ); 15256 if ( allowed === false ) { 15257 return; 15258 } 15259 } 15260 break; 15261 } 15262 15263 step = this.options.step; 15264 if ( this._hasMultipleValues() ) { 15265 curVal = newVal = this.values( index ); 15266 } else { 15267 curVal = newVal = this.value(); 15268 } 15269 15270 switch ( event.keyCode ) { 15271 case $.ui.keyCode.HOME: 15272 newVal = this._valueMin(); 15273 break; 15274 case $.ui.keyCode.END: 15275 newVal = this._valueMax(); 15276 break; 15277 case $.ui.keyCode.PAGE_UP: 15278 newVal = this._trimAlignValue( 15279 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) 15280 ); 15281 break; 15282 case $.ui.keyCode.PAGE_DOWN: 15283 newVal = this._trimAlignValue( 15284 curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) ); 15285 break; 15286 case $.ui.keyCode.UP: 15287 case $.ui.keyCode.RIGHT: 15288 if ( curVal === this._valueMax() ) { 15289 return; 15290 } 15291 newVal = this._trimAlignValue( curVal + step ); 15292 break; 15293 case $.ui.keyCode.DOWN: 15294 case $.ui.keyCode.LEFT: 15295 if ( curVal === this._valueMin() ) { 15296 return; 15297 } 15298 newVal = this._trimAlignValue( curVal - step ); 15299 break; 15300 } 15301 15302 this._slide( event, index, newVal ); 15303 }, 15304 keyup: function( event ) { 15305 var index = $( event.target ).data( "ui-slider-handle-index" ); 15306 15307 if ( this._keySliding ) { 15308 this._keySliding = false; 15309 this._stop( event, index ); 15310 this._change( event, index ); 15311 this._removeClass( $( event.target ), null, "ui-state-active" ); 15312 } 15313 } 15314 } 15315} ); 15316 15317 15318/*! 15319 * jQuery UI Sortable 1.14.1 15320 * https://jqueryui.com 15321 * 15322 * Copyright OpenJS Foundation and other contributors 15323 * Released under the MIT license. 15324 * https://jquery.org/license 15325 */ 15326 15327//>>label: Sortable 15328//>>group: Interactions 15329//>>description: Enables items in a list to be sorted using the mouse. 15330//>>docs: https://api.jqueryui.com/sortable/ 15331//>>demos: https://jqueryui.com/sortable/ 15332//>>css.structure: ../../themes/base/sortable.css 15333 15334 15335var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, { 15336 version: "1.14.1", 15337 widgetEventPrefix: "sort", 15338 ready: false, 15339 options: { 15340 appendTo: "parent", 15341 axis: false, 15342 connectWith: false, 15343 containment: false, 15344 cursor: "auto", 15345 cursorAt: false, 15346 dropOnEmpty: true, 15347 forcePlaceholderSize: false, 15348 forceHelperSize: false, 15349 grid: false, 15350 handle: false, 15351 helper: "original", 15352 items: "> *", 15353 opacity: false, 15354 placeholder: false, 15355 revert: false, 15356 scroll: true, 15357 scrollSensitivity: 20, 15358 scrollSpeed: 20, 15359 scope: "default", 15360 tolerance: "intersect", 15361 zIndex: 1000, 15362 15363 // Callbacks 15364 activate: null, 15365 beforeStop: null, 15366 change: null, 15367 deactivate: null, 15368 out: null, 15369 over: null, 15370 receive: null, 15371 remove: null, 15372 sort: null, 15373 start: null, 15374 stop: null, 15375 update: null 15376 }, 15377 15378 _isOverAxis: function( x, reference, size ) { 15379 return ( x >= reference ) && ( x < ( reference + size ) ); 15380 }, 15381 15382 _isFloating: function( item ) { 15383 return ( /left|right/ ).test( item.css( "float" ) ) || 15384 ( /inline|table-cell/ ).test( item.css( "display" ) ); 15385 }, 15386 15387 _create: function() { 15388 this.containerCache = {}; 15389 this._addClass( "ui-sortable" ); 15390 15391 //Get the items 15392 this.refresh(); 15393 15394 //Let's determine the parent's offset 15395 this.offset = this.element.offset(); 15396 15397 //Initialize mouse events for interaction 15398 this._mouseInit(); 15399 15400 this._setHandleClassName(); 15401 15402 //We're ready to go 15403 this.ready = true; 15404 15405 }, 15406 15407 _setOption: function( key, value ) { 15408 this._super( key, value ); 15409 15410 if ( key === "handle" ) { 15411 this._setHandleClassName(); 15412 } 15413 }, 15414 15415 _setHandleClassName: function() { 15416 var that = this; 15417 this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" ); 15418 $.each( this.items, function() { 15419 that._addClass( 15420 this.instance.options.handle ? 15421 this.item.find( this.instance.options.handle ) : 15422 this.item, 15423 "ui-sortable-handle" 15424 ); 15425 } ); 15426 }, 15427 15428 _destroy: function() { 15429 this._mouseDestroy(); 15430 15431 for ( var i = this.items.length - 1; i >= 0; i-- ) { 15432 this.items[ i ].item.removeData( this.widgetName + "-item" ); 15433 } 15434 15435 return this; 15436 }, 15437 15438 _mouseCapture: function( event, overrideHandle ) { 15439 var currentItem = null, 15440 validHandle = false, 15441 that = this; 15442 15443 if ( this.reverting ) { 15444 return false; 15445 } 15446 15447 if ( this.options.disabled || this.options.type === "static" ) { 15448 return false; 15449 } 15450 15451 //We have to refresh the items data once first 15452 this._refreshItems( event ); 15453 15454 //Find out if the clicked node (or one of its parents) is a actual item in this.items 15455 $( event.target ).parents().each( function() { 15456 if ( $.data( this, that.widgetName + "-item" ) === that ) { 15457 currentItem = $( this ); 15458 return false; 15459 } 15460 } ); 15461 if ( $.data( event.target, that.widgetName + "-item" ) === that ) { 15462 currentItem = $( event.target ); 15463 } 15464 15465 if ( !currentItem ) { 15466 return false; 15467 } 15468 if ( this.options.handle && !overrideHandle ) { 15469 $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() { 15470 if ( this === event.target ) { 15471 validHandle = true; 15472 } 15473 } ); 15474 if ( !validHandle ) { 15475 return false; 15476 } 15477 } 15478 15479 this.currentItem = currentItem; 15480 this._removeCurrentsFromItems(); 15481 return true; 15482 15483 }, 15484 15485 _mouseStart: function( event, overrideHandle, noActivation ) { 15486 15487 var i, body, 15488 o = this.options; 15489 15490 this.currentContainer = this; 15491 15492 //We only need to call refreshPositions, because the refreshItems call has been moved to 15493 // mouseCapture 15494 this.refreshPositions(); 15495 15496 //Prepare the dragged items parent 15497 this.appendTo = $( o.appendTo !== "parent" ? 15498 o.appendTo : 15499 this.currentItem.parent() ); 15500 15501 //Create and append the visible helper 15502 this.helper = this._createHelper( event ); 15503 15504 //Cache the helper size 15505 this._cacheHelperProportions(); 15506 15507 /* 15508 * - Position generation - 15509 * This block generates everything position related - it's the core of draggables. 15510 */ 15511 15512 //Cache the margins of the original element 15513 this._cacheMargins(); 15514 15515 //The element's absolute position on the page minus margins 15516 this.offset = this.currentItem.offset(); 15517 this.offset = { 15518 top: this.offset.top - this.margins.top, 15519 left: this.offset.left - this.margins.left 15520 }; 15521 15522 $.extend( this.offset, { 15523 click: { //Where the click happened, relative to the element 15524 left: event.pageX - this.offset.left, 15525 top: event.pageY - this.offset.top 15526 }, 15527 15528 // This is a relative to absolute position minus the actual position calculation - 15529 // only used for relative positioned helper 15530 relative: this._getRelativeOffset() 15531 } ); 15532 15533 // After we get the helper offset, but before we get the parent offset we can 15534 // change the helper's position to absolute 15535 // TODO: Still need to figure out a way to make relative sorting possible 15536 this.helper.css( "position", "absolute" ); 15537 this.cssPosition = this.helper.css( "position" ); 15538 15539 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 15540 if ( o.cursorAt ) { 15541 this._adjustOffsetFromHelper( o.cursorAt ); 15542 } 15543 15544 //Cache the former DOM position 15545 this.domPosition = { 15546 prev: this.currentItem.prev()[ 0 ], 15547 parent: this.currentItem.parent()[ 0 ] 15548 }; 15549 15550 // If the helper is not the original, hide the original so it's not playing any role during 15551 // the drag, won't cause anything bad this way 15552 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 15553 this.currentItem.hide(); 15554 } 15555 15556 //Create the placeholder 15557 this._createPlaceholder(); 15558 15559 //Get the next scrolling parent 15560 this.scrollParent = this.placeholder.scrollParent(); 15561 15562 $.extend( this.offset, { 15563 parent: this._getParentOffset() 15564 } ); 15565 15566 //Set a containment if given in the options 15567 if ( o.containment ) { 15568 this._setContainment(); 15569 } 15570 15571 if ( o.cursor && o.cursor !== "auto" ) { // cursor option 15572 body = this.document.find( "body" ); 15573 15574 this._storedStylesheet = 15575 $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body ); 15576 } 15577 15578 // We need to make sure to grab the zIndex before setting the 15579 // opacity, because setting the opacity to anything lower than 1 15580 // causes the zIndex to change from "auto" to 0. 15581 if ( o.zIndex ) { // zIndex option 15582 if ( this.helper.css( "zIndex" ) ) { 15583 this._storedZIndex = this.helper.css( "zIndex" ); 15584 } 15585 this.helper.css( "zIndex", o.zIndex ); 15586 } 15587 15588 if ( o.opacity ) { // opacity option 15589 if ( this.helper.css( "opacity" ) ) { 15590 this._storedOpacity = this.helper.css( "opacity" ); 15591 } 15592 this.helper.css( "opacity", o.opacity ); 15593 } 15594 15595 //Prepare scrolling 15596 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15597 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15598 this.overflowOffset = this.scrollParent.offset(); 15599 } 15600 15601 //Call callbacks 15602 this._trigger( "start", event, this._uiHash() ); 15603 15604 //Recache the helper size 15605 if ( !this._preserveHelperProportions ) { 15606 this._cacheHelperProportions(); 15607 } 15608 15609 //Post "activate" events to possible containers 15610 if ( !noActivation ) { 15611 for ( i = this.containers.length - 1; i >= 0; i-- ) { 15612 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 15613 } 15614 } 15615 15616 //Prepare possible droppables 15617 if ( $.ui.ddmanager ) { 15618 $.ui.ddmanager.current = this; 15619 } 15620 15621 if ( $.ui.ddmanager && !o.dropBehaviour ) { 15622 $.ui.ddmanager.prepareOffsets( this, event ); 15623 } 15624 15625 this.dragging = true; 15626 15627 this._addClass( this.helper, "ui-sortable-helper" ); 15628 15629 //Move the helper, if needed 15630 if ( !this.helper.parent().is( this.appendTo ) ) { 15631 this.helper.detach().appendTo( this.appendTo ); 15632 15633 //Update position 15634 this.offset.parent = this._getParentOffset(); 15635 } 15636 15637 //Generate the original position 15638 this.position = this.originalPosition = this._generatePosition( event ); 15639 this.originalPageX = event.pageX; 15640 this.originalPageY = event.pageY; 15641 this.lastPositionAbs = this.positionAbs = this._convertPositionTo( "absolute" ); 15642 15643 this._mouseDrag( event ); 15644 15645 return true; 15646 15647 }, 15648 15649 _scroll: function( event ) { 15650 var o = this.options, 15651 scrolled = false; 15652 15653 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 15654 this.scrollParent[ 0 ].tagName !== "HTML" ) { 15655 15656 if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) - 15657 event.pageY < o.scrollSensitivity ) { 15658 this.scrollParent[ 0 ].scrollTop = 15659 scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed; 15660 } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) { 15661 this.scrollParent[ 0 ].scrollTop = 15662 scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed; 15663 } 15664 15665 if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) - 15666 event.pageX < o.scrollSensitivity ) { 15667 this.scrollParent[ 0 ].scrollLeft = scrolled = 15668 this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed; 15669 } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) { 15670 this.scrollParent[ 0 ].scrollLeft = scrolled = 15671 this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed; 15672 } 15673 15674 } else { 15675 15676 if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) { 15677 scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed ); 15678 } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) < 15679 o.scrollSensitivity ) { 15680 scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed ); 15681 } 15682 15683 if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) { 15684 scrolled = this.document.scrollLeft( 15685 this.document.scrollLeft() - o.scrollSpeed 15686 ); 15687 } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) < 15688 o.scrollSensitivity ) { 15689 scrolled = this.document.scrollLeft( 15690 this.document.scrollLeft() + o.scrollSpeed 15691 ); 15692 } 15693 15694 } 15695 15696 return scrolled; 15697 }, 15698 15699 _mouseDrag: function( event ) { 15700 var i, item, itemElement, intersection, 15701 o = this.options; 15702 15703 //Compute the helpers position 15704 this.position = this._generatePosition( event ); 15705 this.positionAbs = this._convertPositionTo( "absolute" ); 15706 15707 //Set the helper position 15708 if ( !this.options.axis || this.options.axis !== "y" ) { 15709 this.helper[ 0 ].style.left = this.position.left + "px"; 15710 } 15711 if ( !this.options.axis || this.options.axis !== "x" ) { 15712 this.helper[ 0 ].style.top = this.position.top + "px"; 15713 } 15714 15715 //Do scrolling 15716 if ( o.scroll ) { 15717 if ( this._scroll( event ) !== false ) { 15718 15719 //Update item positions used in position checks 15720 this._refreshItemPositions( true ); 15721 15722 if ( $.ui.ddmanager && !o.dropBehaviour ) { 15723 $.ui.ddmanager.prepareOffsets( this, event ); 15724 } 15725 } 15726 } 15727 15728 this.dragDirection = { 15729 vertical: this._getDragVerticalDirection(), 15730 horizontal: this._getDragHorizontalDirection() 15731 }; 15732 15733 //Rearrange 15734 for ( i = this.items.length - 1; i >= 0; i-- ) { 15735 15736 //Cache variables and intersection, continue if no intersection 15737 item = this.items[ i ]; 15738 itemElement = item.item[ 0 ]; 15739 intersection = this._intersectsWithPointer( item ); 15740 if ( !intersection ) { 15741 continue; 15742 } 15743 15744 // Only put the placeholder inside the current Container, skip all 15745 // items from other containers. This works because when moving 15746 // an item from one container to another the 15747 // currentContainer is switched before the placeholder is moved. 15748 // 15749 // Without this, moving items in "sub-sortables" can cause 15750 // the placeholder to jitter between the outer and inner container. 15751 if ( item.instance !== this.currentContainer ) { 15752 continue; 15753 } 15754 15755 // Cannot intersect with itself 15756 // no useless actions that have been done before 15757 // no action if the item moved is the parent of the item checked 15758 if ( itemElement !== this.currentItem[ 0 ] && 15759 this.placeholder[ intersection === 1 ? 15760 "next" : "prev" ]()[ 0 ] !== itemElement && 15761 !$.contains( this.placeholder[ 0 ], itemElement ) && 15762 ( this.options.type === "semi-dynamic" ? 15763 !$.contains( this.element[ 0 ], itemElement ) : 15764 true 15765 ) 15766 ) { 15767 15768 this.direction = intersection === 1 ? "down" : "up"; 15769 15770 if ( this.options.tolerance === "pointer" || 15771 this._intersectsWithSides( item ) ) { 15772 this._rearrange( event, item ); 15773 } else { 15774 break; 15775 } 15776 15777 this._trigger( "change", event, this._uiHash() ); 15778 break; 15779 } 15780 } 15781 15782 //Post events to containers 15783 this._contactContainers( event ); 15784 15785 //Interconnect with droppables 15786 if ( $.ui.ddmanager ) { 15787 $.ui.ddmanager.drag( this, event ); 15788 } 15789 15790 //Call callbacks 15791 this._trigger( "sort", event, this._uiHash() ); 15792 15793 this.lastPositionAbs = this.positionAbs; 15794 return false; 15795 15796 }, 15797 15798 _mouseStop: function( event, noPropagation ) { 15799 15800 if ( !event ) { 15801 return; 15802 } 15803 15804 //If we are using droppables, inform the manager about the drop 15805 if ( $.ui.ddmanager && !this.options.dropBehaviour ) { 15806 $.ui.ddmanager.drop( this, event ); 15807 } 15808 15809 if ( this.options.revert ) { 15810 var that = this, 15811 cur = this.placeholder.offset(), 15812 axis = this.options.axis, 15813 animation = {}; 15814 15815 if ( !axis || axis === "x" ) { 15816 animation.left = cur.left - this.offset.parent.left - this.margins.left + 15817 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15818 0 : 15819 this.offsetParent[ 0 ].scrollLeft 15820 ); 15821 } 15822 if ( !axis || axis === "y" ) { 15823 animation.top = cur.top - this.offset.parent.top - this.margins.top + 15824 ( this.offsetParent[ 0 ] === this.document[ 0 ].body ? 15825 0 : 15826 this.offsetParent[ 0 ].scrollTop 15827 ); 15828 } 15829 this.reverting = true; 15830 $( this.helper ).animate( 15831 animation, 15832 parseInt( this.options.revert, 10 ) || 500, 15833 function() { 15834 that._clear( event ); 15835 } 15836 ); 15837 } else { 15838 this._clear( event, noPropagation ); 15839 } 15840 15841 return false; 15842 15843 }, 15844 15845 cancel: function() { 15846 15847 if ( this.dragging ) { 15848 15849 this._mouseUp( new $.Event( "mouseup", { target: null } ) ); 15850 15851 if ( this.options.helper === "original" ) { 15852 this.currentItem.css( this._storedCSS ); 15853 this._removeClass( this.currentItem, "ui-sortable-helper" ); 15854 } else { 15855 this.currentItem.show(); 15856 } 15857 15858 //Post deactivating events to containers 15859 for ( var i = this.containers.length - 1; i >= 0; i-- ) { 15860 this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) ); 15861 if ( this.containers[ i ].containerCache.over ) { 15862 this.containers[ i ]._trigger( "out", null, this._uiHash( this ) ); 15863 this.containers[ i ].containerCache.over = 0; 15864 } 15865 } 15866 15867 } 15868 15869 if ( this.placeholder ) { 15870 15871 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 15872 // it unbinds ALL events from the original node! 15873 if ( this.placeholder[ 0 ].parentNode ) { 15874 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 15875 } 15876 if ( this.options.helper !== "original" && this.helper && 15877 this.helper[ 0 ].parentNode ) { 15878 this.helper.remove(); 15879 } 15880 15881 $.extend( this, { 15882 helper: null, 15883 dragging: false, 15884 reverting: false, 15885 _noFinalSort: null 15886 } ); 15887 15888 if ( this.domPosition.prev ) { 15889 $( this.domPosition.prev ).after( this.currentItem ); 15890 } else { 15891 $( this.domPosition.parent ).prepend( this.currentItem ); 15892 } 15893 } 15894 15895 return this; 15896 15897 }, 15898 15899 serialize: function( o ) { 15900 15901 var items = this._getItemsAsjQuery( o && o.connected ), 15902 str = []; 15903 o = o || {}; 15904 15905 $( items ).each( function() { 15906 var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" ) 15907 .match( o.expression || ( /(.+)[\-=_](.+)/ ) ); 15908 if ( res ) { 15909 str.push( 15910 ( o.key || res[ 1 ] + "[]" ) + 15911 "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) ); 15912 } 15913 } ); 15914 15915 if ( !str.length && o.key ) { 15916 str.push( o.key + "=" ); 15917 } 15918 15919 return str.join( "&" ); 15920 15921 }, 15922 15923 toArray: function( o ) { 15924 15925 var items = this._getItemsAsjQuery( o && o.connected ), 15926 ret = []; 15927 15928 o = o || {}; 15929 15930 items.each( function() { 15931 ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" ); 15932 } ); 15933 return ret; 15934 15935 }, 15936 15937 /* Be careful with the following core functions */ 15938 _intersectsWith: function( item ) { 15939 15940 var x1 = this.positionAbs.left, 15941 x2 = x1 + this.helperProportions.width, 15942 y1 = this.positionAbs.top, 15943 y2 = y1 + this.helperProportions.height, 15944 l = item.left, 15945 r = l + item.width, 15946 t = item.top, 15947 b = t + item.height, 15948 dyClick = this.offset.click.top, 15949 dxClick = this.offset.click.left, 15950 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && 15951 ( y1 + dyClick ) < b ), 15952 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && 15953 ( x1 + dxClick ) < r ), 15954 isOverElement = isOverElementHeight && isOverElementWidth; 15955 15956 if ( this.options.tolerance === "pointer" || 15957 this.options.forcePointerForContainers || 15958 ( this.options.tolerance !== "pointer" && 15959 this.helperProportions[ this.floating ? "width" : "height" ] > 15960 item[ this.floating ? "width" : "height" ] ) 15961 ) { 15962 return isOverElement; 15963 } else { 15964 15965 return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half 15966 x2 - ( this.helperProportions.width / 2 ) < r && // Left Half 15967 t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half 15968 y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half 15969 15970 } 15971 }, 15972 15973 _intersectsWithPointer: function( item ) { 15974 var verticalDirection, horizontalDirection, 15975 isOverElementHeight = ( this.options.axis === "x" ) || 15976 this._isOverAxis( 15977 this.positionAbs.top + this.offset.click.top, item.top, item.height ), 15978 isOverElementWidth = ( this.options.axis === "y" ) || 15979 this._isOverAxis( 15980 this.positionAbs.left + this.offset.click.left, item.left, item.width ), 15981 isOverElement = isOverElementHeight && isOverElementWidth; 15982 15983 if ( !isOverElement ) { 15984 return false; 15985 } 15986 15987 verticalDirection = this.dragDirection.vertical; 15988 horizontalDirection = this.dragDirection.horizontal; 15989 15990 return this.floating ? 15991 ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 ) : 15992 ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) ); 15993 15994 }, 15995 15996 _intersectsWithSides: function( item ) { 15997 15998 var isOverBottomHalf = this._isOverAxis( this.positionAbs.top + 15999 this.offset.click.top, item.top + ( item.height / 2 ), item.height ), 16000 isOverRightHalf = this._isOverAxis( this.positionAbs.left + 16001 this.offset.click.left, item.left + ( item.width / 2 ), item.width ), 16002 verticalDirection = this.dragDirection.vertical, 16003 horizontalDirection = this.dragDirection.horizontal; 16004 16005 if ( this.floating && horizontalDirection ) { 16006 return ( ( horizontalDirection === "right" && isOverRightHalf ) || 16007 ( horizontalDirection === "left" && !isOverRightHalf ) ); 16008 } else { 16009 return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) || 16010 ( verticalDirection === "up" && !isOverBottomHalf ) ); 16011 } 16012 16013 }, 16014 16015 _getDragVerticalDirection: function() { 16016 var delta = this.positionAbs.top - this.lastPositionAbs.top; 16017 return delta !== 0 && ( delta > 0 ? "down" : "up" ); 16018 }, 16019 16020 _getDragHorizontalDirection: function() { 16021 var delta = this.positionAbs.left - this.lastPositionAbs.left; 16022 return delta !== 0 && ( delta > 0 ? "right" : "left" ); 16023 }, 16024 16025 refresh: function( event ) { 16026 this._refreshItems( event ); 16027 this._setHandleClassName(); 16028 this.refreshPositions(); 16029 return this; 16030 }, 16031 16032 _connectWith: function() { 16033 var options = this.options; 16034 return options.connectWith.constructor === String ? 16035 [ options.connectWith ] : 16036 options.connectWith; 16037 }, 16038 16039 _getItemsAsjQuery: function( connected ) { 16040 16041 var i, j, cur, inst, 16042 items = [], 16043 queries = [], 16044 connectWith = this._connectWith(); 16045 16046 if ( connectWith && connected ) { 16047 for ( i = connectWith.length - 1; i >= 0; i-- ) { 16048 cur = $( connectWith[ i ], this.document[ 0 ] ); 16049 for ( j = cur.length - 1; j >= 0; j-- ) { 16050 inst = $.data( cur[ j ], this.widgetFullName ); 16051 if ( inst && inst !== this && !inst.options.disabled ) { 16052 queries.push( [ typeof inst.options.items === "function" ? 16053 inst.options.items.call( inst.element ) : 16054 $( inst.options.items, inst.element ) 16055 .not( ".ui-sortable-helper" ) 16056 .not( ".ui-sortable-placeholder" ), inst ] ); 16057 } 16058 } 16059 } 16060 } 16061 16062 queries.push( [ typeof this.options.items === "function" ? 16063 this.options.items 16064 .call( this.element, null, { options: this.options, item: this.currentItem } ) : 16065 $( this.options.items, this.element ) 16066 .not( ".ui-sortable-helper" ) 16067 .not( ".ui-sortable-placeholder" ), this ] ); 16068 16069 function addItems() { 16070 items.push( this ); 16071 } 16072 for ( i = queries.length - 1; i >= 0; i-- ) { 16073 queries[ i ][ 0 ].each( addItems ); 16074 } 16075 16076 return $( items ); 16077 16078 }, 16079 16080 _removeCurrentsFromItems: function() { 16081 16082 var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" ); 16083 16084 this.items = $.grep( this.items, function( item ) { 16085 for ( var j = 0; j < list.length; j++ ) { 16086 if ( list[ j ] === item.item[ 0 ] ) { 16087 return false; 16088 } 16089 } 16090 return true; 16091 } ); 16092 16093 }, 16094 16095 _refreshItems: function( event ) { 16096 16097 this.items = []; 16098 this.containers = [ this ]; 16099 16100 var i, j, cur, inst, targetData, _queries, item, queriesLength, 16101 items = this.items, 16102 queries = [ [ typeof this.options.items === "function" ? 16103 this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) : 16104 $( this.options.items, this.element ), this ] ], 16105 connectWith = this._connectWith(); 16106 16107 //Shouldn't be run the first time through due to massive slow-down 16108 if ( connectWith && this.ready ) { 16109 for ( i = connectWith.length - 1; i >= 0; i-- ) { 16110 cur = $( connectWith[ i ], this.document[ 0 ] ); 16111 for ( j = cur.length - 1; j >= 0; j-- ) { 16112 inst = $.data( cur[ j ], this.widgetFullName ); 16113 if ( inst && inst !== this && !inst.options.disabled ) { 16114 queries.push( [ typeof inst.options.items === "function" ? 16115 inst.options.items 16116 .call( inst.element[ 0 ], event, { item: this.currentItem } ) : 16117 $( inst.options.items, inst.element ), inst ] ); 16118 this.containers.push( inst ); 16119 } 16120 } 16121 } 16122 } 16123 16124 for ( i = queries.length - 1; i >= 0; i-- ) { 16125 targetData = queries[ i ][ 1 ]; 16126 _queries = queries[ i ][ 0 ]; 16127 16128 for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) { 16129 item = $( _queries[ j ] ); 16130 16131 // Data for target checking (mouse manager) 16132 item.data( this.widgetName + "-item", targetData ); 16133 16134 items.push( { 16135 item: item, 16136 instance: targetData, 16137 width: 0, height: 0, 16138 left: 0, top: 0 16139 } ); 16140 } 16141 } 16142 16143 }, 16144 16145 _refreshItemPositions: function( fast ) { 16146 var i, item, t, p; 16147 16148 for ( i = this.items.length - 1; i >= 0; i-- ) { 16149 item = this.items[ i ]; 16150 16151 //We ignore calculating positions of all connected containers when we're not over them 16152 if ( this.currentContainer && item.instance !== this.currentContainer && 16153 item.item[ 0 ] !== this.currentItem[ 0 ] ) { 16154 continue; 16155 } 16156 16157 t = this.options.toleranceElement ? 16158 $( this.options.toleranceElement, item.item ) : 16159 item.item; 16160 16161 if ( !fast ) { 16162 item.width = t.outerWidth(); 16163 item.height = t.outerHeight(); 16164 } 16165 16166 p = t.offset(); 16167 item.left = p.left; 16168 item.top = p.top; 16169 } 16170 }, 16171 16172 refreshPositions: function( fast ) { 16173 16174 // Determine whether items are being displayed horizontally 16175 this.floating = this.items.length ? 16176 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : 16177 false; 16178 16179 // This has to be redone because due to the item being moved out/into the offsetParent, 16180 // the offsetParent's position will change 16181 if ( this.offsetParent && this.helper ) { 16182 this.offset.parent = this._getParentOffset(); 16183 } 16184 16185 this._refreshItemPositions( fast ); 16186 16187 var i, p; 16188 16189 if ( this.options.custom && this.options.custom.refreshContainers ) { 16190 this.options.custom.refreshContainers.call( this ); 16191 } else { 16192 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16193 p = this.containers[ i ].element.offset(); 16194 this.containers[ i ].containerCache.left = p.left; 16195 this.containers[ i ].containerCache.top = p.top; 16196 this.containers[ i ].containerCache.width = 16197 this.containers[ i ].element.outerWidth(); 16198 this.containers[ i ].containerCache.height = 16199 this.containers[ i ].element.outerHeight(); 16200 } 16201 } 16202 16203 return this; 16204 }, 16205 16206 _createPlaceholder: function( that ) { 16207 that = that || this; 16208 var className, nodeName, 16209 o = that.options; 16210 16211 if ( !o.placeholder || o.placeholder.constructor === String ) { 16212 className = o.placeholder; 16213 nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(); 16214 o.placeholder = { 16215 element: function() { 16216 16217 var element = $( "<" + nodeName + ">", that.document[ 0 ] ); 16218 16219 that._addClass( element, "ui-sortable-placeholder", 16220 className || that.currentItem[ 0 ].className ) 16221 ._removeClass( element, "ui-sortable-helper" ); 16222 16223 if ( nodeName === "tbody" ) { 16224 that._createTrPlaceholder( 16225 that.currentItem.find( "tr" ).eq( 0 ), 16226 $( "<tr>", that.document[ 0 ] ).appendTo( element ) 16227 ); 16228 } else if ( nodeName === "tr" ) { 16229 that._createTrPlaceholder( that.currentItem, element ); 16230 } else if ( nodeName === "img" ) { 16231 element.attr( "src", that.currentItem.attr( "src" ) ); 16232 } 16233 16234 if ( !className ) { 16235 element.css( "visibility", "hidden" ); 16236 } 16237 16238 return element; 16239 }, 16240 update: function( container, p ) { 16241 16242 // 1. If a className is set as 'placeholder option, we don't force sizes - 16243 // the class is responsible for that
16244 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a 16245 // class name is specified 16246 if ( className && !o.forcePlaceholderSize ) { 16247 return; 16248 } 16249 16250 // If the element doesn't have a actual height or width by itself (without 16251 // styles coming from a stylesheet), it receives the inline height and width 16252 // from the dragged item. Or, if it's a tbody or tr, it's going to have a height 16253 // anyway since we're populating them with <td>s above, but they're unlikely to 16254 // be the correct height on their own if the row heights are dynamic, so we'll 16255 // always assign the height of the dragged item given forcePlaceholderSize 16256 // is true. 16257 if ( !p.height() || ( o.forcePlaceholderSize && 16258 ( nodeName === "tbody" || nodeName === "tr" ) ) ) { 16259 p.height(
vendor: 43,314 bytes, lines 16260-17446
16260 that.currentItem.innerHeight() - 16261 parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) - 16262 parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) ); 16263 } 16264 if ( !p.width() ) { 16265 p.width( 16266 that.currentItem.innerWidth() - 16267 parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) - 16268 parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) ); 16269 } 16270 } 16271 }; 16272 } 16273 16274 //Create the placeholder 16275 that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) ); 16276 16277 //Append it after the actual current item 16278 that.currentItem.after( that.placeholder ); 16279 16280 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 16281 o.placeholder.update( that, that.placeholder ); 16282 16283 }, 16284 16285 _createTrPlaceholder: function( sourceTr, targetTr ) { 16286 var that = this; 16287 16288 sourceTr.children().each( function() { 16289 $( "<td> </td>", that.document[ 0 ] ) 16290 .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 16291 .appendTo( targetTr ); 16292 } ); 16293 }, 16294 16295 _contactContainers: function( event ) { 16296 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, 16297 floating, axis, 16298 innermostContainer = null, 16299 innermostIndex = null; 16300 16301 // Get innermost container that intersects with item 16302 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16303 16304 // Never consider a container that's located within the item itself 16305 if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) { 16306 continue; 16307 } 16308 16309 if ( this._intersectsWith( this.containers[ i ].containerCache ) ) { 16310 16311 // If we've already found a container and it's more "inner" than this, then continue 16312 if ( innermostContainer && 16313 $.contains( 16314 this.containers[ i ].element[ 0 ], 16315 innermostContainer.element[ 0 ] ) ) { 16316 continue; 16317 } 16318 16319 innermostContainer = this.containers[ i ]; 16320 innermostIndex = i; 16321 16322 } else { 16323 16324 // container doesn't intersect. trigger "out" event if necessary 16325 if ( this.containers[ i ].containerCache.over ) { 16326 this.containers[ i ]._trigger( "out", event, this._uiHash( this ) ); 16327 this.containers[ i ].containerCache.over = 0; 16328 } 16329 } 16330 16331 } 16332 16333 // If no intersecting containers found, return 16334 if ( !innermostContainer ) { 16335 return; 16336 } 16337 16338 // Move the item into the container if it's not there already 16339 if ( this.containers.length === 1 ) { 16340 if ( !this.containers[ innermostIndex ].containerCache.over ) { 16341 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16342 this.containers[ innermostIndex ].containerCache.over = 1; 16343 } 16344 } else { 16345 16346 // When entering a new container, we will find the item with the least distance and 16347 // append our item near it 16348 dist = 10000; 16349 itemWithLeastDistance = null; 16350 floating = innermostContainer.floating || this._isFloating( this.currentItem ); 16351 posProperty = floating ? "left" : "top"; 16352 sizeProperty = floating ? "width" : "height"; 16353 axis = floating ? "pageX" : "pageY"; 16354 16355 for ( j = this.items.length - 1; j >= 0; j-- ) { 16356 if ( !$.contains( 16357 this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] ) 16358 ) { 16359 continue; 16360 } 16361 if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) { 16362 continue; 16363 } 16364 16365 cur = this.items[ j ].item.offset()[ posProperty ]; 16366 nearBottom = false; 16367 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 16368 nearBottom = true; 16369 } 16370 16371 if ( Math.abs( event[ axis ] - cur ) < dist ) { 16372 dist = Math.abs( event[ axis ] - cur ); 16373 itemWithLeastDistance = this.items[ j ]; 16374 this.direction = nearBottom ? "up" : "down"; 16375 } 16376 } 16377 16378 //Check if dropOnEmpty is enabled 16379 if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) { 16380 return; 16381 } 16382 16383 if ( this.currentContainer === this.containers[ innermostIndex ] ) { 16384 if ( !this.currentContainer.containerCache.over ) { 16385 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); 16386 this.currentContainer.containerCache.over = 1; 16387 } 16388 return; 16389 } 16390 16391 if ( itemWithLeastDistance ) { 16392 this._rearrange( event, itemWithLeastDistance, null, true ); 16393 } else { 16394 this._rearrange( event, null, this.containers[ innermostIndex ].element, true ); 16395 } 16396 this._trigger( "change", event, this._uiHash() ); 16397 this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) ); 16398 this.currentContainer = this.containers[ innermostIndex ]; 16399 16400 //Update the placeholder 16401 this.options.placeholder.update( this.currentContainer, this.placeholder ); 16402 16403 //Update scrollParent 16404 this.scrollParent = this.placeholder.scrollParent(); 16405 16406 //Update overflowOffset 16407 if ( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16408 this.scrollParent[ 0 ].tagName !== "HTML" ) { 16409 this.overflowOffset = this.scrollParent.offset(); 16410 } 16411 16412 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) ); 16413 this.containers[ innermostIndex ].containerCache.over = 1; 16414 } 16415 16416 }, 16417 16418 _createHelper: function( event ) { 16419 16420 var o = this.options, 16421 helper = typeof o.helper === "function" ? 16422 $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) : 16423 ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem ); 16424 16425 //Add the helper to the DOM if that didn't happen already 16426 if ( !helper.parents( "body" ).length ) { 16427 this.appendTo[ 0 ].appendChild( helper[ 0 ] ); 16428 } 16429 16430 if ( helper[ 0 ] === this.currentItem[ 0 ] ) { 16431 this._storedCSS = { 16432 width: this.currentItem[ 0 ].style.width, 16433 height: this.currentItem[ 0 ].style.height, 16434 position: this.currentItem.css( "position" ), 16435 top: this.currentItem.css( "top" ), 16436 left: this.currentItem.css( "left" ) 16437 }; 16438 } 16439 16440 if ( !helper[ 0 ].style.width || o.forceHelperSize ) { 16441 helper.width( this.currentItem.width() ); 16442 } 16443 if ( !helper[ 0 ].style.height || o.forceHelperSize ) { 16444 helper.height( this.currentItem.height() ); 16445 } 16446 16447 return helper; 16448 16449 }, 16450 16451 _adjustOffsetFromHelper: function( obj ) { 16452 if ( typeof obj === "string" ) { 16453 obj = obj.split( " " ); 16454 } 16455 if ( Array.isArray( obj ) ) { 16456 obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 }; 16457 } 16458 if ( "left" in obj ) { 16459 this.offset.click.left = obj.left + this.margins.left; 16460 } 16461 if ( "right" in obj ) { 16462 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 16463 } 16464 if ( "top" in obj ) { 16465 this.offset.click.top = obj.top + this.margins.top; 16466 } 16467 if ( "bottom" in obj ) { 16468 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 16469 } 16470 }, 16471 16472 _getParentOffset: function() { 16473 16474 //Get the offsetParent and cache its position 16475 this.offsetParent = this.helper.offsetParent(); 16476 var po = this.offsetParent.offset(); 16477 16478 // This is a special case where we need to modify a offset calculated on start, since the 16479 // following happened: 16480 // 1. The position of the helper is absolute, so it's position is calculated based on the 16481 // next positioned parent 16482 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't 16483 // the document, which means that the scroll is included in the initial calculation of the 16484 // offset of the parent, and never recalculated upon drag 16485 if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] && 16486 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) { 16487 po.left += this.scrollParent.scrollLeft(); 16488 po.top += this.scrollParent.scrollTop(); 16489 } 16490 16491 // This needs to be actually done for all browsers, since pageX/pageY includes 16492 // this information. 16493 if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ) { 16494 po = { top: 0, left: 0 }; 16495 } 16496 16497 return { 16498 top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ), 16499 left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 ) 16500 }; 16501 16502 }, 16503 16504 _getRelativeOffset: function() { 16505 16506 if ( this.cssPosition === "relative" ) { 16507 var p = this.currentItem.position(); 16508 return { 16509 top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) + 16510 this.scrollParent.scrollTop(), 16511 left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) + 16512 this.scrollParent.scrollLeft() 16513 }; 16514 } else { 16515 return { top: 0, left: 0 }; 16516 } 16517 16518 }, 16519 16520 _cacheMargins: function() { 16521 this.margins = { 16522 left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ), 16523 top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 ) 16524 }; 16525 }, 16526 16527 _cacheHelperProportions: function() { 16528 this.helperProportions = { 16529 width: this.helper.outerWidth(), 16530 height: this.helper.outerHeight() 16531 }; 16532 }, 16533 16534 _setContainment: function() { 16535 16536 var ce, co, over, 16537 o = this.options; 16538 if ( o.containment === "parent" ) { 16539 o.containment = this.helper[ 0 ].parentNode; 16540 } 16541 if ( o.containment === "document" || o.containment === "window" ) { 16542 this.containment = [ 16543 0 - this.offset.relative.left - this.offset.parent.left, 16544 0 - this.offset.relative.top - this.offset.parent.top, 16545 o.containment === "document" ? 16546 this.document.width() : 16547 this.window.width() - this.helperProportions.width - this.margins.left, 16548 ( o.containment === "document" ? 16549 ( this.document.height() || document.body.parentNode.scrollHeight ) : 16550 this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight 16551 ) - this.helperProportions.height - this.margins.top 16552 ]; 16553 } 16554 16555 if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) { 16556 ce = $( o.containment )[ 0 ]; 16557 co = $( o.containment ).offset(); 16558 over = ( $( ce ).css( "overflow" ) !== "hidden" ); 16559 16560 this.containment = [ 16561 co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) + 16562 ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left, 16563 co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) + 16564 ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top, 16565 co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 16566 ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) - 16567 ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) - 16568 this.helperProportions.width - this.margins.left, 16569 co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 16570 ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) - 16571 ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) - 16572 this.helperProportions.height - this.margins.top 16573 ]; 16574 } 16575 16576 }, 16577 16578 _convertPositionTo: function( d, pos ) { 16579 16580 if ( !pos ) { 16581 pos = this.position; 16582 } 16583 var mod = d === "absolute" ? 1 : -1, 16584 scroll = this.cssPosition === "absolute" && 16585 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16586 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16587 this.offsetParent : 16588 this.scrollParent, 16589 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16590 16591 return { 16592 top: ( 16593 16594 // The absolute mouse position 16595 pos.top + 16596 16597 // Only for relative positioned nodes: Relative offset from element to offset parent 16598 this.offset.relative.top * mod + 16599 16600 // The offsetParent's offset without borders (offset + border) 16601 this.offset.parent.top * mod - 16602 ( ( this.cssPosition === "fixed" ? 16603 -this.scrollParent.scrollTop() : 16604 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod ) 16605 ), 16606 left: ( 16607 16608 // The absolute mouse position 16609 pos.left + 16610 16611 // Only for relative positioned nodes: Relative offset from element to offset parent 16612 this.offset.relative.left * mod + 16613 16614 // The offsetParent's offset without borders (offset + border) 16615 this.offset.parent.left * mod - 16616 ( ( this.cssPosition === "fixed" ? 16617 -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : 16618 scroll.scrollLeft() ) * mod ) 16619 ) 16620 }; 16621 16622 }, 16623 16624 _generatePosition: function( event ) { 16625 16626 var top, left, 16627 o = this.options, 16628 pageX = event.pageX, 16629 pageY = event.pageY, 16630 scroll = this.cssPosition === "absolute" && 16631 !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16632 $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? 16633 this.offsetParent : 16634 this.scrollParent, 16635 scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName ); 16636 16637 // This is another very weird special case that only happens for relative elements: 16638 // 1. If the css position is relative 16639 // 2. and the scroll parent is the document or similar to the offset parent 16640 // we have to refresh the relative offset during the scroll so there are no jumps 16641 if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] && 16642 this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) { 16643 this.offset.relative = this._getRelativeOffset(); 16644 } 16645 16646 /* 16647 * - Position constraining - 16648 * Constrain the position to a mix of grid, containment. 16649 */ 16650 16651 if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options 16652 16653 if ( this.containment ) { 16654 if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) { 16655 pageX = this.containment[ 0 ] + this.offset.click.left; 16656 } 16657 if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) { 16658 pageY = this.containment[ 1 ] + this.offset.click.top; 16659 } 16660 if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) { 16661 pageX = this.containment[ 2 ] + this.offset.click.left; 16662 } 16663 if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) { 16664 pageY = this.containment[ 3 ] + this.offset.click.top; 16665 } 16666 } 16667 16668 if ( o.grid ) { 16669 top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) / 16670 o.grid[ 1 ] ) * o.grid[ 1 ]; 16671 pageY = this.containment ? 16672 ( ( top - this.offset.click.top >= this.containment[ 1 ] && 16673 top - this.offset.click.top <= this.containment[ 3 ] ) ? 16674 top : 16675 ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ? 16676 top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : 16677 top; 16678 16679 left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) / 16680 o.grid[ 0 ] ) * o.grid[ 0 ]; 16681 pageX = this.containment ? 16682 ( ( left - this.offset.click.left >= this.containment[ 0 ] && 16683 left - this.offset.click.left <= this.containment[ 2 ] ) ? 16684 left : 16685 ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ? 16686 left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : 16687 left; 16688 } 16689 16690 } 16691 16692 return { 16693 top: ( 16694 16695 // The absolute mouse position 16696 pageY - 16697 16698 // Click offset (relative to the element) 16699 this.offset.click.top - 16700 16701 // Only for relative positioned nodes: Relative offset from element to offset parent 16702 this.offset.relative.top - 16703 16704 // The offsetParent's offset without borders (offset + border) 16705 this.offset.parent.top + 16706 ( ( this.cssPosition === "fixed" ? 16707 -this.scrollParent.scrollTop() : 16708 ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) ) 16709 ), 16710 left: ( 16711 16712 // The absolute mouse position 16713 pageX - 16714 16715 // Click offset (relative to the element) 16716 this.offset.click.left - 16717 16718 // Only for relative positioned nodes: Relative offset from element to offset parent 16719 this.offset.relative.left - 16720 16721 // The offsetParent's offset without borders (offset + border) 16722 this.offset.parent.left + 16723 ( ( this.cssPosition === "fixed" ? 16724 -this.scrollParent.scrollLeft() : 16725 scrollIsRootNode ? 0 : scroll.scrollLeft() ) ) 16726 ) 16727 }; 16728 16729 }, 16730 16731 _rearrange: function( event, i, a, hardRefresh ) { 16732 16733 if ( a ) { 16734 a[ 0 ].appendChild( this.placeholder[ 0 ] ); 16735 } else { 16736 i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ], 16737 ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) ); 16738 } 16739 16740 //Various things done here to improve the performance: 16741 // 1. we create a setTimeout, that calls refreshPositions 16742 // 2. on the instance, we have a counter variable, that get's higher after every append 16743 // 3. on the local scope, we copy the counter variable, and check in the timeout, 16744 // if it's still the same 16745 // 4. this lets only the last addition to the timeout stack through 16746 this.counter = this.counter ? ++this.counter : 1; 16747 var counter = this.counter; 16748 16749 this._delay( function() { 16750 if ( counter === this.counter ) { 16751 16752 //Precompute after each DOM insertion, NOT on mousemove 16753 this.refreshPositions( !hardRefresh ); 16754 } 16755 } ); 16756 16757 }, 16758 16759 _clear: function( event, noPropagation ) { 16760 16761 this.reverting = false; 16762 16763 // We delay all events that have to be triggered to after the point where the placeholder 16764 // has been removed and everything else normalized again 16765 var i, 16766 delayedTriggers = []; 16767 16768 // We first have to update the dom position of the actual currentItem 16769 // Note: don't do it if the current item is already removed (by a user), or it gets 16770 // reappended (see #4088) 16771 if ( !this._noFinalSort && this.currentItem.parent().length ) { 16772 this.placeholder.before( this.currentItem ); 16773 } 16774 this._noFinalSort = null; 16775 16776 if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) { 16777 for ( i in this._storedCSS ) { 16778 if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) { 16779 this._storedCSS[ i ] = ""; 16780 } 16781 } 16782 this.currentItem.css( this._storedCSS ); 16783 this._removeClass( this.currentItem, "ui-sortable-helper" ); 16784 } else { 16785 this.currentItem.show(); 16786 } 16787 16788 if ( this.fromOutside && !noPropagation ) { 16789 delayedTriggers.push( function( event ) { 16790 this._trigger( "receive", event, this._uiHash( this.fromOutside ) ); 16791 } ); 16792 } 16793 if ( ( this.fromOutside || 16794 this.domPosition.prev !== 16795 this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] || 16796 this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) { 16797 16798 // Trigger update callback if the DOM position has changed 16799 delayedTriggers.push( function( event ) { 16800 this._trigger( "update", event, this._uiHash() ); 16801 } ); 16802 } 16803 16804 // Check if the items Container has Changed and trigger appropriate 16805 // events. 16806 if ( this !== this.currentContainer ) { 16807 if ( !noPropagation ) { 16808 delayedTriggers.push( function( event ) { 16809 this._trigger( "remove", event, this._uiHash() ); 16810 } ); 16811 delayedTriggers.push( ( function( c ) { 16812 return function( event ) { 16813 c._trigger( "receive", event, this._uiHash( this ) ); 16814 }; 16815 } ).call( this, this.currentContainer ) ); 16816 delayedTriggers.push( ( function( c ) { 16817 return function( event ) { 16818 c._trigger( "update", event, this._uiHash( this ) ); 16819 }; 16820 } ).call( this, this.currentContainer ) ); 16821 } 16822 } 16823 16824 //Post events to containers 16825 function delayEvent( type, instance, container ) { 16826 return function( event ) { 16827 container._trigger( type, event, instance._uiHash( instance ) ); 16828 }; 16829 } 16830 for ( i = this.containers.length - 1; i >= 0; i-- ) { 16831 if ( !noPropagation ) { 16832 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 16833 } 16834 if ( this.containers[ i ].containerCache.over ) { 16835 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 16836 this.containers[ i ].containerCache.over = 0; 16837 } 16838 } 16839 16840 //Do what was originally in plugins 16841 if ( this._storedStylesheet ) { 16842 this._storedStylesheet.remove(); 16843 this._storedStylesheet = null; 16844 } 16845 if ( this._storedOpacity ) { 16846 this.helper.css( "opacity", this._storedOpacity ); 16847 } 16848 if ( this._storedZIndex ) { 16849 this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex ); 16850 } 16851 16852 this.dragging = false; 16853 16854 if ( !noPropagation ) { 16855 this._trigger( "beforeStop", event, this._uiHash() ); 16856 } 16857 16858 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, 16859 // it unbinds ALL events from the original node! 16860 this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] ); 16861 16862 if ( !this.cancelHelperRemoval ) { 16863 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 16864 this.helper.remove(); 16865 } 16866 this.helper = null; 16867 } 16868 16869 if ( !noPropagation ) { 16870 for ( i = 0; i < delayedTriggers.length; i++ ) { 16871 16872 // Trigger all delayed events 16873 delayedTriggers[ i ].call( this, event ); 16874 } 16875 this._trigger( "stop", event, this._uiHash() ); 16876 } 16877 16878 this.fromOutside = false; 16879 return !this.cancelHelperRemoval; 16880 16881 }, 16882 16883 _trigger: function() { 16884 if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) { 16885 this.cancel(); 16886 } 16887 }, 16888 16889 _uiHash: function( _inst ) { 16890 var inst = _inst || this; 16891 return { 16892 helper: inst.helper, 16893 placeholder: inst.placeholder || $( [] ), 16894 position: inst.position, 16895 originalPosition: inst.originalPosition, 16896 offset: inst.positionAbs, 16897 item: inst.currentItem, 16898 sender: _inst ? _inst.element : null 16899 }; 16900 } 16901 16902} ); 16903 16904 16905/*! 16906 * jQuery UI Spinner 1.14.1 16907 * https://jqueryui.com 16908 * 16909 * Copyright OpenJS Foundation and other contributors 16910 * Released under the MIT license. 16911 * https://jquery.org/license 16912 */ 16913 16914//>>label: Spinner 16915//>>group: Widgets 16916//>>description: Displays buttons to easily input numbers via the keyboard or mouse. 16917//>>docs: https://api.jqueryui.com/spinner/ 16918//>>demos: https://jqueryui.com/spinner/ 16919//>>css.structure: ../../themes/base/core.css 16920//>>css.structure: ../../themes/base/spinner.css 16921//>>css.theme: ../../themes/base/theme.css 16922 16923 16924function spinnerModifier( fn ) { 16925 return function() { 16926 var previous = this.element.val(); 16927 fn.apply( this, arguments ); 16928 this._refresh(); 16929 if ( previous !== this.element.val() ) { 16930 this._trigger( "change" ); 16931 } 16932 }; 16933} 16934 16935$.widget( "ui.spinner", { 16936 version: "1.14.1", 16937 defaultElement: "<input>", 16938 widgetEventPrefix: "spin", 16939 options: { 16940 classes: { 16941 "ui-spinner": "ui-corner-all", 16942 "ui-spinner-down": "ui-corner-br", 16943 "ui-spinner-up": "ui-corner-tr" 16944 }, 16945 culture: null, 16946 icons: { 16947 down: "ui-icon-triangle-1-s", 16948 up: "ui-icon-triangle-1-n" 16949 }, 16950 incremental: true, 16951 max: null, 16952 min: null, 16953 numberFormat: null, 16954 page: 10, 16955 step: 1, 16956 16957 change: null, 16958 spin: null, 16959 start: null, 16960 stop: null 16961 }, 16962 16963 _create: function() { 16964 16965 // handle string values that need to be parsed 16966 this._setOption( "max", this.options.max ); 16967 this._setOption( "min", this.options.min ); 16968 this._setOption( "step", this.options.step ); 16969 16970 // Only format if there is a value, prevents the field from being marked 16971 // as invalid in Firefox, see #9573. 16972 if ( this.value() !== "" ) { 16973 16974 // Format the value, but don't constrain. 16975 this._value( this.element.val(), true ); 16976 } 16977 16978 this._draw(); 16979 this._on( this._events ); 16980 this._refresh(); 16981 16982 // Turning off autocomplete prevents the browser from remembering the 16983 // value when navigating through history, so we re-enable autocomplete 16984 // if the page is unloaded before the widget is destroyed. #7790 16985 this._on( this.window, { 16986 beforeunload: function() { 16987 this.element.removeAttr( "autocomplete" ); 16988 } 16989 } ); 16990 }, 16991 16992 _getCreateOptions: function() { 16993 var options = this._super(); 16994 var element = this.element; 16995 16996 $.each( [ "min", "max", "step" ], function( i, option ) { 16997 var value = element.attr( option ); 16998 if ( value != null && value.length ) { 16999 options[ option ] = value; 17000 } 17001 } ); 17002 17003 return options; 17004 }, 17005 17006 _events: { 17007 keydown: function( event ) { 17008 if ( this._start( event ) && this._keydown( event ) ) { 17009 event.preventDefault(); 17010 } 17011 }, 17012 keyup: "_stop", 17013 focus: function() { 17014 this.previous = this.element.val(); 17015 }, 17016 blur: function( event ) { 17017 this._stop(); 17018 this._refresh(); 17019 if ( this.previous !== this.element.val() ) { 17020 this._trigger( "change", event ); 17021 } 17022 }, 17023 mousewheel: function( event, delta ) { 17024 var activeElement = this.document[ 0 ].activeElement; 17025 var isActive = this.element[ 0 ] === activeElement; 17026 17027 if ( !isActive || !delta ) { 17028 return; 17029 } 17030 17031 if ( !this.spinning && !this._start( event ) ) { 17032 return false; 17033 } 17034 17035 this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); 17036 clearTimeout( this.mousewheelTimer ); 17037 this.mousewheelTimer = this._delay( function() { 17038 if ( this.spinning ) { 17039 this._stop( event ); 17040 } 17041 }, 100 ); 17042 event.preventDefault(); 17043 }, 17044 "mousedown .ui-spinner-button": function( event ) { 17045 var previous; 17046 17047 // We never want the buttons to have focus; whenever the user is 17048 // interacting with the spinner, the focus should be on the input. 17049 // If the input is focused then this.previous is properly set from 17050 // when the input first received focus. If the input is not focused 17051 // then we need to set this.previous based on the value before spinning. 17052 previous = this.element[ 0 ] === this.document[ 0 ].activeElement ? 17053 this.previous : this.element.val(); 17054 function checkFocus() { 17055 var isActive = this.element[ 0 ] === this.document[ 0 ].activeElement; 17056 if ( !isActive ) { 17057 this.element.trigger( "focus" ); 17058 this.previous = previous; 17059 } 17060 } 17061 17062 // Ensure focus is on (or stays on) the text field 17063 event.preventDefault(); 17064 checkFocus.call( this ); 17065 17066 if ( this._start( event ) === false ) { 17067 return; 17068 } 17069 17070 this._repeat( null, $( event.currentTarget ) 17071 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 17072 }, 17073 "mouseup .ui-spinner-button": "_stop", 17074 "mouseenter .ui-spinner-button": function( event ) { 17075 17076 // button will add ui-state-active if mouse was down while mouseleave and kept down 17077 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 17078 return; 17079 } 17080 17081 if ( this._start( event ) === false ) { 17082 return false; 17083 } 17084 this._repeat( null, $( event.currentTarget ) 17085 .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 17086 }, 17087 17088 // TODO: do we really want to consider this a stop? 17089 // shouldn't we just stop the repeater and wait until mouseup before 17090 // we trigger the stop event? 17091 "mouseleave .ui-spinner-button": "_stop" 17092 }, 17093 17094 // Support mobile enhanced option and make backcompat more sane 17095 _enhance: function() { 17096 this.uiSpinner = this.element 17097 .attr( "autocomplete", "off" ) 17098 .wrap( "<span>" ) 17099 .parent() 17100 17101 // Add buttons 17102 .append( 17103 "<a></a><a></a>" 17104 ); 17105 }, 17106 17107 _draw: function() { 17108 this._enhance(); 17109 17110 this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); 17111 this._addClass( "ui-spinner-input" ); 17112 17113 this.element.attr( "role", "spinbutton" ); 17114 17115 // Button bindings 17116 this.buttons = this.uiSpinner.children( "a" ) 17117 .attr( "tabIndex", -1 ) 17118 .attr( "aria-hidden", true ) 17119 .button( { 17120 classes: { 17121 "ui-button": "" 17122 } 17123 } ); 17124 17125 // TODO: Right now button does not support classes this is already updated in button PR 17126 this._removeClass( this.buttons, "ui-corner-all" ); 17127 17128 this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); 17129 this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); 17130 this.buttons.first().button( { 17131 "icon": this.options.icons.up, 17132 "showLabel": false 17133 } ); 17134 this.buttons.last().button( { 17135 "icon": this.options.icons.down, 17136 "showLabel": false 17137 } ); 17138 17139 // IE 6 doesn't understand height: 50% for the buttons 17140 // unless the wrapper has an explicit height 17141 if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && 17142 this.uiSpinner.height() > 0 ) { 17143 this.uiSpinner.height( this.uiSpinner.height() ); 17144 } 17145 }, 17146 17147 _keydown: function( event ) { 17148 var options = this.options, 17149 keyCode = $.ui.keyCode; 17150 17151 switch ( event.keyCode ) { 17152 case keyCode.UP: 17153 this._repeat( null, 1, event ); 17154 return true; 17155 case keyCode.DOWN: 17156 this._repeat( null, -1, event ); 17157 return true; 17158 case keyCode.PAGE_UP: 17159 this._repeat( null, options.page, event ); 17160 return true; 17161 case keyCode.PAGE_DOWN: 17162 this._repeat( null, -options.page, event ); 17163 return true; 17164 } 17165 17166 return false; 17167 }, 17168 17169 _start: function( event ) { 17170 if ( !this.spinning && this._trigger( "start", event ) === false ) { 17171 return false; 17172 } 17173 17174 if ( !this.counter ) { 17175 this.counter = 1; 17176 } 17177 this.spinning = true; 17178 return true; 17179 }, 17180 17181 _repeat: function( i, steps, event ) { 17182 i = i || 500; 17183 17184 clearTimeout( this.timer ); 17185 this.timer = this._delay( function() { 17186 this._repeat( 40, steps, event ); 17187 }, i ); 17188 17189 this._spin( steps * this.options.step, event ); 17190 }, 17191 17192 _spin: function( step, event ) { 17193 var value = this.value() || 0; 17194 17195 if ( !this.counter ) { 17196 this.counter = 1; 17197 } 17198 17199 value = this._adjustValue( value + step * this._increment( this.counter ) ); 17200 17201 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { 17202 this._value( value ); 17203 this.counter++; 17204 } 17205 }, 17206 17207 _increment: function( i ) { 17208 var incremental = this.options.incremental; 17209 17210 if ( incremental ) { 17211 return typeof incremental === "function" ? 17212 incremental( i ) : 17213 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 17214 } 17215 17216 return 1; 17217 }, 17218 17219 _precision: function() { 17220 var precision = this._precisionOf( this.options.step ); 17221 if ( this.options.min !== null ) { 17222 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 17223 } 17224 return precision; 17225 }, 17226 17227 _precisionOf: function( num ) { 17228 var str = num.toString(), 17229 decimal = str.indexOf( "." ); 17230 return decimal === -1 ? 0 : str.length - decimal - 1; 17231 }, 17232 17233 _adjustValue: function( value ) { 17234 var base, aboveMin, 17235 options = this.options; 17236 17237 // Make sure we're at a valid step 17238 // - find out where we are relative to the base (min or 0) 17239 base = options.min !== null ? options.min : 0; 17240 aboveMin = value - base; 17241 17242 // - round to the nearest step 17243 aboveMin = Math.round( aboveMin / options.step ) * options.step; 17244 17245 // - rounding is based on 0, so adjust back to our base 17246 value = base + aboveMin; 17247 17248 // Fix precision from bad JS floating point math 17249 value = parseFloat( value.toFixed( this._precision() ) ); 17250 17251 // Clamp the value 17252 if ( options.max !== null && value > options.max ) { 17253 return options.max; 17254 } 17255 if ( options.min !== null && value < options.min ) { 17256 return options.min; 17257 } 17258 17259 return value; 17260 }, 17261 17262 _stop: function( event ) { 17263 if ( !this.spinning ) { 17264 return; 17265 } 17266 17267 clearTimeout( this.timer ); 17268 clearTimeout( this.mousewheelTimer ); 17269 this.counter = 0; 17270 this.spinning = false; 17271 this._trigger( "stop", event ); 17272 }, 17273 17274 _setOption: function( key, value ) { 17275 var prevValue, first, last; 17276 17277 if ( key === "culture" || key === "numberFormat" ) { 17278 prevValue = this._parse( this.element.val() ); 17279 this.options[ key ] = value; 17280 this.element.val( this._format( prevValue ) ); 17281 return; 17282 } 17283 17284 if ( key === "max" || key === "min" || key === "step" ) { 17285 if ( typeof value === "string" ) { 17286 value = this._parse( value ); 17287 } 17288 } 17289 if ( key === "icons" ) { 17290 first = this.buttons.first().find( ".ui-icon" ); 17291 this._removeClass( first, null, this.options.icons.up ); 17292 this._addClass( first, null, value.up ); 17293 last = this.buttons.last().find( ".ui-icon" ); 17294 this._removeClass( last, null, this.options.icons.down ); 17295 this._addClass( last, null, value.down ); 17296 } 17297 17298 this._super( key, value ); 17299 }, 17300 17301 _setOptionDisabled: function( value ) { 17302 this._super( value ); 17303 17304 this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); 17305 this.element.prop( "disabled", !!value ); 17306 this.buttons.button( value ? "disable" : "enable" ); 17307 }, 17308 17309 _setOptions: spinnerModifier( function( options ) { 17310 this._super( options ); 17311 } ), 17312 17313 _parse: function( val ) { 17314 if ( typeof val === "string" && val !== "" ) { 17315 val = window.Globalize && this.options.numberFormat ? 17316 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 17317 } 17318 return val === "" || isNaN( val ) ? null : val; 17319 }, 17320 17321 _format: function( value ) { 17322 if ( value === "" ) { 17323 return ""; 17324 } 17325 return window.Globalize && this.options.numberFormat ? 17326 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 17327 value; 17328 }, 17329 17330 _refresh: function() { 17331 this.element.attr( { 17332 "aria-valuemin": this.options.min, 17333 "aria-valuemax": this.options.max, 17334 17335 // TODO: what should we do with values that can't be parsed? 17336 "aria-valuenow": this._parse( this.element.val() ) 17337 } ); 17338 }, 17339 17340 isValid: function() { 17341 var value = this.value(); 17342 17343 // Null is invalid 17344 if ( value === null ) { 17345 return false; 17346 } 17347 17348 // If value gets adjusted, it's invalid 17349 return value === this._adjustValue( value ); 17350 }, 17351 17352 // Update the value without triggering change 17353 _value: function( value, allowAny ) { 17354 var parsed; 17355 if ( value !== "" ) { 17356 parsed = this._parse( value ); 17357 if ( parsed !== null ) { 17358 if ( !allowAny ) { 17359 parsed = this._adjustValue( parsed ); 17360 } 17361 value = this._format( parsed ); 17362 } 17363 } 17364 this.element.val( value ); 17365 this._refresh(); 17366 }, 17367 17368 _destroy: function() { 17369 this.element 17370 .prop( "disabled", false ) 17371 .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); 17372 17373 this.uiSpinner.replaceWith( this.element ); 17374 }, 17375 17376 stepUp: spinnerModifier( function( steps ) { 17377 this._stepUp( steps ); 17378 } ), 17379 _stepUp: function( steps ) { 17380 if ( this._start() ) { 17381 this._spin( ( steps || 1 ) * this.options.step ); 17382 this._stop(); 17383 } 17384 }, 17385 17386 stepDown: spinnerModifier( function( steps ) { 17387 this._stepDown( steps ); 17388 } ), 17389 _stepDown: function( steps ) { 17390 if ( this._start() ) { 17391 this._spin( ( steps || 1 ) * -this.options.step ); 17392 this._stop(); 17393 } 17394 }, 17395 17396 pageUp: spinnerModifier( function( pages ) { 17397 this._stepUp( ( pages || 1 ) * this.options.page ); 17398 } ), 17399 17400 pageDown: spinnerModifier( function( pages ) { 17401 this._stepDown( ( pages || 1 ) * this.options.page ); 17402 } ), 17403 17404 value: function( newVal ) { 17405 if ( !arguments.length ) { 17406 return this._parse( this.element.val() ); 17407 } 17408 spinnerModifier( this._value ).call( this, newVal ); 17409 }, 17410 17411 widget: function() { 17412 return this.uiSpinner; 17413 } 17414} ); 17415 17416// DEPRECATED 17417// TODO: switch return back to widget declaration at top of file when this is removed 17418if ( $.uiBackCompat === true ) { 17419 17420 // Backcompat for spinner html extension points 17421 $.widget( "ui.spinner", $.ui.spinner, { 17422 _enhance: function() { 17423 this.uiSpinner = this.element 17424 .attr( "autocomplete", "off" ) 17425 .wrap( this._uiSpinnerHtml() ) 17426 .parent() 17427 17428 // Add buttons 17429 .append( this._buttonHtml() ); 17430 }, 17431 _uiSpinnerHtml: function() { 17432 return "<span>"; 17433 }, 17434 17435 _buttonHtml: function() { 17436 return "<a></a><a></a>"; 17437 } 17438 } ); 17439} 17440 17441var widgetsSpinner = $.ui.spinner; 17442 17443 17444/*! 17445 * jQuery UI Tabs 1.14.1 17446 * https://jqueryui.com
vendor: 10,691 bytes, lines 17447-17775
17447 * 17448 * Copyright OpenJS Foundation and other contributors 17449 * Released under the MIT license. 17450 * https://jquery.org/license 17451 */ 17452 17453//>>label: Tabs 17454//>>group: Widgets 17455//>>description: Transforms a set of container elements into a tab structure. 17456//>>docs: https://api.jqueryui.com/tabs/ 17457//>>demos: https://jqueryui.com/tabs/ 17458//>>css.structure: ../../themes/base/core.css 17459//>>css.structure: ../../themes/base/tabs.css 17460//>>css.theme: ../../themes/base/theme.css 17461 17462 17463$.widget( "ui.tabs", { 17464 version: "1.14.1", 17465 delay: 300, 17466 options: { 17467 active: null, 17468 classes: { 17469 "ui-tabs": "ui-corner-all", 17470 "ui-tabs-nav": "ui-corner-all", 17471 "ui-tabs-panel": "ui-corner-bottom", 17472 "ui-tabs-tab": "ui-corner-top" 17473 }, 17474 collapsible: false, 17475 event: "click", 17476 heightStyle: "content", 17477 hide: null, 17478 show: null, 17479 17480 // Callbacks 17481 activate: null, 17482 beforeActivate: null, 17483 beforeLoad: null, 17484 load: null 17485 }, 17486 17487 _isLocal: ( function() { 17488 var rhash = /#.*$/; 17489 17490 return function( anchor ) { 17491 var anchorUrl, locationUrl; 17492 17493 anchorUrl = anchor.href.replace( rhash, "" ); 17494 locationUrl = location.href.replace( rhash, "" ); 17495 17496 // Decoding may throw an error if the URL isn't UTF-8 (#9518) 17497 try { 17498 anchorUrl = decodeURIComponent( anchorUrl ); 17499 } catch ( error ) {} 17500 try { 17501 locationUrl = decodeURIComponent( locationUrl ); 17502 } catch ( error ) {} 17503 17504 return anchor.hash.length > 1 && anchorUrl === locationUrl; 17505 }; 17506 } )(), 17507 17508 _create: function() { 17509 var that = this, 17510 options = this.options; 17511 17512 this.running = false; 17513 17514 this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); 17515 this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); 17516 17517 this._processTabs(); 17518 options.active = this._initialActive(); 17519 17520 // Take disabling tabs via class attribute from HTML 17521 // into account and update option properly. 17522 if ( Array.isArray( options.disabled ) ) { 17523 options.disabled = $.uniqueSort( options.disabled.concat( 17524 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { 17525 return that.tabs.index( li ); 17526 } ) 17527 ) ).sort(); 17528 } 17529 17530 // Check for length avoids error when initializing empty list 17531 if ( this.options.active !== false && this.anchors.length ) { 17532 this.active = this._findActive( options.active ); 17533 } else { 17534 this.active = $(); 17535 } 17536 17537 this._refresh(); 17538 17539 if ( this.active.length ) { 17540 this.load( options.active ); 17541 } 17542 }, 17543 17544 _initialActive: function() { 17545 var active = this.options.active, 17546 collapsible = this.options.collapsible, 17547 locationHashDecoded = decodeURIComponent( location.hash.substring( 1 ) ); 17548 17549 if ( active === null ) { 17550 17551 // check the fragment identifier in the URL 17552 if ( locationHashDecoded ) { 17553 this.tabs.each( function( i, tab ) { 17554 if ( $( tab ).attr( "aria-controls" ) === locationHashDecoded ) { 17555 active = i; 17556 return false; 17557 } 17558 } ); 17559 } 17560 17561 // Check for a tab marked active via a class 17562 if ( active === null ) { 17563 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); 17564 } 17565 17566 // No active tab, set to false 17567 if ( active === null || active === -1 ) { 17568 active = this.tabs.length ? 0 : false; 17569 } 17570 } 17571 17572 // Handle numbers: negative, out of range 17573 if ( active !== false ) { 17574 active = this.tabs.index( this.tabs.eq( active ) ); 17575 if ( active === -1 ) { 17576 active = collapsible ? false : 0; 17577 } 17578 } 17579 17580 // Don't allow collapsible: false and active: false 17581 if ( !collapsible && active === false && this.anchors.length ) { 17582 active = 0; 17583 } 17584 17585 return active; 17586 }, 17587 17588 _getCreateEventData: function() { 17589 return { 17590 tab: this.active, 17591 panel: !this.active.length ? $() : this._getPanelForTab( this.active ) 17592 }; 17593 }, 17594 17595 _tabKeydown: function( event ) { 17596 var focusedTab = $( this.document[ 0 ].activeElement ).closest( "li" ), 17597 selectedIndex = this.tabs.index( focusedTab ), 17598 goingForward = true; 17599 17600 if ( this._handlePageNav( event ) ) { 17601 return; 17602 } 17603 17604 switch ( event.keyCode ) { 17605 case $.ui.keyCode.RIGHT: 17606 case $.ui.keyCode.DOWN: 17607 selectedIndex++; 17608 break; 17609 case $.ui.keyCode.UP: 17610 case $.ui.keyCode.LEFT: 17611 goingForward = false; 17612 selectedIndex--; 17613 break; 17614 case $.ui.keyCode.END: 17615 selectedIndex = this.anchors.length - 1; 17616 break; 17617 case $.ui.keyCode.HOME: 17618 selectedIndex = 0; 17619 break; 17620 case $.ui.keyCode.SPACE: 17621 17622 // Activate only, no collapsing 17623 event.preventDefault(); 17624 clearTimeout( this.activating ); 17625 this._activate( selectedIndex ); 17626 return; 17627 case $.ui.keyCode.ENTER: 17628 17629 // Toggle (cancel delayed activation, allow collapsing) 17630 event.preventDefault(); 17631 clearTimeout( this.activating ); 17632 17633 // Determine if we should collapse or activate 17634 this._activate( selectedIndex === this.options.active ? false : selectedIndex ); 17635 return; 17636 default: 17637 return; 17638 } 17639 17640 // Focus the appropriate tab, based on which key was pressed 17641 event.preventDefault(); 17642 clearTimeout( this.activating ); 17643 selectedIndex = this._focusNextTab( selectedIndex, goingForward ); 17644 17645 // Navigating with control/command key will prevent automatic activation 17646 if ( !event.ctrlKey && !event.metaKey ) { 17647 17648 // Update aria-selected immediately so that AT think the tab is already selected. 17649 // Otherwise AT may confuse the user by stating that they need to activate the tab, 17650 // but the tab will already be activated by the time the announcement finishes. 17651 focusedTab.attr( "aria-selected", "false" ); 17652 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); 17653 17654 this.activating = this._delay( function() { 17655 this.option( "active", selectedIndex ); 17656 }, this.delay ); 17657 } 17658 }, 17659 17660 _panelKeydown: function( event ) { 17661 if ( this._handlePageNav( event ) ) { 17662 return; 17663 } 17664 17665 // Ctrl+up moves focus to the current tab 17666 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { 17667 event.preventDefault(); 17668 this.active.trigger( "focus" ); 17669 } 17670 }, 17671 17672 // Alt+page up/down moves focus to the previous/next tab (and activates) 17673 _handlePageNav: function( event ) { 17674 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { 17675 this._activate( this._focusNextTab( this.options.active - 1, false ) ); 17676 return true; 17677 } 17678 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { 17679 this._activate( this._focusNextTab( this.options.active + 1, true ) ); 17680 return true; 17681 } 17682 }, 17683 17684 _findNextTab: function( index, goingForward ) { 17685 var lastTabIndex = this.tabs.length - 1; 17686 17687 function constrain() { 17688 if ( index > lastTabIndex ) { 17689 index = 0; 17690 } 17691 if ( index < 0 ) { 17692 index = lastTabIndex; 17693 } 17694 return index; 17695 } 17696 17697 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { 17698 index = goingForward ? index + 1 : index - 1; 17699 } 17700 17701 return index; 17702 }, 17703 17704 _focusNextTab: function( index, goingForward ) { 17705 index = this._findNextTab( index, goingForward ); 17706 this.tabs.eq( index ).trigger( "focus" ); 17707 return index; 17708 }, 17709 17710 _setOption: function( key, value ) { 17711 if ( key === "active" ) { 17712 17713 // _activate() will handle invalid values and update this.options 17714 this._activate( value ); 17715 return; 17716 } 17717 17718 this._super( key, value ); 17719 17720 if ( key === "collapsible" ) { 17721 this._toggleClass( "ui-tabs-collapsible", null, value ); 17722 17723 // Setting collapsible: false while collapsed; open first panel 17724 if ( !value && this.options.active === false ) { 17725 this._activate( 0 ); 17726 } 17727 } 17728 17729 if ( key === "event" ) { 17730 this._setupEvents( value ); 17731 } 17732 17733 if ( key === "heightStyle" ) { 17734 this._setupHeightStyle( value ); 17735 } 17736 }, 17737 17738 refresh: function() { 17739 var options = this.options, 17740 lis = this.tablist.children( ":has(a[href])" ); 17741 17742 // Get disabled tabs from class attribute from HTML 17743 // this will get converted to a boolean if needed in _refresh() 17744 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { 17745 return lis.index( tab ); 17746 } ); 17747 17748 this._processTabs(); 17749 17750 // Was collapsed or no tabs 17751 if ( options.active === false || !this.anchors.length ) { 17752 options.active = false; 17753 this.active = $(); 17754 17755 // was active, but active tab is gone 17756 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { 17757 17758 // all remaining tabs are disabled 17759 if ( this.tabs.length === options.disabled.length ) { 17760 options.active = false; 17761 this.active = $(); 17762 17763 // activate previous tab 17764 } else { 17765 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); 17766 } 17767 17768 // was active, active tab still exists 17769 } else { 17770 17771 // make sure active index is correct 17772 options.active = this.tabs.index( this.active ); 17773 } 17774 17775 this._refresh();
vendor: 35,423 bytes, lines 17776-18819
17776 }, 17777 17778 _refresh: function() { 17779 this._setOptionDisabled( this.options.disabled ); 17780 this._setupEvents( this.options.event ); 17781 this._setupHeightStyle( this.options.heightStyle ); 17782 17783 this.tabs.not( this.active ).attr( { 17784 "aria-selected": "false", 17785 "aria-expanded": "false", 17786 tabIndex: -1 17787 } ); 17788 this.panels.not( this._getPanelForTab( this.active ) ) 17789 .hide() 17790 .attr( { 17791 "aria-hidden": "true" 17792 } ); 17793 17794 // Make sure one tab is in the tab order 17795 if ( !this.active.length ) { 17796 this.tabs.eq( 0 ).attr( "tabIndex", 0 ); 17797 } else { 17798 this.active 17799 .attr( { 17800 "aria-selected": "true", 17801 "aria-expanded": "true", 17802 tabIndex: 0 17803 } ); 17804 this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); 17805 this._getPanelForTab( this.active ) 17806 .show() 17807 .attr( { 17808 "aria-hidden": "false" 17809 } ); 17810 } 17811 }, 17812 17813 _processTabs: function() { 17814 var that = this, 17815 prevTabs = this.tabs, 17816 prevAnchors = this.anchors, 17817 prevPanels = this.panels; 17818 17819 this.tablist = this._getList().attr( "role", "tablist" ); 17820 this._addClass( this.tablist, "ui-tabs-nav", 17821 "ui-helper-reset ui-helper-clearfix ui-widget-header" ); 17822 17823 // Prevent users from focusing disabled tabs via click 17824 this.tablist 17825 .on( "mousedown" + this.eventNamespace, "> li", function( event ) { 17826 if ( $( this ).is( ".ui-state-disabled" ) ) { 17827 event.preventDefault(); 17828 } 17829 } ); 17830 17831 this.tabs = this.tablist.find( "> li:has(a[href])" ) 17832 .attr( { 17833 role: "tab", 17834 tabIndex: -1 17835 } ); 17836 this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); 17837 17838 this.anchors = this.tabs.map( function() { 17839 return $( "a", this )[ 0 ]; 17840 } ) 17841 .attr( { 17842 tabIndex: -1 17843 } ); 17844 this._addClass( this.anchors, "ui-tabs-anchor" ); 17845 17846 this.panels = $(); 17847 17848 this.anchors.each( function( i, anchor ) { 17849 var selector, panel, panelId, 17850 anchorId = $( anchor ).uniqueId().attr( "id" ), 17851 tab = $( anchor ).closest( "li" ), 17852 originalAriaControls = tab.attr( "aria-controls" ); 17853 17854 // Inline tab 17855 if ( that._isLocal( anchor ) ) { 17856 selector = decodeURIComponent( anchor.hash ); 17857 panelId = selector.substring( 1 ); 17858 panel = that.element.find( "#" + CSS.escape( panelId ) ); 17859 17860 // remote tab 17861 } else { 17862 17863 // If the tab doesn't already have aria-controls, 17864 // generate an id by using a throw-away element 17865 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; 17866 selector = "#" + panelId; 17867 panel = that.element.find( selector ); 17868 if ( !panel.length ) { 17869 panel = that._createPanel( panelId ); 17870 panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); 17871 } 17872 panel.attr( "aria-live", "polite" ); 17873 } 17874 17875 if ( panel.length ) { 17876 that.panels = that.panels.add( panel ); 17877 } 17878 if ( originalAriaControls ) { 17879 tab.data( "ui-tabs-aria-controls", originalAriaControls ); 17880 } 17881 tab.attr( { 17882 "aria-controls": panelId, 17883 "aria-labelledby": anchorId 17884 } ); 17885 panel.attr( "aria-labelledby", anchorId ); 17886 } ); 17887 17888 this.panels.attr( "role", "tabpanel" ); 17889 this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); 17890 17891 // Avoid memory leaks (#10056) 17892 if ( prevTabs ) { 17893 this._off( prevTabs.not( this.tabs ) ); 17894 this._off( prevAnchors.not( this.anchors ) ); 17895 this._off( prevPanels.not( this.panels ) ); 17896 } 17897 }, 17898 17899 // Allow overriding how to find the list for rare usage scenarios (#7715) 17900 _getList: function() { 17901 return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); 17902 }, 17903 17904 _createPanel: function( id ) { 17905 return $( "<div>" ) 17906 .attr( "id", id ) 17907 .data( "ui-tabs-destroy", true ); 17908 }, 17909 17910 _setOptionDisabled: function( disabled ) { 17911 var currentItem, li, i; 17912 17913 if ( Array.isArray( disabled ) ) { 17914 if ( !disabled.length ) { 17915 disabled = false; 17916 } else if ( disabled.length === this.anchors.length ) { 17917 disabled = true; 17918 } 17919 } 17920 17921 // Disable tabs 17922 for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { 17923 currentItem = $( li ); 17924 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { 17925 currentItem.attr( "aria-disabled", "true" ); 17926 this._addClass( currentItem, null, "ui-state-disabled" ); 17927 } else { 17928 currentItem.removeAttr( "aria-disabled" ); 17929 this._removeClass( currentItem, null, "ui-state-disabled" ); 17930 } 17931 } 17932 17933 this.options.disabled = disabled; 17934 17935 this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, 17936 disabled === true ); 17937 }, 17938 17939 _setupEvents: function( event ) { 17940 var events = {}; 17941 if ( event ) { 17942 $.each( event.split( " " ), function( index, eventName ) { 17943 events[ eventName ] = "_eventHandler"; 17944 } ); 17945 } 17946 17947 this._off( this.anchors.add( this.tabs ).add( this.panels ) ); 17948 17949 // Always prevent the default action, even when disabled 17950 this._on( true, this.anchors, { 17951 click: function( event ) { 17952 event.preventDefault(); 17953 } 17954 } ); 17955 this._on( this.anchors, events ); 17956 this._on( this.tabs, { keydown: "_tabKeydown" } ); 17957 this._on( this.panels, { keydown: "_panelKeydown" } ); 17958 17959 this._focusable( this.tabs ); 17960 this._hoverable( this.tabs ); 17961 }, 17962 17963 _setupHeightStyle: function( heightStyle ) { 17964 var maxHeight, 17965 parent = this.element.parent(); 17966 17967 if ( heightStyle === "fill" ) { 17968 maxHeight = parent.height(); 17969 maxHeight -= this.element.outerHeight() - this.element.height(); 17970 17971 this.element.siblings( ":visible" ).each( function() { 17972 var elem = $( this ), 17973 position = elem.css( "position" ); 17974 17975 if ( position === "absolute" || position === "fixed" ) { 17976 return; 17977 } 17978 maxHeight -= elem.outerHeight( true ); 17979 } ); 17980 17981 this.element.children().not( this.panels ).each( function() { 17982 maxHeight -= $( this ).outerHeight( true ); 17983 } ); 17984 17985 this.panels.each( function() { 17986 $( this ).height( Math.max( 0, maxHeight - 17987 $( this ).innerHeight() + $( this ).height() ) ); 17988 } ) 17989 .css( "overflow", "auto" ); 17990 } else if ( heightStyle === "auto" ) { 17991 maxHeight = 0; 17992 this.panels.each( function() { 17993 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 17994 } ).height( maxHeight ); 17995 } 17996 }, 17997 17998 _eventHandler: function( event ) { 17999 var options = this.options, 18000 active = this.active, 18001 anchor = $( event.currentTarget ), 18002 tab = anchor.closest( "li" ), 18003 clickedIsActive = tab[ 0 ] === active[ 0 ], 18004 collapsing = clickedIsActive && options.collapsible, 18005 toShow = collapsing ? $() : this._getPanelForTab( tab ), 18006 toHide = !active.length ? $() : this._getPanelForTab( active ), 18007 eventData = { 18008 oldTab: active, 18009 oldPanel: toHide, 18010 newTab: collapsing ? $() : tab, 18011 newPanel: toShow 18012 }; 18013 18014 event.preventDefault(); 18015 18016 if ( tab.hasClass( "ui-state-disabled" ) || 18017 18018 // tab is already loading 18019 tab.hasClass( "ui-tabs-loading" ) || 18020 18021 // can't switch durning an animation 18022 this.running || 18023 18024 // click on active header, but not collapsible 18025 ( clickedIsActive && !options.collapsible ) || 18026 18027 // allow canceling activation 18028 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 18029 return; 18030 } 18031 18032 options.active = collapsing ? false : this.tabs.index( tab ); 18033 18034 this.active = clickedIsActive ? $() : tab; 18035 if ( this.xhr ) { 18036 this.xhr.abort(); 18037 } 18038 18039 if ( !toHide.length && !toShow.length ) { 18040 $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); 18041 } 18042 18043 if ( toShow.length ) { 18044 this.load( this.tabs.index( tab ), event ); 18045 } 18046 this._toggle( event, eventData ); 18047 }, 18048 18049 // Handles show/hide for selecting tabs 18050 _toggle: function( event, eventData ) { 18051 var that = this, 18052 toShow = eventData.newPanel, 18053 toHide = eventData.oldPanel; 18054 18055 this.running = true; 18056 18057 function complete() { 18058 that.running = false; 18059 that._trigger( "activate", event, eventData ); 18060 } 18061 18062 function show() { 18063 that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); 18064 18065 if ( toShow.length && that.options.show ) { 18066 that._show( toShow, that.options.show, complete ); 18067 } else { 18068 toShow.show(); 18069 complete(); 18070 } 18071 } 18072 18073 // Start out by hiding, then showing, then completing 18074 if ( toHide.length && this.options.hide ) { 18075 this._hide( toHide, this.options.hide, function() { 18076 that._removeClass( eventData.oldTab.closest( "li" ), 18077 "ui-tabs-active", "ui-state-active" ); 18078 show(); 18079 } ); 18080 } else { 18081 this._removeClass( eventData.oldTab.closest( "li" ), 18082 "ui-tabs-active", "ui-state-active" ); 18083 toHide.hide(); 18084 show(); 18085 } 18086 18087 toHide.attr( "aria-hidden", "true" ); 18088 eventData.oldTab.attr( { 18089 "aria-selected": "false", 18090 "aria-expanded": "false" 18091 } ); 18092 18093 // If we're switching tabs, remove the old tab from the tab order. 18094 // If we're opening from collapsed state, remove the previous tab from the tab order. 18095 // If we're collapsing, then keep the collapsing tab in the tab order. 18096 if ( toShow.length && toHide.length ) { 18097 eventData.oldTab.attr( "tabIndex", -1 ); 18098 } else if ( toShow.length ) { 18099 this.tabs.filter( function() { 18100 return $( this ).attr( "tabIndex" ) === 0; 18101 } ) 18102 .attr( "tabIndex", -1 ); 18103 } 18104 18105 toShow.attr( "aria-hidden", "false" ); 18106 eventData.newTab.attr( { 18107 "aria-selected": "true", 18108 "aria-expanded": "true", 18109 tabIndex: 0 18110 } ); 18111 }, 18112 18113 _activate: function( index ) { 18114 var anchor, 18115 active = this._findActive( index ); 18116 18117 // Trying to activate the already active panel 18118 if ( active[ 0 ] === this.active[ 0 ] ) { 18119 return; 18120 } 18121 18122 // Trying to collapse, simulate a click on the current active header 18123 if ( !active.length ) { 18124 active = this.active; 18125 } 18126 18127 anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; 18128 this._eventHandler( { 18129 target: anchor, 18130 currentTarget: anchor, 18131 preventDefault: $.noop 18132 } ); 18133 }, 18134 18135 _findActive: function( index ) { 18136 return index === false ? $() : this.tabs.eq( index ); 18137 }, 18138 18139 _getIndex: function( index ) { 18140 18141 // meta-function to give users option to provide a href string instead of a numerical index. 18142 if ( typeof index === "string" ) { 18143 index = this.anchors.index( this.anchors.filter( "[href$='" + 18144 CSS.escape( index ) + "']" ) ); 18145 } 18146 18147 return index; 18148 }, 18149 18150 _destroy: function() { 18151 if ( this.xhr ) { 18152 this.xhr.abort(); 18153 } 18154 18155 this.tablist 18156 .removeAttr( "role" ) 18157 .off( this.eventNamespace ); 18158 18159 this.anchors 18160 .removeAttr( "role tabIndex" ) 18161 .removeUniqueId(); 18162 18163 this.tabs.add( this.panels ).each( function() { 18164 if ( $.data( this, "ui-tabs-destroy" ) ) { 18165 $( this ).remove(); 18166 } else { 18167 $( this ).removeAttr( "role tabIndex " + 18168 "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); 18169 } 18170 } ); 18171 18172 this.tabs.each( function() { 18173 var li = $( this ), 18174 prev = li.data( "ui-tabs-aria-controls" ); 18175 if ( prev ) { 18176 li 18177 .attr( "aria-controls", prev ) 18178 .removeData( "ui-tabs-aria-controls" ); 18179 } else { 18180 li.removeAttr( "aria-controls" ); 18181 } 18182 } ); 18183 18184 this.panels.show(); 18185 18186 if ( this.options.heightStyle !== "content" ) { 18187 this.panels.css( "height", "" ); 18188 } 18189 }, 18190 18191 enable: function( index ) { 18192 var disabled = this.options.disabled; 18193 if ( disabled === false ) { 18194 return; 18195 } 18196 18197 if ( index === undefined ) { 18198 disabled = false; 18199 } else { 18200 index = this._getIndex( index ); 18201 if ( Array.isArray( disabled ) ) { 18202 disabled = $.map( disabled, function( num ) { 18203 return num !== index ? num : null; 18204 } ); 18205 } else { 18206 disabled = $.map( this.tabs, function( li, num ) { 18207 return num !== index ? num : null; 18208 } ); 18209 } 18210 } 18211 this._setOptionDisabled( disabled ); 18212 }, 18213 18214 disable: function( index ) { 18215 var disabled = this.options.disabled; 18216 if ( disabled === true ) { 18217 return; 18218 } 18219 18220 if ( index === undefined ) { 18221 disabled = true; 18222 } else { 18223 index = this._getIndex( index ); 18224 if ( $.inArray( index, disabled ) !== -1 ) { 18225 return; 18226 } 18227 if ( Array.isArray( disabled ) ) { 18228 disabled = $.merge( [ index ], disabled ).sort(); 18229 } else { 18230 disabled = [ index ]; 18231 } 18232 } 18233 this._setOptionDisabled( disabled ); 18234 }, 18235 18236 load: function( index, event ) { 18237 index = this._getIndex( index ); 18238 var that = this, 18239 tab = this.tabs.eq( index ), 18240 anchor = tab.find( ".ui-tabs-anchor" ), 18241 panel = this._getPanelForTab( tab ), 18242 eventData = { 18243 tab: tab, 18244 panel: panel 18245 }, 18246 complete = function( jqXHR, status ) { 18247 if ( status === "abort" ) { 18248 that.panels.stop( false, true ); 18249 } 18250 18251 that._removeClass( tab, "ui-tabs-loading" ); 18252 panel.removeAttr( "aria-busy" ); 18253 18254 if ( jqXHR === that.xhr ) { 18255 delete that.xhr; 18256 } 18257 }; 18258 18259 // Not remote 18260 if ( this._isLocal( anchor[ 0 ] ) ) { 18261 return; 18262 } 18263 18264 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); 18265 18266 if ( this.xhr.statusText !== "canceled" ) { 18267 this._addClass( tab, "ui-tabs-loading" ); 18268 panel.attr( "aria-busy", "true" ); 18269 18270 this.xhr 18271 .done( function( response, status, jqXHR ) { 18272 panel.html( response ); 18273 that._trigger( "load", event, eventData ); 18274 18275 complete( jqXHR, status ); 18276 } ) 18277 .fail( function( jqXHR, status ) { 18278 complete( jqXHR, status ); 18279 } ); 18280 } 18281 }, 18282 18283 _ajaxSettings: function( anchor, event, eventData ) { 18284 var that = this; 18285 return { 18286 url: anchor.attr( "href" ), 18287 beforeSend: function( jqXHR, settings ) { 18288 return that._trigger( "beforeLoad", event, 18289 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); 18290 } 18291 }; 18292 }, 18293 18294 _getPanelForTab: function( tab ) { 18295 var id = $( tab ).attr( "aria-controls" ); 18296 return this.element.find( "#" + CSS.escape( id ) ); 18297 } 18298} ); 18299 18300// DEPRECATED 18301// TODO: Switch return back to widget declaration at top of file when this is removed 18302if ( $.uiBackCompat === true ) { 18303 18304 // Backcompat for ui-tab class (now ui-tabs-tab) 18305 $.widget( "ui.tabs", $.ui.tabs, { 18306 _processTabs: function() { 18307 this._superApply( arguments ); 18308 this._addClass( this.tabs, "ui-tab" ); 18309 } 18310 } ); 18311} 18312 18313var widgetsTabs = $.ui.tabs; 18314 18315 18316/*! 18317 * jQuery UI Tooltip 1.14.1 18318 * https://jqueryui.com 18319 * 18320 * Copyright OpenJS Foundation and other contributors 18321 * Released under the MIT license. 18322 * https://jquery.org/license 18323 */ 18324 18325//>>label: Tooltip 18326//>>group: Widgets 18327//>>description: Shows additional information for any element on hover or focus. 18328//>>docs: https://api.jqueryui.com/tooltip/ 18329//>>demos: https://jqueryui.com/tooltip/ 18330//>>css.structure: ../../themes/base/core.css 18331//>>css.structure: ../../themes/base/tooltip.css 18332//>>css.theme: ../../themes/base/theme.css 18333 18334 18335$.widget( "ui.tooltip", { 18336 version: "1.14.1", 18337 options: { 18338 classes: { 18339 "ui-tooltip": "ui-corner-all ui-widget-shadow" 18340 }, 18341 content: function() { 18342 var title = $( this ).attr( "title" ); 18343 18344 // Escape title, since we're going from an attribute to raw HTML 18345 return $( "<a>" ).text( title ).html(); 18346 }, 18347 hide: true, 18348 18349 // Disabled elements have inconsistent behavior across browsers (#8661) 18350 items: "[title]:not([disabled])", 18351 position: { 18352 my: "left top+15", 18353 at: "left bottom", 18354 collision: "flipfit flip" 18355 }, 18356 show: true, 18357 track: false, 18358 18359 // Callbacks 18360 close: null, 18361 open: null 18362 }, 18363 18364 _addDescribedBy: function( elem, id ) { 18365 var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); 18366 describedby.push( id ); 18367 elem 18368 .data( "ui-tooltip-id", id ) 18369 .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) ); 18370 }, 18371 18372 _removeDescribedBy: function( elem ) { 18373 var id = elem.data( "ui-tooltip-id" ), 18374 describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), 18375 index = $.inArray( id, describedby ); 18376 18377 if ( index !== -1 ) { 18378 describedby.splice( index, 1 ); 18379 } 18380 18381 elem.removeData( "ui-tooltip-id" ); 18382 describedby = String.prototype.trim.call( describedby.join( " " ) ); 18383 if ( describedby ) { 18384 elem.attr( "aria-describedby", describedby ); 18385 } else { 18386 elem.removeAttr( "aria-describedby" ); 18387 } 18388 }, 18389 18390 _create: function() { 18391 this._on( { 18392 mouseover: "open", 18393 focusin: "open" 18394 } ); 18395 18396 // IDs of generated tooltips, needed for destroy 18397 this.tooltips = {}; 18398 18399 // IDs of parent tooltips where we removed the title attribute 18400 this.parents = {}; 18401 18402 // Append the aria-live region so tooltips announce correctly 18403 this.liveRegion = $( "<div>" ) 18404 .attr( { 18405 role: "log", 18406 "aria-live": "assertive", 18407 "aria-relevant": "additions" 18408 } ) 18409 .appendTo( this.document[ 0 ].body ); 18410 this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); 18411 18412 this.disabledTitles = $( [] ); 18413 }, 18414 18415 _setOption: function( key, value ) { 18416 var that = this; 18417 18418 this._super( key, value ); 18419 18420 if ( key === "content" ) { 18421 $.each( this.tooltips, function( id, tooltipData ) { 18422 that._updateContent( tooltipData.element ); 18423 } ); 18424 } 18425 }, 18426 18427 _setOptionDisabled: function( value ) { 18428 this[ value ? "_disable" : "_enable" ](); 18429 }, 18430 18431 _disable: function() { 18432 var that = this; 18433 18434 // Close open tooltips 18435 $.each( this.tooltips, function( id, tooltipData ) { 18436 var event = $.Event( "blur" ); 18437 event.target = event.currentTarget = tooltipData.element[ 0 ]; 18438 that.close( event, true ); 18439 } ); 18440 18441 // Remove title attributes to prevent native tooltips 18442 this.disabledTitles = this.disabledTitles.add( 18443 this.element.find( this.options.items ).addBack() 18444 .filter( function() { 18445 var element = $( this ); 18446 if ( element.is( "[title]" ) ) { 18447 return element 18448 .data( "ui-tooltip-title", element.attr( "title" ) ) 18449 .removeAttr( "title" ); 18450 } 18451 } ) 18452 ); 18453 }, 18454 18455 _enable: function() { 18456 18457 // restore title attributes 18458 this.disabledTitles.each( function() { 18459 var element = $( this ); 18460 if ( element.data( "ui-tooltip-title" ) ) { 18461 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18462 } 18463 } ); 18464 this.disabledTitles = $( [] ); 18465 }, 18466 18467 open: function( event ) { 18468 var that = this, 18469 target = $( event ? event.target : this.element ) 18470 18471 // we need closest here due to mouseover bubbling, 18472 // but always pointing at the same event target 18473 .closest( this.options.items ); 18474 18475 // No element to show a tooltip for or the tooltip is already open 18476 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 18477 return; 18478 } 18479 18480 if ( target.attr( "title" ) ) { 18481 target.data( "ui-tooltip-title", target.attr( "title" ) ); 18482 } 18483 18484 target.data( "ui-tooltip-open", true ); 18485 18486 // Kill parent tooltips, custom or native, for hover 18487 if ( event && event.type === "mouseover" ) { 18488 target.parents().each( function() { 18489 var parent = $( this ), 18490 blurEvent; 18491 if ( parent.data( "ui-tooltip-open" ) ) { 18492 blurEvent = $.Event( "blur" ); 18493 blurEvent.target = blurEvent.currentTarget = this; 18494 that.close( blurEvent, true ); 18495 } 18496 if ( parent.attr( "title" ) ) { 18497 parent.uniqueId(); 18498 that.parents[ this.id ] = { 18499 element: this, 18500 title: parent.attr( "title" ) 18501 }; 18502 parent.attr( "title", "" ); 18503 } 18504 } ); 18505 } 18506 18507 this._registerCloseHandlers( event, target ); 18508 this._updateContent( target, event ); 18509 }, 18510 18511 _updateContent: function( target, event ) { 18512 var content, 18513 contentOption = this.options.content, 18514 that = this, 18515 eventType = event ? event.type : null; 18516 18517 if ( typeof contentOption === "string" || contentOption.nodeType || 18518 contentOption.jquery ) { 18519 return this._open( event, target, contentOption ); 18520 } 18521 18522 content = contentOption.call( target[ 0 ], function( response ) { 18523 18524 // Ignore async response if tooltip was closed already 18525 if ( !target.data( "ui-tooltip-open" ) ) { 18526 return; 18527 } 18528 18529 // JQuery creates a special event for focusin when it doesn't 18530 // exist natively. To improve performance, the native event 18531 // object is reused and the type is changed. Therefore, we can't 18532 // rely on the type being correct after the event finished 18533 // bubbling, so we set it back to the previous value. (#8740) 18534 if ( event ) { 18535 event.type = eventType; 18536 } 18537 that._open( event, target, response ); 18538 } ); 18539 if ( content ) { 18540 this._open( event, target, content ); 18541 } 18542 }, 18543 18544 _open: function( event, target, content ) { 18545 var tooltipData, tooltip, delayedShow, a11yContent, 18546 positionOption = $.extend( {}, this.options.position ); 18547 18548 if ( !content ) { 18549 return; 18550 } 18551 18552 // Content can be updated multiple times. If the tooltip already 18553 // exists, then just update the content and bail. 18554 tooltipData = this._find( target ); 18555 if ( tooltipData ) { 18556 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); 18557 return; 18558 } 18559 18560 // If we have a title, clear it to prevent the native tooltip 18561 // we have to check first to avoid defining a title if none exists 18562 // (we don't want to cause an element to start matching [title]) 18563 // 18564 // We use removeAttr only for key events, to allow IE to export the correct 18565 // accessible attributes. For mouse events, set to empty string to avoid 18566 // native tooltip showing up (happens only when removing inside mouseover). 18567 if ( target.is( "[title]" ) ) { 18568 if ( event && event.type === "mouseover" ) { 18569 target.attr( "title", "" ); 18570 } else { 18571 target.removeAttr( "title" ); 18572 } 18573 } 18574 18575 tooltipData = this._tooltip( target ); 18576 tooltip = tooltipData.tooltip; 18577 this._addDescribedBy( target, tooltip.attr( "id" ) ); 18578 tooltip.find( ".ui-tooltip-content" ).html( content ); 18579 18580 // Support: Voiceover on OS X, JAWS on IE <= 9 18581 // JAWS announces deletions even when aria-relevant="additions" 18582 // Voiceover will sometimes re-read the entire log region's contents from the beginning 18583 this.liveRegion.children().hide(); 18584 a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() ); 18585 a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); 18586 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 18587 a11yContent.appendTo( this.liveRegion ); 18588 18589 function position( event ) { 18590 positionOption.of = event; 18591 if ( tooltip.is( ":hidden" ) ) { 18592 return; 18593 } 18594 tooltip.position( positionOption ); 18595 } 18596 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 18597 this._on( this.document, { 18598 mousemove: position 18599 } ); 18600 18601 // trigger once to override element-relative positioning 18602 position( event ); 18603 } else { 18604 tooltip.position( $.extend( { 18605 of: target 18606 }, this.options.position ) ); 18607 } 18608 18609 tooltip.hide(); 18610 18611 this._show( tooltip, this.options.show ); 18612 18613 // Handle tracking tooltips that are shown with a delay (#8644). As soon 18614 // as the tooltip is visible, position the tooltip using the most recent 18615 // event. 18616 // Adds the check to add the timers only when both delay and track options are set (#14682) 18617 if ( this.options.track && this.options.show && this.options.show.delay ) { 18618 delayedShow = this.delayedShow = setInterval( function() { 18619 if ( tooltip.is( ":visible" ) ) { 18620 position( positionOption.of ); 18621 clearInterval( delayedShow ); 18622 } 18623 }, 13 ); 18624 } 18625 18626 this._trigger( "open", event, { tooltip: tooltip } ); 18627 }, 18628 18629 _registerCloseHandlers: function( event, target ) { 18630 var events = { 18631 keyup: function( event ) { 18632 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 18633 var fakeEvent = $.Event( event ); 18634 fakeEvent.currentTarget = target[ 0 ]; 18635 this.close( fakeEvent, true ); 18636 } 18637 } 18638 }; 18639 18640 // Only bind remove handler for delegated targets. Non-delegated 18641 // tooltips will handle this in destroy. 18642 if ( target[ 0 ] !== this.element[ 0 ] ) { 18643 events.remove = function() { 18644 var targetElement = this._find( target ); 18645 if ( targetElement ) { 18646 this._removeTooltip( targetElement.tooltip ); 18647 } 18648 }; 18649 } 18650 18651 if ( !event || event.type === "mouseover" ) { 18652 events.mouseleave = "close"; 18653 } 18654 if ( !event || event.type === "focusin" ) { 18655 events.focusout = "close"; 18656 } 18657 this._on( true, target, events ); 18658 }, 18659 18660 close: function( event ) { 18661 var tooltip, 18662 that = this, 18663 target = $( event ? event.currentTarget : this.element ), 18664 tooltipData = this._find( target ); 18665 18666 // The tooltip may already be closed 18667 if ( !tooltipData ) { 18668 18669 // We set ui-tooltip-open immediately upon open (in open()), but only set the 18670 // additional data once there's actually content to show (in _open()). So even if the 18671 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in 18672 // the period between open() and _open(). 18673 target.removeData( "ui-tooltip-open" ); 18674 return; 18675 } 18676 18677 tooltip = tooltipData.tooltip; 18678 18679 // Disabling closes the tooltip, so we need to track when we're closing 18680 // to avoid an infinite loop in case the tooltip becomes disabled on close 18681 if ( tooltipData.closing ) { 18682 return; 18683 } 18684 18685 // Clear the interval for delayed tracking tooltips 18686 clearInterval( this.delayedShow ); 18687 18688 // Only set title if we had one before (see comment in _open()) 18689 // If the title attribute has changed since open(), don't restore 18690 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 18691 target.attr( "title", target.data( "ui-tooltip-title" ) ); 18692 } 18693 18694 this._removeDescribedBy( target ); 18695 18696 tooltipData.hiding = true; 18697 tooltip.stop( true ); 18698 this._hide( tooltip, this.options.hide, function() { 18699 that._removeTooltip( $( this ) ); 18700 } ); 18701 18702 target.removeData( "ui-tooltip-open" ); 18703 this._off( target, "mouseleave focusout keyup" ); 18704 18705 // Remove 'remove' binding only on delegated targets 18706 if ( target[ 0 ] !== this.element[ 0 ] ) { 18707 this._off( target, "remove" ); 18708 } 18709 this._off( this.document, "mousemove" ); 18710 18711 if ( event && event.type === "mouseleave" ) { 18712 $.each( this.parents, function( id, parent ) { 18713 $( parent.element ).attr( "title", parent.title ); 18714 delete that.parents[ id ]; 18715 } ); 18716 } 18717 18718 tooltipData.closing = true; 18719 this._trigger( "close", event, { tooltip: tooltip } ); 18720 if ( !tooltipData.hiding ) { 18721 tooltipData.closing = false; 18722 } 18723 }, 18724 18725 _tooltip: function( element ) { 18726 var tooltip = $( "<div>" ).attr( "role", "tooltip" ), 18727 content = $( "<div>" ).appendTo( tooltip ), 18728 id = tooltip.uniqueId().attr( "id" ); 18729 18730 this._addClass( content, "ui-tooltip-content" ); 18731 this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); 18732 18733 tooltip.appendTo( this._appendTo( element ) ); 18734 18735 return this.tooltips[ id ] = { 18736 element: element, 18737 tooltip: tooltip 18738 }; 18739 }, 18740 18741 _find: function( target ) { 18742 var id = target.data( "ui-tooltip-id" ); 18743 return id ? this.tooltips[ id ] : null; 18744 }, 18745 18746 _removeTooltip: function( tooltip ) { 18747 18748 // Clear the interval for delayed tracking tooltips 18749 clearInterval( this.delayedShow ); 18750 18751 tooltip.remove(); 18752 delete this.tooltips[ tooltip.attr( "id" ) ]; 18753 }, 18754 18755 _appendTo: function( target ) { 18756 var element = target.closest( ".ui-front, dialog" ); 18757 18758 if ( !element.length ) { 18759 element = this.document[ 0 ].body; 18760 } 18761 18762 return element; 18763 }, 18764 18765 _destroy: function() { 18766 var that = this; 18767 18768 // Close open tooltips 18769 $.each( this.tooltips, function( id, tooltipData ) { 18770 18771 // Delegate to close method to handle common cleanup 18772 var event = $.Event( "blur" ), 18773 element = tooltipData.element; 18774 event.target = event.currentTarget = element[ 0 ]; 18775 that.close( event, true ); 18776 18777 // Remove immediately; destroying an open tooltip doesn't use the 18778 // hide animation 18779 $( "#" + id ).remove(); 18780 18781 // Restore the title 18782 if ( element.data( "ui-tooltip-title" ) ) { 18783 18784 // If the title attribute has changed since open(), don't restore 18785 if ( !element.attr( "title" ) ) { 18786 element.attr( "title", element.data( "ui-tooltip-title" ) ); 18787 } 18788 element.removeData( "ui-tooltip-title" ); 18789 } 18790 } ); 18791 this.liveRegion.remove(); 18792 } 18793} ); 18794 18795// DEPRECATED 18796// TODO: Switch return back to widget declaration at top of file when this is removed 18797if ( $.uiBackCompat === true ) { 18798 18799 // Backcompat for tooltipClass option 18800 $.widget( "ui.tooltip", $.ui.tooltip, { 18801 options: { 18802 tooltipClass: null 18803 }, 18804 _tooltip: function() { 18805 var tooltipData = this._superApply( arguments ); 18806 if ( this.options.tooltipClass ) { 18807 tooltipData.tooltip.addClass( this.options.tooltipClass ); 18808 } 18809 return tooltipData; 18810 } 18811 } ); 18812} 18813 18814var widgetsTooltip = $.ui.tooltip; 18815 18816 18817 18818 18819} );
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.