[ Index ] |
PHP Cross Reference of DokuWiki |
[Summary view] [Print] [Text view]
1 /*! jQuery UI - v1.11.4 - 2015-03-11 2 * http://jqueryui.com 3 * Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js 4 * Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */ 5 6 (function( factory ) { 7 if ( typeof define === "function" && define.amd ) { 8 9 // AMD. Register as an anonymous module. 10 define([ "jquery" ], factory ); 11 } else { 12 13 // Browser globals 14 factory( jQuery ); 15 } 16 }(function( $ ) { 17 /*! 18 * jQuery UI Core 1.11.4 19 * http://jqueryui.com 20 * 21 * Copyright jQuery Foundation and other contributors 22 * Released under the MIT license. 23 * http://jquery.org/license 24 * 25 * http://api.jqueryui.com/category/ui-core/ 26 */ 27 28 29 // $.ui might exist from components with no dependencies, e.g., $.ui.position 30 $.ui = $.ui || {}; 31 32 $.extend( $.ui, { 33 version: "1.11.4", 34 35 keyCode: { 36 BACKSPACE: 8, 37 COMMA: 188, 38 DELETE: 46, 39 DOWN: 40, 40 END: 35, 41 ENTER: 13, 42 ESCAPE: 27, 43 HOME: 36, 44 LEFT: 37, 45 PAGE_DOWN: 34, 46 PAGE_UP: 33, 47 PERIOD: 190, 48 RIGHT: 39, 49 SPACE: 32, 50 TAB: 9, 51 UP: 38 52 } 53 }); 54 55 // plugins 56 $.fn.extend({ 57 scrollParent: function( includeHidden ) { 58 var position = this.css( "position" ), 59 excludeStaticParent = position === "absolute", 60 overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, 61 scrollParent = this.parents().filter( function() { 62 var parent = $( this ); 63 if ( excludeStaticParent && parent.css( "position" ) === "static" ) { 64 return false; 65 } 66 return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) ); 67 }).eq( 0 ); 68 69 return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent; 70 }, 71 72 uniqueId: (function() { 73 var uuid = 0; 74 75 return function() { 76 return this.each(function() { 77 if ( !this.id ) { 78 this.id = "ui-id-" + ( ++uuid ); 79 } 80 }); 81 }; 82 })(), 83 84 removeUniqueId: function() { 85 return this.each(function() { 86 if ( /^ui-id-\d+$/.test( this.id ) ) { 87 $( this ).removeAttr( "id" ); 88 } 89 }); 90 } 91 }); 92 93 // selectors 94 function focusable( element, isTabIndexNotNaN ) { 95 var map, mapName, img, 96 nodeName = element.nodeName.toLowerCase(); 97 if ( "area" === nodeName ) { 98 map = element.parentNode; 99 mapName = map.name; 100 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { 101 return false; 102 } 103 img = $( "img[usemap='#" + mapName + "']" )[ 0 ]; 104 return !!img && visible( img ); 105 } 106 return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ? 107 !element.disabled : 108 "a" === nodeName ? 109 element.href || isTabIndexNotNaN : 110 isTabIndexNotNaN) && 111 // the element and all of its ancestors must be visible 112 visible( element ); 113 } 114 115 function visible( element ) { 116 return $.expr.filters.visible( element ) && 117 !$( element ).parents().addBack().filter(function() { 118 return $.css( this, "visibility" ) === "hidden"; 119 }).length; 120 } 121 122 $.extend( $.expr[ ":" ], { 123 data: $.expr.createPseudo ? 124 $.expr.createPseudo(function( dataName ) { 125 return function( elem ) { 126 return !!$.data( elem, dataName ); 127 }; 128 }) : 129 // support: jQuery <1.8 130 function( elem, i, match ) { 131 return !!$.data( elem, match[ 3 ] ); 132 }, 133 134 focusable: function( element ) { 135 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); 136 }, 137 138 tabbable: function( element ) { 139 var tabIndex = $.attr( element, "tabindex" ), 140 isTabIndexNaN = isNaN( tabIndex ); 141 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); 142 } 143 }); 144 145 // support: jQuery <1.8 146 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) { 147 $.each( [ "Width", "Height" ], function( i, name ) { 148 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], 149 type = name.toLowerCase(), 150 orig = { 151 innerWidth: $.fn.innerWidth, 152 innerHeight: $.fn.innerHeight, 153 outerWidth: $.fn.outerWidth, 154 outerHeight: $.fn.outerHeight 155 }; 156 157 function reduce( elem, size, border, margin ) { 158 $.each( side, function() { 159 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; 160 if ( border ) { 161 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; 162 } 163 if ( margin ) { 164 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; 165 } 166 }); 167 return size; 168 } 169 170 $.fn[ "inner" + name ] = function( size ) { 171 if ( size === undefined ) { 172 return orig[ "inner" + name ].call( this ); 173 } 174 175 return this.each(function() { 176 $( this ).css( type, reduce( this, size ) + "px" ); 177 }); 178 }; 179 180 $.fn[ "outer" + name] = function( size, margin ) { 181 if ( typeof size !== "number" ) { 182 return orig[ "outer" + name ].call( this, size ); 183 } 184 185 return this.each(function() { 186 $( this).css( type, reduce( this, size, true, margin ) + "px" ); 187 }); 188 }; 189 }); 190 } 191 192 // support: jQuery <1.8 193 if ( !$.fn.addBack ) { 194 $.fn.addBack = function( selector ) { 195 return this.add( selector == null ? 196 this.prevObject : this.prevObject.filter( selector ) 197 ); 198 }; 199 } 200 201 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) 202 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { 203 $.fn.removeData = (function( removeData ) { 204 return function( key ) { 205 if ( arguments.length ) { 206 return removeData.call( this, $.camelCase( key ) ); 207 } else { 208 return removeData.call( this ); 209 } 210 }; 211 })( $.fn.removeData ); 212 } 213 214 // deprecated 215 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); 216 217 $.fn.extend({ 218 focus: (function( orig ) { 219 return function( delay, fn ) { 220 return typeof delay === "number" ? 221 this.each(function() { 222 var elem = this; 223 setTimeout(function() { 224 $( elem ).focus(); 225 if ( fn ) { 226 fn.call( elem ); 227 } 228 }, delay ); 229 }) : 230 orig.apply( this, arguments ); 231 }; 232 })( $.fn.focus ), 233 234 disableSelection: (function() { 235 var eventType = "onselectstart" in document.createElement( "div" ) ? 236 "selectstart" : 237 "mousedown"; 238 239 return function() { 240 return this.bind( eventType + ".ui-disableSelection", function( event ) { 241 event.preventDefault(); 242 }); 243 }; 244 })(), 245 246 enableSelection: function() { 247 return this.unbind( ".ui-disableSelection" ); 248 }, 249 250 zIndex: function( zIndex ) { 251 if ( zIndex !== undefined ) { 252 return this.css( "zIndex", zIndex ); 253 } 254 255 if ( this.length ) { 256 var elem = $( this[ 0 ] ), position, value; 257 while ( elem.length && elem[ 0 ] !== document ) { 258 // Ignore z-index if position is set to a value where z-index is ignored by the browser 259 // This makes behavior of this function consistent across browsers 260 // WebKit always returns auto if the element is positioned 261 position = elem.css( "position" ); 262 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 263 // IE returns 0 when zIndex is not specified 264 // other browsers return a string 265 // we ignore the case of nested elements with an explicit value of 0 266 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 267 value = parseInt( elem.css( "zIndex" ), 10 ); 268 if ( !isNaN( value ) && value !== 0 ) { 269 return value; 270 } 271 } 272 elem = elem.parent(); 273 } 274 } 275 276 return 0; 277 } 278 }); 279 280 // $.ui.plugin is deprecated. Use $.widget() extensions instead. 281 $.ui.plugin = { 282 add: function( module, option, set ) { 283 var i, 284 proto = $.ui[ module ].prototype; 285 for ( i in set ) { 286 proto.plugins[ i ] = proto.plugins[ i ] || []; 287 proto.plugins[ i ].push( [ option, set[ i ] ] ); 288 } 289 }, 290 call: function( instance, name, args, allowDisconnected ) { 291 var i, 292 set = instance.plugins[ name ]; 293 294 if ( !set ) { 295 return; 296 } 297 298 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) { 299 return; 300 } 301 302 for ( i = 0; i < set.length; i++ ) { 303 if ( instance.options[ set[ i ][ 0 ] ] ) { 304 set[ i ][ 1 ].apply( instance.element, args ); 305 } 306 } 307 } 308 }; 309 310 311 /*! 312 * jQuery UI Widget 1.11.4 313 * http://jqueryui.com 314 * 315 * Copyright jQuery Foundation and other contributors 316 * Released under the MIT license. 317 * http://jquery.org/license 318 * 319 * http://api.jqueryui.com/jQuery.widget/ 320 */ 321 322 323 var widget_uuid = 0, 324 widget_slice = Array.prototype.slice; 325 326 $.cleanData = (function( orig ) { 327 return function( elems ) { 328 var events, elem, i; 329 for ( i = 0; (elem = elems[i]) != null; i++ ) { 330 try { 331 332 // Only trigger remove when necessary to save time 333 events = $._data( elem, "events" ); 334 if ( events && events.remove ) { 335 $( elem ).triggerHandler( "remove" ); 336 } 337 338 // http://bugs.jquery.com/ticket/8235 339 } catch ( e ) {} 340 } 341 orig( elems ); 342 }; 343 })( $.cleanData ); 344 345 $.widget = function( name, base, prototype ) { 346 var fullName, existingConstructor, constructor, basePrototype, 347 // proxiedPrototype allows the provided prototype to remain unmodified 348 // so that it can be used as a mixin for multiple widgets (#8876) 349 proxiedPrototype = {}, 350 namespace = name.split( "." )[ 0 ]; 351 352 name = name.split( "." )[ 1 ]; 353 fullName = namespace + "-" + name; 354 355 if ( !prototype ) { 356 prototype = base; 357 base = $.Widget; 358 } 359 360 // create selector for plugin 361 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { 362 return !!$.data( elem, fullName ); 363 }; 364 365 $[ namespace ] = $[ namespace ] || {}; 366 existingConstructor = $[ namespace ][ name ]; 367 constructor = $[ namespace ][ name ] = function( options, element ) { 368 // allow instantiation without "new" keyword 369 if ( !this._createWidget ) { 370 return new constructor( options, element ); 371 } 372 373 // allow instantiation without initializing for simple inheritance 374 // must use "new" keyword (the code above always passes args) 375 if ( arguments.length ) { 376 this._createWidget( options, element ); 377 } 378 }; 379 // extend with the existing constructor to carry over any static properties 380 $.extend( constructor, existingConstructor, { 381 version: prototype.version, 382 // copy the object used to create the prototype in case we need to 383 // redefine the widget later 384 _proto: $.extend( {}, prototype ), 385 // track widgets that inherit from this widget in case this widget is 386 // redefined after a widget inherits from it 387 _childConstructors: [] 388 }); 389 390 basePrototype = new base(); 391 // we need to make the options hash a property directly on the new instance 392 // otherwise we'll modify the options hash on the prototype that we're 393 // inheriting from 394 basePrototype.options = $.widget.extend( {}, basePrototype.options ); 395 $.each( prototype, function( prop, value ) { 396 if ( !$.isFunction( value ) ) { 397 proxiedPrototype[ prop ] = value; 398 return; 399 } 400 proxiedPrototype[ prop ] = (function() { 401 var _super = function() { 402 return base.prototype[ prop ].apply( this, arguments ); 403 }, 404 _superApply = function( args ) { 405 return base.prototype[ prop ].apply( this, args ); 406 }; 407 return function() { 408 var __super = this._super, 409 __superApply = this._superApply, 410 returnValue; 411 412 this._super = _super; 413 this._superApply = _superApply; 414 415 returnValue = value.apply( this, arguments ); 416 417 this._super = __super; 418 this._superApply = __superApply; 419 420 return returnValue; 421 }; 422 })(); 423 }); 424 constructor.prototype = $.widget.extend( basePrototype, { 425 // TODO: remove support for widgetEventPrefix 426 // always use the name + a colon as the prefix, e.g., draggable:start 427 // don't prefix for widgets that aren't DOM-based 428 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name 429 }, proxiedPrototype, { 430 constructor: constructor, 431 namespace: namespace, 432 widgetName: name, 433 widgetFullName: fullName 434 }); 435 436 // If this widget is being redefined then we need to find all widgets that 437 // are inheriting from it and redefine all of them so that they inherit from 438 // the new version of this widget. We're essentially trying to replace one 439 // level in the prototype chain. 440 if ( existingConstructor ) { 441 $.each( existingConstructor._childConstructors, function( i, child ) { 442 var childPrototype = child.prototype; 443 444 // redefine the child widget using the same prototype that was 445 // originally used, but inherit from the new version of the base 446 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); 447 }); 448 // remove the list of existing child constructors from the old constructor 449 // so the old child constructors can be garbage collected 450 delete existingConstructor._childConstructors; 451 } else { 452 base._childConstructors.push( constructor ); 453 } 454 455 $.widget.bridge( name, constructor ); 456 457 return constructor; 458 }; 459 460 $.widget.extend = function( target ) { 461 var input = widget_slice.call( arguments, 1 ), 462 inputIndex = 0, 463 inputLength = input.length, 464 key, 465 value; 466 for ( ; inputIndex < inputLength; inputIndex++ ) { 467 for ( key in input[ inputIndex ] ) { 468 value = input[ inputIndex ][ key ]; 469 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { 470 // Clone objects 471 if ( $.isPlainObject( value ) ) { 472 target[ key ] = $.isPlainObject( target[ key ] ) ? 473 $.widget.extend( {}, target[ key ], value ) : 474 // Don't extend strings, arrays, etc. with objects 475 $.widget.extend( {}, value ); 476 // Copy everything else by reference 477 } else { 478 target[ key ] = value; 479 } 480 } 481 } 482 } 483 return target; 484 }; 485 486 $.widget.bridge = function( name, object ) { 487 var fullName = object.prototype.widgetFullName || name; 488 $.fn[ name ] = function( options ) { 489 var isMethodCall = typeof options === "string", 490 args = widget_slice.call( arguments, 1 ), 491 returnValue = this; 492 493 if ( isMethodCall ) { 494 this.each(function() { 495 var methodValue, 496 instance = $.data( this, fullName ); 497 if ( options === "instance" ) { 498 returnValue = instance; 499 return false; 500 } 501 if ( !instance ) { 502 return $.error( "cannot call methods on " + name + " prior to initialization; " + 503 "attempted to call method '" + options + "'" ); 504 } 505 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { 506 return $.error( "no such method '" + options + "' for " + name + " widget instance" ); 507 } 508 methodValue = instance[ options ].apply( instance, args ); 509 if ( methodValue !== instance && methodValue !== undefined ) { 510 returnValue = methodValue && methodValue.jquery ? 511 returnValue.pushStack( methodValue.get() ) : 512 methodValue; 513 return false; 514 } 515 }); 516 } else { 517 518 // Allow multiple hashes to be passed on init 519 if ( args.length ) { 520 options = $.widget.extend.apply( null, [ options ].concat(args) ); 521 } 522 523 this.each(function() { 524 var instance = $.data( this, fullName ); 525 if ( instance ) { 526 instance.option( options || {} ); 527 if ( instance._init ) { 528 instance._init(); 529 } 530 } else { 531 $.data( this, fullName, new object( options, this ) ); 532 } 533 }); 534 } 535 536 return returnValue; 537 }; 538 }; 539 540 $.Widget = function( /* options, element */ ) {}; 541 $.Widget._childConstructors = []; 542 543 $.Widget.prototype = { 544 widgetName: "widget", 545 widgetEventPrefix: "", 546 defaultElement: "<div>", 547 options: { 548 disabled: false, 549 550 // callbacks 551 create: null 552 }, 553 _createWidget: function( options, element ) { 554 element = $( element || this.defaultElement || this )[ 0 ]; 555 this.element = $( element ); 556 this.uuid = widget_uuid++; 557 this.eventNamespace = "." + this.widgetName + this.uuid; 558 559 this.bindings = $(); 560 this.hoverable = $(); 561 this.focusable = $(); 562 563 if ( element !== this ) { 564 $.data( element, this.widgetFullName, this ); 565 this._on( true, this.element, { 566 remove: function( event ) { 567 if ( event.target === element ) { 568 this.destroy(); 569 } 570 } 571 }); 572 this.document = $( element.style ? 573 // element within the document 574 element.ownerDocument : 575 // element is window or document 576 element.document || element ); 577 this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); 578 } 579 580 this.options = $.widget.extend( {}, 581 this.options, 582 this._getCreateOptions(), 583 options ); 584 585 this._create(); 586 this._trigger( "create", null, this._getCreateEventData() ); 587 this._init(); 588 }, 589 _getCreateOptions: $.noop, 590 _getCreateEventData: $.noop, 591 _create: $.noop, 592 _init: $.noop, 593 594 destroy: function() { 595 this._destroy(); 596 // we can probably remove the unbind calls in 2.0 597 // all event bindings should go through this._on() 598 this.element 599 .unbind( this.eventNamespace ) 600 .removeData( this.widgetFullName ) 601 // support: jquery <1.6.3 602 // http://bugs.jquery.com/ticket/9413 603 .removeData( $.camelCase( this.widgetFullName ) ); 604 this.widget() 605 .unbind( this.eventNamespace ) 606 .removeAttr( "aria-disabled" ) 607 .removeClass( 608 this.widgetFullName + "-disabled " + 609 "ui-state-disabled" ); 610 611 // clean up events and states 612 this.bindings.unbind( this.eventNamespace ); 613 this.hoverable.removeClass( "ui-state-hover" ); 614 this.focusable.removeClass( "ui-state-focus" ); 615 }, 616 _destroy: $.noop, 617 618 widget: function() { 619 return this.element; 620 }, 621 622 option: function( key, value ) { 623 var options = key, 624 parts, 625 curOption, 626 i; 627 628 if ( arguments.length === 0 ) { 629 // don't return a reference to the internal hash 630 return $.widget.extend( {}, this.options ); 631 } 632 633 if ( typeof key === "string" ) { 634 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 635 options = {}; 636 parts = key.split( "." ); 637 key = parts.shift(); 638 if ( parts.length ) { 639 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 640 for ( i = 0; i < parts.length - 1; i++ ) { 641 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 642 curOption = curOption[ parts[ i ] ]; 643 } 644 key = parts.pop(); 645 if ( arguments.length === 1 ) { 646 return curOption[ key ] === undefined ? null : curOption[ key ]; 647 } 648 curOption[ key ] = value; 649 } else { 650 if ( arguments.length === 1 ) { 651 return this.options[ key ] === undefined ? null : this.options[ key ]; 652 } 653 options[ key ] = value; 654 } 655 } 656 657 this._setOptions( options ); 658 659 return this; 660 }, 661 _setOptions: function( options ) { 662 var key; 663 664 for ( key in options ) { 665 this._setOption( key, options[ key ] ); 666 } 667 668 return this; 669 }, 670 _setOption: function( key, value ) { 671 this.options[ key ] = value; 672 673 if ( key === "disabled" ) { 674 this.widget() 675 .toggleClass( this.widgetFullName + "-disabled", !!value ); 676 677 // If the widget is becoming disabled, then nothing is interactive 678 if ( value ) { 679 this.hoverable.removeClass( "ui-state-hover" ); 680 this.focusable.removeClass( "ui-state-focus" ); 681 } 682 } 683 684 return this; 685 }, 686 687 enable: function() { 688 return this._setOptions({ disabled: false }); 689 }, 690 disable: function() { 691 return this._setOptions({ disabled: true }); 692 }, 693 694 _on: function( suppressDisabledCheck, element, handlers ) { 695 var delegateElement, 696 instance = this; 697 698 // no suppressDisabledCheck flag, shuffle arguments 699 if ( typeof suppressDisabledCheck !== "boolean" ) { 700 handlers = element; 701 element = suppressDisabledCheck; 702 suppressDisabledCheck = false; 703 } 704 705 // no element argument, shuffle and use this.element 706 if ( !handlers ) { 707 handlers = element; 708 element = this.element; 709 delegateElement = this.widget(); 710 } else { 711 element = delegateElement = $( element ); 712 this.bindings = this.bindings.add( element ); 713 } 714 715 $.each( handlers, function( event, handler ) { 716 function handlerProxy() { 717 // allow widgets to customize the disabled handling 718 // - disabled as an array instead of boolean 719 // - disabled class as method for disabling individual parts 720 if ( !suppressDisabledCheck && 721 ( instance.options.disabled === true || 722 $( this ).hasClass( "ui-state-disabled" ) ) ) { 723 return; 724 } 725 return ( typeof handler === "string" ? instance[ handler ] : handler ) 726 .apply( instance, arguments ); 727 } 728 729 // copy the guid so direct unbinding works 730 if ( typeof handler !== "string" ) { 731 handlerProxy.guid = handler.guid = 732 handler.guid || handlerProxy.guid || $.guid++; 733 } 734 735 var match = event.match( /^([\w:-]*)\s*(.*)$/ ), 736 eventName = match[1] + instance.eventNamespace, 737 selector = match[2]; 738 if ( selector ) { 739 delegateElement.delegate( selector, eventName, handlerProxy ); 740 } else { 741 element.bind( eventName, handlerProxy ); 742 } 743 }); 744 }, 745 746 _off: function( element, eventName ) { 747 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + 748 this.eventNamespace; 749 element.unbind( eventName ).undelegate( eventName ); 750 751 // Clear the stack to avoid memory leaks (#10056) 752 this.bindings = $( this.bindings.not( element ).get() ); 753 this.focusable = $( this.focusable.not( element ).get() ); 754 this.hoverable = $( this.hoverable.not( element ).get() ); 755 }, 756 757 _delay: function( handler, delay ) { 758 function handlerProxy() { 759 return ( typeof handler === "string" ? instance[ handler ] : handler ) 760 .apply( instance, arguments ); 761 } 762 var instance = this; 763 return setTimeout( handlerProxy, delay || 0 ); 764 }, 765 766 _hoverable: function( element ) { 767 this.hoverable = this.hoverable.add( element ); 768 this._on( element, { 769 mouseenter: function( event ) { 770 $( event.currentTarget ).addClass( "ui-state-hover" ); 771 }, 772 mouseleave: function( event ) { 773 $( event.currentTarget ).removeClass( "ui-state-hover" ); 774 } 775 }); 776 }, 777 778 _focusable: function( element ) { 779 this.focusable = this.focusable.add( element ); 780 this._on( element, { 781 focusin: function( event ) { 782 $( event.currentTarget ).addClass( "ui-state-focus" ); 783 }, 784 focusout: function( event ) { 785 $( event.currentTarget ).removeClass( "ui-state-focus" ); 786 } 787 }); 788 }, 789 790 _trigger: function( type, event, data ) { 791 var prop, orig, 792 callback = this.options[ type ]; 793 794 data = data || {}; 795 event = $.Event( event ); 796 event.type = ( type === this.widgetEventPrefix ? 797 type : 798 this.widgetEventPrefix + type ).toLowerCase(); 799 // the original event may come from any element 800 // so we need to reset the target on the new event 801 event.target = this.element[ 0 ]; 802 803 // copy original event properties over to the new event 804 orig = event.originalEvent; 805 if ( orig ) { 806 for ( prop in orig ) { 807 if ( !( prop in event ) ) { 808 event[ prop ] = orig[ prop ]; 809 } 810 } 811 } 812 813 this.element.trigger( event, data ); 814 return !( $.isFunction( callback ) && 815 callback.apply( this.element[0], [ event ].concat( data ) ) === false || 816 event.isDefaultPrevented() ); 817 } 818 }; 819 820 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 821 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 822 if ( typeof options === "string" ) { 823 options = { effect: options }; 824 } 825 var hasOptions, 826 effectName = !options ? 827 method : 828 options === true || typeof options === "number" ? 829 defaultEffect : 830 options.effect || defaultEffect; 831 options = options || {}; 832 if ( typeof options === "number" ) { 833 options = { duration: options }; 834 } 835 hasOptions = !$.isEmptyObject( options ); 836 options.complete = callback; 837 if ( options.delay ) { 838 element.delay( options.delay ); 839 } 840 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 841 element[ method ]( options ); 842 } else if ( effectName !== method && element[ effectName ] ) { 843 element[ effectName ]( options.duration, options.easing, callback ); 844 } else { 845 element.queue(function( next ) { 846 $( this )[ method ](); 847 if ( callback ) { 848 callback.call( element[ 0 ] ); 849 } 850 next(); 851 }); 852 } 853 }; 854 }); 855 856 var widget = $.widget; 857 858 859 /*! 860 * jQuery UI Mouse 1.11.4 861 * http://jqueryui.com 862 * 863 * Copyright jQuery Foundation and other contributors 864 * Released under the MIT license. 865 * http://jquery.org/license 866 * 867 * http://api.jqueryui.com/mouse/ 868 */ 869 870 871 var mouseHandled = false; 872 $( document ).mouseup( function() { 873 mouseHandled = false; 874 }); 875 876 var mouse = $.widget("ui.mouse", { 877 version: "1.11.4", 878 options: { 879 cancel: "input,textarea,button,select,option", 880 distance: 1, 881 delay: 0 882 }, 883 _mouseInit: function() { 884 var that = this; 885 886 this.element 887 .bind("mousedown." + this.widgetName, function(event) { 888 return that._mouseDown(event); 889 }) 890 .bind("click." + this.widgetName, function(event) { 891 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { 892 $.removeData(event.target, that.widgetName + ".preventClickEvent"); 893 event.stopImmediatePropagation(); 894 return false; 895 } 896 }); 897 898 this.started = false; 899 }, 900 901 // TODO: make sure destroying one instance of mouse doesn't mess with 902 // other instances of mouse 903 _mouseDestroy: function() { 904 this.element.unbind("." + this.widgetName); 905 if ( this._mouseMoveDelegate ) { 906 this.document 907 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate) 908 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate); 909 } 910 }, 911 912 _mouseDown: function(event) { 913 // don't let more than one widget handle mouseStart 914 if ( mouseHandled ) { 915 return; 916 } 917 918 this._mouseMoved = false; 919 920 // we may have missed mouseup (out of window) 921 (this._mouseStarted && this._mouseUp(event)); 922 923 this._mouseDownEvent = event; 924 925 var that = this, 926 btnIsLeft = (event.which === 1), 927 // event.target.nodeName works around a bug in IE 8 with 928 // disabled inputs (#7620) 929 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); 930 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { 931 return true; 932 } 933 934 this.mouseDelayMet = !this.options.delay; 935 if (!this.mouseDelayMet) { 936 this._mouseDelayTimer = setTimeout(function() { 937 that.mouseDelayMet = true; 938 }, this.options.delay); 939 } 940 941 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 942 this._mouseStarted = (this._mouseStart(event) !== false); 943 if (!this._mouseStarted) { 944 event.preventDefault(); 945 return true; 946 } 947 } 948 949 // Click event may never have fired (Gecko & Opera) 950 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { 951 $.removeData(event.target, this.widgetName + ".preventClickEvent"); 952 } 953 954 // these delegates are required to keep context 955 this._mouseMoveDelegate = function(event) { 956 return that._mouseMove(event); 957 }; 958 this._mouseUpDelegate = function(event) { 959 return that._mouseUp(event); 960 }; 961 962 this.document 963 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 964 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate ); 965 966 event.preventDefault(); 967 968 mouseHandled = true; 969 return true; 970 }, 971 972 _mouseMove: function(event) { 973 // Only check for mouseups outside the document if you've moved inside the document 974 // at least once. This prevents the firing of mouseup in the case of IE<9, which will 975 // fire a mousemove event if content is placed under the cursor. See #7778 976 // Support: IE <9 977 if ( this._mouseMoved ) { 978 // IE mouseup check - mouseup happened when mouse was out of window 979 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { 980 return this._mouseUp(event); 981 982 // Iframe mouseup check - mouseup occurred in another document 983 } else if ( !event.which ) { 984 return this._mouseUp( event ); 985 } 986 } 987 988 if ( event.which || event.button ) { 989 this._mouseMoved = true; 990 } 991 992 if (this._mouseStarted) { 993 this._mouseDrag(event); 994 return event.preventDefault(); 995 } 996 997 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 998 this._mouseStarted = 999 (this._mouseStart(this._mouseDownEvent, event) !== false); 1000 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); 1001 } 1002 1003 return !this._mouseStarted; 1004 }, 1005 1006 _mouseUp: function(event) { 1007 this.document 1008 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 1009 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate ); 1010 1011 if (this._mouseStarted) { 1012 this._mouseStarted = false; 1013 1014 if (event.target === this._mouseDownEvent.target) { 1015 $.data(event.target, this.widgetName + ".preventClickEvent", true); 1016 } 1017 1018 this._mouseStop(event); 1019 } 1020 1021 mouseHandled = false; 1022 return false; 1023 }, 1024 1025 _mouseDistanceMet: function(event) { 1026 return (Math.max( 1027 Math.abs(this._mouseDownEvent.pageX - event.pageX), 1028 Math.abs(this._mouseDownEvent.pageY - event.pageY) 1029 ) >= this.options.distance 1030 ); 1031 }, 1032 1033 _mouseDelayMet: function(/* event */) { 1034 return this.mouseDelayMet; 1035 }, 1036 1037 // These are placeholder methods, to be overriden by extending plugin 1038 _mouseStart: function(/* event */) {}, 1039 _mouseDrag: function(/* event */) {}, 1040 _mouseStop: function(/* event */) {}, 1041 _mouseCapture: function(/* event */) { return true; } 1042 }); 1043 1044 1045 /*! 1046 * jQuery UI Position 1.11.4 1047 * http://jqueryui.com 1048 * 1049 * Copyright jQuery Foundation and other contributors 1050 * Released under the MIT license. 1051 * http://jquery.org/license 1052 * 1053 * http://api.jqueryui.com/position/ 1054 */ 1055 1056 (function() { 1057 1058 $.ui = $.ui || {}; 1059 1060 var cachedScrollbarWidth, supportsOffsetFractions, 1061 max = Math.max, 1062 abs = Math.abs, 1063 round = Math.round, 1064 rhorizontal = /left|center|right/, 1065 rvertical = /top|center|bottom/, 1066 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 1067 rposition = /^\w+/, 1068 rpercent = /%$/, 1069 _position = $.fn.position; 1070 1071 function getOffsets( offsets, width, height ) { 1072 return [ 1073 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 1074 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 1075 ]; 1076 } 1077 1078 function parseCss( element, property ) { 1079 return parseInt( $.css( element, property ), 10 ) || 0; 1080 } 1081 1082 function getDimensions( elem ) { 1083 var raw = elem[0]; 1084 if ( raw.nodeType === 9 ) { 1085 return { 1086 width: elem.width(), 1087 height: elem.height(), 1088 offset: { top: 0, left: 0 } 1089 }; 1090 } 1091 if ( $.isWindow( raw ) ) { 1092 return { 1093 width: elem.width(), 1094 height: elem.height(), 1095 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 1096 }; 1097 } 1098 if ( raw.preventDefault ) { 1099 return { 1100 width: 0, 1101 height: 0, 1102 offset: { top: raw.pageY, left: raw.pageX } 1103 }; 1104 } 1105 return { 1106 width: elem.outerWidth(), 1107 height: elem.outerHeight(), 1108 offset: elem.offset() 1109 }; 1110 } 1111 1112 $.position = { 1113 scrollbarWidth: function() { 1114 if ( cachedScrollbarWidth !== undefined ) { 1115 return cachedScrollbarWidth; 1116 } 1117 var w1, w2, 1118 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), 1119 innerDiv = div.children()[0]; 1120 1121 $( "body" ).append( div ); 1122 w1 = innerDiv.offsetWidth; 1123 div.css( "overflow", "scroll" ); 1124 1125 w2 = innerDiv.offsetWidth; 1126 1127 if ( w1 === w2 ) { 1128 w2 = div[0].clientWidth; 1129 } 1130 1131 div.remove(); 1132 1133 return (cachedScrollbarWidth = w1 - w2); 1134 }, 1135 getScrollInfo: function( within ) { 1136 var overflowX = within.isWindow || within.isDocument ? "" : 1137 within.element.css( "overflow-x" ), 1138 overflowY = within.isWindow || within.isDocument ? "" : 1139 within.element.css( "overflow-y" ), 1140 hasOverflowX = overflowX === "scroll" || 1141 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), 1142 hasOverflowY = overflowY === "scroll" || 1143 ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); 1144 return { 1145 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 1146 height: hasOverflowX ? $.position.scrollbarWidth() : 0 1147 }; 1148 }, 1149 getWithinInfo: function( element ) { 1150 var withinElement = $( element || window ), 1151 isWindow = $.isWindow( withinElement[0] ), 1152 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; 1153 return { 1154 element: withinElement, 1155 isWindow: isWindow, 1156 isDocument: isDocument, 1157 offset: withinElement.offset() || { left: 0, top: 0 }, 1158 scrollLeft: withinElement.scrollLeft(), 1159 scrollTop: withinElement.scrollTop(), 1160 1161 // support: jQuery 1.6.x 1162 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows 1163 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), 1164 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() 1165 }; 1166 } 1167 }; 1168 1169 $.fn.position = function( options ) { 1170 if ( !options || !options.of ) { 1171 return _position.apply( this, arguments ); 1172 } 1173 1174 // make a copy, we don't want to modify arguments 1175 options = $.extend( {}, options ); 1176 1177 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 1178 target = $( options.of ), 1179 within = $.position.getWithinInfo( options.within ), 1180 scrollInfo = $.position.getScrollInfo( within ), 1181 collision = ( options.collision || "flip" ).split( " " ), 1182 offsets = {}; 1183 1184 dimensions = getDimensions( target ); 1185 if ( target[0].preventDefault ) { 1186 // force left top to allow flipping 1187 options.at = "left top"; 1188 } 1189 targetWidth = dimensions.width; 1190 targetHeight = dimensions.height; 1191 targetOffset = dimensions.offset; 1192 // clone to reuse original targetOffset later 1193 basePosition = $.extend( {}, targetOffset ); 1194 1195 // force my and at to have valid horizontal and vertical positions 1196 // if a value is missing or invalid, it will be converted to center 1197 $.each( [ "my", "at" ], function() { 1198 var pos = ( options[ this ] || "" ).split( " " ), 1199 horizontalOffset, 1200 verticalOffset; 1201 1202 if ( pos.length === 1) { 1203 pos = rhorizontal.test( pos[ 0 ] ) ? 1204 pos.concat( [ "center" ] ) : 1205 rvertical.test( pos[ 0 ] ) ? 1206 [ "center" ].concat( pos ) : 1207 [ "center", "center" ]; 1208 } 1209 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 1210 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 1211 1212 // calculate offsets 1213 horizontalOffset = roffset.exec( pos[ 0 ] ); 1214 verticalOffset = roffset.exec( pos[ 1 ] ); 1215 offsets[ this ] = [ 1216 horizontalOffset ? horizontalOffset[ 0 ] : 0, 1217 verticalOffset ? verticalOffset[ 0 ] : 0 1218 ]; 1219 1220 // reduce to just the positions without the offsets 1221 options[ this ] = [ 1222 rposition.exec( pos[ 0 ] )[ 0 ], 1223 rposition.exec( pos[ 1 ] )[ 0 ] 1224 ]; 1225 }); 1226 1227 // normalize collision option 1228 if ( collision.length === 1 ) { 1229 collision[ 1 ] = collision[ 0 ]; 1230 } 1231 1232 if ( options.at[ 0 ] === "right" ) { 1233 basePosition.left += targetWidth; 1234 } else if ( options.at[ 0 ] === "center" ) { 1235 basePosition.left += targetWidth / 2; 1236 } 1237 1238 if ( options.at[ 1 ] === "bottom" ) { 1239 basePosition.top += targetHeight; 1240 } else if ( options.at[ 1 ] === "center" ) { 1241 basePosition.top += targetHeight / 2; 1242 } 1243 1244 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 1245 basePosition.left += atOffset[ 0 ]; 1246 basePosition.top += atOffset[ 1 ]; 1247 1248 return this.each(function() { 1249 var collisionPosition, using, 1250 elem = $( this ), 1251 elemWidth = elem.outerWidth(), 1252 elemHeight = elem.outerHeight(), 1253 marginLeft = parseCss( this, "marginLeft" ), 1254 marginTop = parseCss( this, "marginTop" ), 1255 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, 1256 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, 1257 position = $.extend( {}, basePosition ), 1258 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 1259 1260 if ( options.my[ 0 ] === "right" ) { 1261 position.left -= elemWidth; 1262 } else if ( options.my[ 0 ] === "center" ) { 1263 position.left -= elemWidth / 2; 1264 } 1265 1266 if ( options.my[ 1 ] === "bottom" ) { 1267 position.top -= elemHeight; 1268 } else if ( options.my[ 1 ] === "center" ) { 1269 position.top -= elemHeight / 2; 1270 } 1271 1272 position.left += myOffset[ 0 ]; 1273 position.top += myOffset[ 1 ]; 1274 1275 // if the browser doesn't support fractions, then round for consistent results 1276 if ( !supportsOffsetFractions ) { 1277 position.left = round( position.left ); 1278 position.top = round( position.top ); 1279 } 1280 1281 collisionPosition = { 1282 marginLeft: marginLeft, 1283 marginTop: marginTop 1284 }; 1285 1286 $.each( [ "left", "top" ], function( i, dir ) { 1287 if ( $.ui.position[ collision[ i ] ] ) { 1288 $.ui.position[ collision[ i ] ][ dir ]( position, { 1289 targetWidth: targetWidth, 1290 targetHeight: targetHeight, 1291 elemWidth: elemWidth, 1292 elemHeight: elemHeight, 1293 collisionPosition: collisionPosition, 1294 collisionWidth: collisionWidth, 1295 collisionHeight: collisionHeight, 1296 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 1297 my: options.my, 1298 at: options.at, 1299 within: within, 1300 elem: elem 1301 }); 1302 } 1303 }); 1304 1305 if ( options.using ) { 1306 // adds feedback as second argument to using callback, if present 1307 using = function( props ) { 1308 var left = targetOffset.left - position.left, 1309 right = left + targetWidth - elemWidth, 1310 top = targetOffset.top - position.top, 1311 bottom = top + targetHeight - elemHeight, 1312 feedback = { 1313 target: { 1314 element: target, 1315 left: targetOffset.left, 1316 top: targetOffset.top, 1317 width: targetWidth, 1318 height: targetHeight 1319 }, 1320 element: { 1321 element: elem, 1322 left: position.left, 1323 top: position.top, 1324 width: elemWidth, 1325 height: elemHeight 1326 }, 1327 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", 1328 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" 1329 }; 1330 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { 1331 feedback.horizontal = "center"; 1332 } 1333 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { 1334 feedback.vertical = "middle"; 1335 } 1336 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { 1337 feedback.important = "horizontal"; 1338 } else { 1339 feedback.important = "vertical"; 1340 } 1341 options.using.call( this, props, feedback ); 1342 }; 1343 } 1344 1345 elem.offset( $.extend( position, { using: using } ) ); 1346 }); 1347 }; 1348 1349 $.ui.position = { 1350 fit: { 1351 left: function( position, data ) { 1352 var within = data.within, 1353 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, 1354 outerWidth = within.width, 1355 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1356 overLeft = withinOffset - collisionPosLeft, 1357 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, 1358 newOverRight; 1359 1360 // element is wider than within 1361 if ( data.collisionWidth > outerWidth ) { 1362 // element is initially over the left side of within 1363 if ( overLeft > 0 && overRight <= 0 ) { 1364 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; 1365 position.left += overLeft - newOverRight; 1366 // element is initially over right side of within 1367 } else if ( overRight > 0 && overLeft <= 0 ) { 1368 position.left = withinOffset; 1369 // element is initially over both left and right sides of within 1370 } else { 1371 if ( overLeft > overRight ) { 1372 position.left = withinOffset + outerWidth - data.collisionWidth; 1373 } else { 1374 position.left = withinOffset; 1375 } 1376 } 1377 // too far left -> align with left edge 1378 } else if ( overLeft > 0 ) { 1379 position.left += overLeft; 1380 // too far right -> align with right edge 1381 } else if ( overRight > 0 ) { 1382 position.left -= overRight; 1383 // adjust based on position and margin 1384 } else { 1385 position.left = max( position.left - collisionPosLeft, position.left ); 1386 } 1387 }, 1388 top: function( position, data ) { 1389 var within = data.within, 1390 withinOffset = within.isWindow ? within.scrollTop : within.offset.top, 1391 outerHeight = data.within.height, 1392 collisionPosTop = position.top - data.collisionPosition.marginTop, 1393 overTop = withinOffset - collisionPosTop, 1394 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, 1395 newOverBottom; 1396 1397 // element is taller than within 1398 if ( data.collisionHeight > outerHeight ) { 1399 // element is initially over the top of within 1400 if ( overTop > 0 && overBottom <= 0 ) { 1401 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; 1402 position.top += overTop - newOverBottom; 1403 // element is initially over bottom of within 1404 } else if ( overBottom > 0 && overTop <= 0 ) { 1405 position.top = withinOffset; 1406 // element is initially over both top and bottom of within 1407 } else { 1408 if ( overTop > overBottom ) { 1409 position.top = withinOffset + outerHeight - data.collisionHeight; 1410 } else { 1411 position.top = withinOffset; 1412 } 1413 } 1414 // too far up -> align with top 1415 } else if ( overTop > 0 ) { 1416 position.top += overTop; 1417 // too far down -> align with bottom edge 1418 } else if ( overBottom > 0 ) { 1419 position.top -= overBottom; 1420 // adjust based on position and margin 1421 } else { 1422 position.top = max( position.top - collisionPosTop, position.top ); 1423 } 1424 } 1425 }, 1426 flip: { 1427 left: function( position, data ) { 1428 var within = data.within, 1429 withinOffset = within.offset.left + within.scrollLeft, 1430 outerWidth = within.width, 1431 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, 1432 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1433 overLeft = collisionPosLeft - offsetLeft, 1434 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, 1435 myOffset = data.my[ 0 ] === "left" ? 1436 -data.elemWidth : 1437 data.my[ 0 ] === "right" ? 1438 data.elemWidth : 1439 0, 1440 atOffset = data.at[ 0 ] === "left" ? 1441 data.targetWidth : 1442 data.at[ 0 ] === "right" ? 1443 -data.targetWidth : 1444 0, 1445 offset = -2 * data.offset[ 0 ], 1446 newOverRight, 1447 newOverLeft; 1448 1449 if ( overLeft < 0 ) { 1450 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; 1451 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { 1452 position.left += myOffset + atOffset + offset; 1453 } 1454 } else if ( overRight > 0 ) { 1455 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; 1456 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { 1457 position.left += myOffset + atOffset + offset; 1458 } 1459 } 1460 }, 1461 top: function( position, data ) { 1462 var within = data.within, 1463 withinOffset = within.offset.top + within.scrollTop, 1464 outerHeight = within.height, 1465 offsetTop = within.isWindow ? within.scrollTop : within.offset.top, 1466 collisionPosTop = position.top - data.collisionPosition.marginTop, 1467 overTop = collisionPosTop - offsetTop, 1468 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, 1469 top = data.my[ 1 ] === "top", 1470 myOffset = top ? 1471 -data.elemHeight : 1472 data.my[ 1 ] === "bottom" ? 1473 data.elemHeight : 1474 0, 1475 atOffset = data.at[ 1 ] === "top" ? 1476 data.targetHeight : 1477 data.at[ 1 ] === "bottom" ? 1478 -data.targetHeight : 1479 0, 1480 offset = -2 * data.offset[ 1 ], 1481 newOverTop, 1482 newOverBottom; 1483 if ( overTop < 0 ) { 1484 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; 1485 if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { 1486 position.top += myOffset + atOffset + offset; 1487 } 1488 } else if ( overBottom > 0 ) { 1489 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; 1490 if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { 1491 position.top += myOffset + atOffset + offset; 1492 } 1493 } 1494 } 1495 }, 1496 flipfit: { 1497 left: function() { 1498 $.ui.position.flip.left.apply( this, arguments ); 1499 $.ui.position.fit.left.apply( this, arguments ); 1500 }, 1501 top: function() { 1502 $.ui.position.flip.top.apply( this, arguments ); 1503 $.ui.position.fit.top.apply( this, arguments ); 1504 } 1505 } 1506 }; 1507 1508 // fraction support test 1509 (function() { 1510 var testElement, testElementParent, testElementStyle, offsetLeft, i, 1511 body = document.getElementsByTagName( "body" )[ 0 ], 1512 div = document.createElement( "div" ); 1513 1514 //Create a "fake body" for testing based on method used in jQuery.support 1515 testElement = document.createElement( body ? "div" : "body" ); 1516 testElementStyle = { 1517 visibility: "hidden", 1518 width: 0, 1519 height: 0, 1520 border: 0, 1521 margin: 0, 1522 background: "none" 1523 }; 1524 if ( body ) { 1525 $.extend( testElementStyle, { 1526 position: "absolute", 1527 left: "-1000px", 1528 top: "-1000px" 1529 }); 1530 } 1531 for ( i in testElementStyle ) { 1532 testElement.style[ i ] = testElementStyle[ i ]; 1533 } 1534 testElement.appendChild( div ); 1535 testElementParent = body || document.documentElement; 1536 testElementParent.insertBefore( testElement, testElementParent.firstChild ); 1537 1538 div.style.cssText = "position: absolute; left: 10.7432222px;"; 1539 1540 offsetLeft = $( div ).offset().left; 1541 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; 1542 1543 testElement.innerHTML = ""; 1544 testElementParent.removeChild( testElement ); 1545 })(); 1546 1547 })(); 1548 1549 var position = $.ui.position; 1550 1551 1552 /*! 1553 * jQuery UI Accordion 1.11.4 1554 * http://jqueryui.com 1555 * 1556 * Copyright jQuery Foundation and other contributors 1557 * Released under the MIT license. 1558 * http://jquery.org/license 1559 * 1560 * http://api.jqueryui.com/accordion/ 1561 */ 1562 1563 1564 var accordion = $.widget( "ui.accordion", { 1565 version: "1.11.4", 1566 options: { 1567 active: 0, 1568 animate: {}, 1569 collapsible: false, 1570 event: "click", 1571 header: "> li > :first-child,> :not(li):even", 1572 heightStyle: "auto", 1573 icons: { 1574 activeHeader: "ui-icon-triangle-1-s", 1575 header: "ui-icon-triangle-1-e" 1576 }, 1577 1578 // callbacks 1579 activate: null, 1580 beforeActivate: null 1581 }, 1582 1583 hideProps: { 1584 borderTopWidth: "hide", 1585 borderBottomWidth: "hide", 1586 paddingTop: "hide", 1587 paddingBottom: "hide", 1588 height: "hide" 1589 }, 1590 1591 showProps: { 1592 borderTopWidth: "show", 1593 borderBottomWidth: "show", 1594 paddingTop: "show", 1595 paddingBottom: "show", 1596 height: "show" 1597 }, 1598 1599 _create: function() { 1600 var options = this.options; 1601 this.prevShow = this.prevHide = $(); 1602 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) 1603 // ARIA 1604 .attr( "role", "tablist" ); 1605 1606 // don't allow collapsible: false and active: false / null 1607 if ( !options.collapsible && (options.active === false || options.active == null) ) { 1608 options.active = 0; 1609 } 1610 1611 this._processPanels(); 1612 // handle negative values 1613 if ( options.active < 0 ) { 1614 options.active += this.headers.length; 1615 } 1616 this._refresh(); 1617 }, 1618 1619 _getCreateEventData: function() { 1620 return { 1621 header: this.active, 1622 panel: !this.active.length ? $() : this.active.next() 1623 }; 1624 }, 1625 1626 _createIcons: function() { 1627 var icons = this.options.icons; 1628 if ( icons ) { 1629 $( "<span>" ) 1630 .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) 1631 .prependTo( this.headers ); 1632 this.active.children( ".ui-accordion-header-icon" ) 1633 .removeClass( icons.header ) 1634 .addClass( icons.activeHeader ); 1635 this.headers.addClass( "ui-accordion-icons" ); 1636 } 1637 }, 1638 1639 _destroyIcons: function() { 1640 this.headers 1641 .removeClass( "ui-accordion-icons" ) 1642 .children( ".ui-accordion-header-icon" ) 1643 .remove(); 1644 }, 1645 1646 _destroy: function() { 1647 var contents; 1648 1649 // clean up main element 1650 this.element 1651 .removeClass( "ui-accordion ui-widget ui-helper-reset" ) 1652 .removeAttr( "role" ); 1653 1654 // clean up headers 1655 this.headers 1656 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " + 1657 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) 1658 .removeAttr( "role" ) 1659 .removeAttr( "aria-expanded" ) 1660 .removeAttr( "aria-selected" ) 1661 .removeAttr( "aria-controls" ) 1662 .removeAttr( "tabIndex" ) 1663 .removeUniqueId(); 1664 1665 this._destroyIcons(); 1666 1667 // clean up content panels 1668 contents = this.headers.next() 1669 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " + 1670 "ui-accordion-content ui-accordion-content-active ui-state-disabled" ) 1671 .css( "display", "" ) 1672 .removeAttr( "role" ) 1673 .removeAttr( "aria-hidden" ) 1674 .removeAttr( "aria-labelledby" ) 1675 .removeUniqueId(); 1676 1677 if ( this.options.heightStyle !== "content" ) { 1678 contents.css( "height", "" ); 1679 } 1680 }, 1681 1682 _setOption: function( key, value ) { 1683 if ( key === "active" ) { 1684 // _activate() will handle invalid values and update this.options 1685 this._activate( value ); 1686 return; 1687 } 1688 1689 if ( key === "event" ) { 1690 if ( this.options.event ) { 1691 this._off( this.headers, this.options.event ); 1692 } 1693 this._setupEvents( value ); 1694 } 1695 1696 this._super( key, value ); 1697 1698 // setting collapsible: false while collapsed; open first panel 1699 if ( key === "collapsible" && !value && this.options.active === false ) { 1700 this._activate( 0 ); 1701 } 1702 1703 if ( key === "icons" ) { 1704 this._destroyIcons(); 1705 if ( value ) { 1706 this._createIcons(); 1707 } 1708 } 1709 1710 // #5332 - opacity doesn't cascade to positioned elements in IE 1711 // so we need to add the disabled class to the headers and panels 1712 if ( key === "disabled" ) { 1713 this.element 1714 .toggleClass( "ui-state-disabled", !!value ) 1715 .attr( "aria-disabled", value ); 1716 this.headers.add( this.headers.next() ) 1717 .toggleClass( "ui-state-disabled", !!value ); 1718 } 1719 }, 1720 1721 _keydown: function( event ) { 1722 if ( event.altKey || event.ctrlKey ) { 1723 return; 1724 } 1725 1726 var keyCode = $.ui.keyCode, 1727 length = this.headers.length, 1728 currentIndex = this.headers.index( event.target ), 1729 toFocus = false; 1730 1731 switch ( event.keyCode ) { 1732 case keyCode.RIGHT: 1733 case keyCode.DOWN: 1734 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 1735 break; 1736 case keyCode.LEFT: 1737 case keyCode.UP: 1738 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 1739 break; 1740 case keyCode.SPACE: 1741 case keyCode.ENTER: 1742 this._eventHandler( event ); 1743 break; 1744 case keyCode.HOME: 1745 toFocus = this.headers[ 0 ]; 1746 break; 1747 case keyCode.END: 1748 toFocus = this.headers[ length - 1 ]; 1749 break; 1750 } 1751 1752 if ( toFocus ) { 1753 $( event.target ).attr( "tabIndex", -1 ); 1754 $( toFocus ).attr( "tabIndex", 0 ); 1755 toFocus.focus(); 1756 event.preventDefault(); 1757 } 1758 }, 1759 1760 _panelKeyDown: function( event ) { 1761 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { 1762 $( event.currentTarget ).prev().focus(); 1763 } 1764 }, 1765 1766 refresh: function() { 1767 var options = this.options; 1768 this._processPanels(); 1769 1770 // was collapsed or no panel 1771 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { 1772 options.active = false; 1773 this.active = $(); 1774 // active false only when collapsible is true 1775 } else if ( options.active === false ) { 1776 this._activate( 0 ); 1777 // was active, but active panel is gone 1778 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 1779 // all remaining panel are disabled 1780 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { 1781 options.active = false; 1782 this.active = $(); 1783 // activate previous panel 1784 } else { 1785 this._activate( Math.max( 0, options.active - 1 ) ); 1786 } 1787 // was active, active panel still exists 1788 } else { 1789 // make sure active index is correct 1790 options.active = this.headers.index( this.active ); 1791 } 1792 1793 this._destroyIcons(); 1794 1795 this._refresh(); 1796 }, 1797 1798 _processPanels: function() { 1799 var prevHeaders = this.headers, 1800 prevPanels = this.panels; 1801 1802 this.headers = this.element.find( this.options.header ) 1803 .addClass( "ui-accordion-header ui-state-default ui-corner-all" ); 1804 1805 this.panels = this.headers.next() 1806 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) 1807 .filter( ":not(.ui-accordion-content-active)" ) 1808 .hide(); 1809 1810 // Avoid memory leaks (#10056) 1811 if ( prevPanels ) { 1812 this._off( prevHeaders.not( this.headers ) ); 1813 this._off( prevPanels.not( this.panels ) ); 1814 } 1815 }, 1816 1817 _refresh: function() { 1818 var maxHeight, 1819 options = this.options, 1820 heightStyle = options.heightStyle, 1821 parent = this.element.parent(); 1822 1823 this.active = this._findActive( options.active ) 1824 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) 1825 .removeClass( "ui-corner-all" ); 1826 this.active.next() 1827 .addClass( "ui-accordion-content-active" ) 1828 .show(); 1829 1830 this.headers 1831 .attr( "role", "tab" ) 1832 .each(function() { 1833 var header = $( this ), 1834 headerId = header.uniqueId().attr( "id" ), 1835 panel = header.next(), 1836 panelId = panel.uniqueId().attr( "id" ); 1837 header.attr( "aria-controls", panelId ); 1838 panel.attr( "aria-labelledby", headerId ); 1839 }) 1840 .next() 1841 .attr( "role", "tabpanel" ); 1842 1843 this.headers 1844 .not( this.active ) 1845 .attr({ 1846 "aria-selected": "false", 1847 "aria-expanded": "false", 1848 tabIndex: -1 1849 }) 1850 .next() 1851 .attr({ 1852 "aria-hidden": "true" 1853 }) 1854 .hide(); 1855 1856 // make sure at least one header is in the tab order 1857 if ( !this.active.length ) { 1858 this.headers.eq( 0 ).attr( "tabIndex", 0 ); 1859 } else { 1860 this.active.attr({ 1861 "aria-selected": "true", 1862 "aria-expanded": "true", 1863 tabIndex: 0 1864 }) 1865 .next() 1866 .attr({ 1867 "aria-hidden": "false" 1868 }); 1869 } 1870 1871 this._createIcons(); 1872 1873 this._setupEvents( options.event ); 1874 1875 if ( heightStyle === "fill" ) { 1876 maxHeight = parent.height(); 1877 this.element.siblings( ":visible" ).each(function() { 1878 var elem = $( this ), 1879 position = elem.css( "position" ); 1880 1881 if ( position === "absolute" || position === "fixed" ) { 1882 return; 1883 } 1884 maxHeight -= elem.outerHeight( true ); 1885 }); 1886 1887 this.headers.each(function() { 1888 maxHeight -= $( this ).outerHeight( true ); 1889 }); 1890 1891 this.headers.next() 1892 .each(function() { 1893 $( this ).height( Math.max( 0, maxHeight - 1894 $( this ).innerHeight() + $( this ).height() ) ); 1895 }) 1896 .css( "overflow", "auto" ); 1897 } else if ( heightStyle === "auto" ) { 1898 maxHeight = 0; 1899 this.headers.next() 1900 .each(function() { 1901 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); 1902 }) 1903 .height( maxHeight ); 1904 } 1905 }, 1906 1907 _activate: function( index ) { 1908 var active = this._findActive( index )[ 0 ]; 1909 1910 // trying to activate the already active panel 1911 if ( active === this.active[ 0 ] ) { 1912 return; 1913 } 1914 1915 // trying to collapse, simulate a click on the currently active header 1916 active = active || this.active[ 0 ]; 1917 1918 this._eventHandler({ 1919 target: active, 1920 currentTarget: active, 1921 preventDefault: $.noop 1922 }); 1923 }, 1924 1925 _findActive: function( selector ) { 1926 return typeof selector === "number" ? this.headers.eq( selector ) : $(); 1927 }, 1928 1929 _setupEvents: function( event ) { 1930 var events = { 1931 keydown: "_keydown" 1932 }; 1933 if ( event ) { 1934 $.each( event.split( " " ), function( index, eventName ) { 1935 events[ eventName ] = "_eventHandler"; 1936 }); 1937 } 1938 1939 this._off( this.headers.add( this.headers.next() ) ); 1940 this._on( this.headers, events ); 1941 this._on( this.headers.next(), { keydown: "_panelKeyDown" }); 1942 this._hoverable( this.headers ); 1943 this._focusable( this.headers ); 1944 }, 1945 1946 _eventHandler: function( event ) { 1947 var options = this.options, 1948 active = this.active, 1949 clicked = $( event.currentTarget ), 1950 clickedIsActive = clicked[ 0 ] === active[ 0 ], 1951 collapsing = clickedIsActive && options.collapsible, 1952 toShow = collapsing ? $() : clicked.next(), 1953 toHide = active.next(), 1954 eventData = { 1955 oldHeader: active, 1956 oldPanel: toHide, 1957 newHeader: collapsing ? $() : clicked, 1958 newPanel: toShow 1959 }; 1960 1961 event.preventDefault(); 1962 1963 if ( 1964 // click on active header, but not collapsible 1965 ( clickedIsActive && !options.collapsible ) || 1966 // allow canceling activation 1967 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 1968 return; 1969 } 1970 1971 options.active = collapsing ? false : this.headers.index( clicked ); 1972 1973 // when the call to ._toggle() comes after the class changes 1974 // it causes a very odd bug in IE 8 (see #6720) 1975 this.active = clickedIsActive ? $() : clicked; 1976 this._toggle( eventData ); 1977 1978 // switch classes 1979 // corner classes on the previously active header stay after the animation 1980 active.removeClass( "ui-accordion-header-active ui-state-active" ); 1981 if ( options.icons ) { 1982 active.children( ".ui-accordion-header-icon" ) 1983 .removeClass( options.icons.activeHeader ) 1984 .addClass( options.icons.header ); 1985 } 1986 1987 if ( !clickedIsActive ) { 1988 clicked 1989 .removeClass( "ui-corner-all" ) 1990 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); 1991 if ( options.icons ) { 1992 clicked.children( ".ui-accordion-header-icon" ) 1993 .removeClass( options.icons.header ) 1994 .addClass( options.icons.activeHeader ); 1995 } 1996 1997 clicked 1998 .next() 1999 .addClass( "ui-accordion-content-active" ); 2000 } 2001 }, 2002 2003 _toggle: function( data ) { 2004 var toShow = data.newPanel, 2005 toHide = this.prevShow.length ? this.prevShow : data.oldPanel; 2006 2007 // handle activating a panel during the animation for another activation 2008 this.prevShow.add( this.prevHide ).stop( true, true ); 2009 this.prevShow = toShow; 2010 this.prevHide = toHide; 2011 2012 if ( this.options.animate ) { 2013 this._animate( toShow, toHide, data ); 2014 } else { 2015 toHide.hide(); 2016 toShow.show(); 2017 this._toggleComplete( data ); 2018 } 2019 2020 toHide.attr({ 2021 "aria-hidden": "true" 2022 }); 2023 toHide.prev().attr({ 2024 "aria-selected": "false", 2025 "aria-expanded": "false" 2026 }); 2027 // if we're switching panels, remove the old header from the tab order 2028 // if we're opening from collapsed state, remove the previous header from the tab order 2029 // if we're collapsing, then keep the collapsing header in the tab order 2030 if ( toShow.length && toHide.length ) { 2031 toHide.prev().attr({ 2032 "tabIndex": -1, 2033 "aria-expanded": "false" 2034 }); 2035 } else if ( toShow.length ) { 2036 this.headers.filter(function() { 2037 return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; 2038 }) 2039 .attr( "tabIndex", -1 ); 2040 } 2041 2042 toShow 2043 .attr( "aria-hidden", "false" ) 2044 .prev() 2045 .attr({ 2046 "aria-selected": "true", 2047 "aria-expanded": "true", 2048 tabIndex: 0 2049 }); 2050 }, 2051 2052 _animate: function( toShow, toHide, data ) { 2053 var total, easing, duration, 2054 that = this, 2055 adjust = 0, 2056 boxSizing = toShow.css( "box-sizing" ), 2057 down = toShow.length && 2058 ( !toHide.length || ( toShow.index() < toHide.index() ) ), 2059 animate = this.options.animate || {}, 2060 options = down && animate.down || animate, 2061 complete = function() { 2062 that._toggleComplete( data ); 2063 }; 2064 2065 if ( typeof options === "number" ) { 2066 duration = options; 2067 } 2068 if ( typeof options === "string" ) { 2069 easing = options; 2070 } 2071 // fall back from options to animation in case of partial down settings 2072 easing = easing || options.easing || animate.easing; 2073 duration = duration || options.duration || animate.duration; 2074 2075 if ( !toHide.length ) { 2076 return toShow.animate( this.showProps, duration, easing, complete ); 2077 } 2078 if ( !toShow.length ) { 2079 return toHide.animate( this.hideProps, duration, easing, complete ); 2080 } 2081 2082 total = toShow.show().outerHeight(); 2083 toHide.animate( this.hideProps, { 2084 duration: duration, 2085 easing: easing, 2086 step: function( now, fx ) { 2087 fx.now = Math.round( now ); 2088 } 2089 }); 2090 toShow 2091 .hide() 2092 .animate( this.showProps, { 2093 duration: duration, 2094 easing: easing, 2095 complete: complete, 2096 step: function( now, fx ) { 2097 fx.now = Math.round( now ); 2098 if ( fx.prop !== "height" ) { 2099 if ( boxSizing === "content-box" ) { 2100 adjust += fx.now; 2101 } 2102 } else if ( that.options.heightStyle !== "content" ) { 2103 fx.now = Math.round( total - toHide.outerHeight() - adjust ); 2104 adjust = 0; 2105 } 2106 } 2107 }); 2108 }, 2109 2110 _toggleComplete: function( data ) { 2111 var toHide = data.oldPanel; 2112 2113 toHide 2114 .removeClass( "ui-accordion-content-active" ) 2115 .prev() 2116 .removeClass( "ui-corner-top" ) 2117 .addClass( "ui-corner-all" ); 2118 2119 // Work around for rendering bug in IE (#5421) 2120 if ( toHide.length ) { 2121 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; 2122 } 2123 this._trigger( "activate", null, data ); 2124 } 2125 }); 2126 2127 2128 /*! 2129 * jQuery UI Menu 1.11.4 2130 * http://jqueryui.com 2131 * 2132 * Copyright jQuery Foundation and other contributors 2133 * Released under the MIT license. 2134 * http://jquery.org/license 2135 * 2136 * http://api.jqueryui.com/menu/ 2137 */ 2138 2139 2140 var menu = $.widget( "ui.menu", { 2141 version: "1.11.4", 2142 defaultElement: "<ul>", 2143 delay: 300, 2144 options: { 2145 icons: { 2146 submenu: "ui-icon-carat-1-e" 2147 }, 2148 items: "> *", 2149 menus: "ul", 2150 position: { 2151 my: "left-1 top", 2152 at: "right top" 2153 }, 2154 role: "menu", 2155 2156 // callbacks 2157 blur: null, 2158 focus: null, 2159 select: null 2160 }, 2161 2162 _create: function() { 2163 this.activeMenu = this.element; 2164 2165 // Flag used to prevent firing of the click handler 2166 // as the event bubbles up through nested menus 2167 this.mouseHandled = false; 2168 this.element 2169 .uniqueId() 2170 .addClass( "ui-menu ui-widget ui-widget-content" ) 2171 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) 2172 .attr({ 2173 role: this.options.role, 2174 tabIndex: 0 2175 }); 2176 2177 if ( this.options.disabled ) { 2178 this.element 2179 .addClass( "ui-state-disabled" ) 2180 .attr( "aria-disabled", "true" ); 2181 } 2182 2183 this._on({ 2184 // Prevent focus from sticking to links inside menu after clicking 2185 // them (focus should always stay on UL during navigation). 2186 "mousedown .ui-menu-item": function( event ) { 2187 event.preventDefault(); 2188 }, 2189 "click .ui-menu-item": function( event ) { 2190 var target = $( event.target ); 2191 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { 2192 this.select( event ); 2193 2194 // Only set the mouseHandled flag if the event will bubble, see #9469. 2195 if ( !event.isPropagationStopped() ) { 2196 this.mouseHandled = true; 2197 } 2198 2199 // Open submenu on click 2200 if ( target.has( ".ui-menu" ).length ) { 2201 this.expand( event ); 2202 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) { 2203 2204 // Redirect focus to the menu 2205 this.element.trigger( "focus", [ true ] ); 2206 2207 // If the active item is on the top level, let it stay active. 2208 // Otherwise, blur the active item since it is no longer visible. 2209 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { 2210 clearTimeout( this.timer ); 2211 } 2212 } 2213 } 2214 }, 2215 "mouseenter .ui-menu-item": function( event ) { 2216 // Ignore mouse events while typeahead is active, see #10458. 2217 // Prevents focusing the wrong item when typeahead causes a scroll while the mouse 2218 // is over an item in the menu 2219 if ( this.previousFilter ) { 2220 return; 2221 } 2222 var target = $( event.currentTarget ); 2223 // Remove ui-state-active class from siblings of the newly focused menu item 2224 // to avoid a jump caused by adjacent elements both having a class with a border 2225 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" ); 2226 this.focus( event, target ); 2227 }, 2228 mouseleave: "collapseAll", 2229 "mouseleave .ui-menu": "collapseAll", 2230 focus: function( event, keepActiveItem ) { 2231 // If there's already an active item, keep it active 2232 // If not, activate the first item 2233 var item = this.active || this.element.find( this.options.items ).eq( 0 ); 2234 2235 if ( !keepActiveItem ) { 2236 this.focus( event, item ); 2237 } 2238 }, 2239 blur: function( event ) { 2240 this._delay(function() { 2241 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { 2242 this.collapseAll( event ); 2243 } 2244 }); 2245 }, 2246 keydown: "_keydown" 2247 }); 2248 2249 this.refresh(); 2250 2251 // Clicks outside of a menu collapse any open menus 2252 this._on( this.document, { 2253 click: function( event ) { 2254 if ( this._closeOnDocumentClick( event ) ) { 2255 this.collapseAll( event ); 2256 } 2257 2258 // Reset the mouseHandled flag 2259 this.mouseHandled = false; 2260 } 2261 }); 2262 }, 2263 2264 _destroy: function() { 2265 // Destroy (sub)menus 2266 this.element 2267 .removeAttr( "aria-activedescendant" ) 2268 .find( ".ui-menu" ).addBack() 2269 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" ) 2270 .removeAttr( "role" ) 2271 .removeAttr( "tabIndex" ) 2272 .removeAttr( "aria-labelledby" ) 2273 .removeAttr( "aria-expanded" ) 2274 .removeAttr( "aria-hidden" ) 2275 .removeAttr( "aria-disabled" ) 2276 .removeUniqueId() 2277 .show(); 2278 2279 // Destroy menu items 2280 this.element.find( ".ui-menu-item" ) 2281 .removeClass( "ui-menu-item" ) 2282 .removeAttr( "role" ) 2283 .removeAttr( "aria-disabled" ) 2284 .removeUniqueId() 2285 .removeClass( "ui-state-hover" ) 2286 .removeAttr( "tabIndex" ) 2287 .removeAttr( "role" ) 2288 .removeAttr( "aria-haspopup" ) 2289 .children().each( function() { 2290 var elem = $( this ); 2291 if ( elem.data( "ui-menu-submenu-carat" ) ) { 2292 elem.remove(); 2293 } 2294 }); 2295 2296 // Destroy menu dividers 2297 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); 2298 }, 2299 2300 _keydown: function( event ) { 2301 var match, prev, character, skip, 2302 preventDefault = true; 2303 2304 switch ( event.keyCode ) { 2305 case $.ui.keyCode.PAGE_UP: 2306 this.previousPage( event ); 2307 break; 2308 case $.ui.keyCode.PAGE_DOWN: 2309 this.nextPage( event ); 2310 break; 2311 case $.ui.keyCode.HOME: 2312 this._move( "first", "first", event ); 2313 break; 2314 case $.ui.keyCode.END: 2315 this._move( "last", "last", event ); 2316 break; 2317 case $.ui.keyCode.UP: 2318 this.previous( event ); 2319 break; 2320 case $.ui.keyCode.DOWN: 2321 this.next( event ); 2322 break; 2323 case $.ui.keyCode.LEFT: 2324 this.collapse( event ); 2325 break; 2326 case $.ui.keyCode.RIGHT: 2327 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 2328 this.expand( event ); 2329 } 2330 break; 2331 case $.ui.keyCode.ENTER: 2332 case $.ui.keyCode.SPACE: 2333 this._activate( event ); 2334 break; 2335 case $.ui.keyCode.ESCAPE: 2336 this.collapse( event ); 2337 break; 2338 default: 2339 preventDefault = false; 2340 prev = this.previousFilter || ""; 2341 character = String.fromCharCode( event.keyCode ); 2342 skip = false; 2343 2344 clearTimeout( this.filterTimer ); 2345 2346 if ( character === prev ) { 2347 skip = true; 2348 } else { 2349 character = prev + character; 2350 } 2351 2352 match = this._filterMenuItems( character ); 2353 match = skip && match.index( this.active.next() ) !== -1 ? 2354 this.active.nextAll( ".ui-menu-item" ) : 2355 match; 2356 2357 // If no matches on the current filter, reset to the last character pressed 2358 // to move down the menu to the first item that starts with that character 2359 if ( !match.length ) { 2360 character = String.fromCharCode( event.keyCode ); 2361 match = this._filterMenuItems( character ); 2362 } 2363 2364 if ( match.length ) { 2365 this.focus( event, match ); 2366 this.previousFilter = character; 2367 this.filterTimer = this._delay(function() { 2368 delete this.previousFilter; 2369 }, 1000 ); 2370 } else { 2371 delete this.previousFilter; 2372 } 2373 } 2374 2375 if ( preventDefault ) { 2376 event.preventDefault(); 2377 } 2378 }, 2379 2380 _activate: function( event ) { 2381 if ( !this.active.is( ".ui-state-disabled" ) ) { 2382 if ( this.active.is( "[aria-haspopup='true']" ) ) { 2383 this.expand( event ); 2384 } else { 2385 this.select( event ); 2386 } 2387 } 2388 }, 2389 2390 refresh: function() { 2391 var menus, items, 2392 that = this, 2393 icon = this.options.icons.submenu, 2394 submenus = this.element.find( this.options.menus ); 2395 2396 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ); 2397 2398 // Initialize nested menus 2399 submenus.filter( ":not(.ui-menu)" ) 2400 .addClass( "ui-menu ui-widget ui-widget-content ui-front" ) 2401 .hide() 2402 .attr({ 2403 role: this.options.role, 2404 "aria-hidden": "true", 2405 "aria-expanded": "false" 2406 }) 2407 .each(function() { 2408 var menu = $( this ), 2409 item = menu.parent(), 2410 submenuCarat = $( "<span>" ) 2411 .addClass( "ui-menu-icon ui-icon " + icon ) 2412 .data( "ui-menu-submenu-carat", true ); 2413 2414 item 2415 .attr( "aria-haspopup", "true" ) 2416 .prepend( submenuCarat ); 2417 menu.attr( "aria-labelledby", item.attr( "id" ) ); 2418 }); 2419 2420 menus = submenus.add( this.element ); 2421 items = menus.find( this.options.items ); 2422 2423 // Initialize menu-items containing spaces and/or dashes only as dividers 2424 items.not( ".ui-menu-item" ).each(function() { 2425 var item = $( this ); 2426 if ( that._isDivider( item ) ) { 2427 item.addClass( "ui-widget-content ui-menu-divider" ); 2428 } 2429 }); 2430 2431 // Don't refresh list items that are already adapted 2432 items.not( ".ui-menu-item, .ui-menu-divider" ) 2433 .addClass( "ui-menu-item" ) 2434 .uniqueId() 2435 .attr({ 2436 tabIndex: -1, 2437 role: this._itemRole() 2438 }); 2439 2440 // Add aria-disabled attribute to any disabled menu item 2441 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); 2442 2443 // If the active item has been removed, blur the menu 2444 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 2445 this.blur(); 2446 } 2447 }, 2448 2449 _itemRole: function() { 2450 return { 2451 menu: "menuitem", 2452 listbox: "option" 2453 }[ this.options.role ]; 2454 }, 2455 2456 _setOption: function( key, value ) { 2457 if ( key === "icons" ) { 2458 this.element.find( ".ui-menu-icon" ) 2459 .removeClass( this.options.icons.submenu ) 2460 .addClass( value.submenu ); 2461 } 2462 if ( key === "disabled" ) { 2463 this.element 2464 .toggleClass( "ui-state-disabled", !!value ) 2465 .attr( "aria-disabled", value ); 2466 } 2467 this._super( key, value ); 2468 }, 2469 2470 focus: function( event, item ) { 2471 var nested, focused; 2472 this.blur( event, event && event.type === "focus" ); 2473 2474 this._scrollIntoView( item ); 2475 2476 this.active = item.first(); 2477 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" ); 2478 // Only update aria-activedescendant if there's a role 2479 // otherwise we assume focus is managed elsewhere 2480 if ( this.options.role ) { 2481 this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); 2482 } 2483 2484 // Highlight active parent menu item, if any 2485 this.active 2486 .parent() 2487 .closest( ".ui-menu-item" ) 2488 .addClass( "ui-state-active" ); 2489 2490 if ( event && event.type === "keydown" ) { 2491 this._close(); 2492 } else { 2493 this.timer = this._delay(function() { 2494 this._close(); 2495 }, this.delay ); 2496 } 2497 2498 nested = item.children( ".ui-menu" ); 2499 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { 2500 this._startOpening(nested); 2501 } 2502 this.activeMenu = item.parent(); 2503 2504 this._trigger( "focus", event, { item: item } ); 2505 }, 2506 2507 _scrollIntoView: function( item ) { 2508 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; 2509 if ( this._hasScroll() ) { 2510 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; 2511 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; 2512 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; 2513 scroll = this.activeMenu.scrollTop(); 2514 elementHeight = this.activeMenu.height(); 2515 itemHeight = item.outerHeight(); 2516 2517 if ( offset < 0 ) { 2518 this.activeMenu.scrollTop( scroll + offset ); 2519 } else if ( offset + itemHeight > elementHeight ) { 2520 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); 2521 } 2522 } 2523 }, 2524 2525 blur: function( event, fromFocus ) { 2526 if ( !fromFocus ) { 2527 clearTimeout( this.timer ); 2528 } 2529 2530 if ( !this.active ) { 2531 return; 2532 } 2533 2534 this.active.removeClass( "ui-state-focus" ); 2535 this.active = null; 2536 2537 this._trigger( "blur", event, { item: this.active } ); 2538 }, 2539 2540 _startOpening: function( submenu ) { 2541 clearTimeout( this.timer ); 2542 2543 // Don't open if already open fixes a Firefox bug that caused a .5 pixel 2544 // shift in the submenu position when mousing over the carat icon 2545 if ( submenu.attr( "aria-hidden" ) !== "true" ) { 2546 return; 2547 } 2548 2549 this.timer = this._delay(function() { 2550 this._close(); 2551 this._open( submenu ); 2552 }, this.delay ); 2553 }, 2554 2555 _open: function( submenu ) { 2556 var position = $.extend({ 2557 of: this.active 2558 }, this.options.position ); 2559 2560 clearTimeout( this.timer ); 2561 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) 2562 .hide() 2563 .attr( "aria-hidden", "true" ); 2564 2565 submenu 2566 .show() 2567 .removeAttr( "aria-hidden" ) 2568 .attr( "aria-expanded", "true" ) 2569 .position( position ); 2570 }, 2571 2572 collapseAll: function( event, all ) { 2573 clearTimeout( this.timer ); 2574 this.timer = this._delay(function() { 2575 // If we were passed an event, look for the submenu that contains the event 2576 var currentMenu = all ? this.element : 2577 $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); 2578 2579 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway 2580 if ( !currentMenu.length ) { 2581 currentMenu = this.element; 2582 } 2583 2584 this._close( currentMenu ); 2585 2586 this.blur( event ); 2587 this.activeMenu = currentMenu; 2588 }, this.delay ); 2589 }, 2590 2591 // With no arguments, closes the currently active menu - if nothing is active 2592 // it closes all menus. If passed an argument, it will search for menus BELOW 2593 _close: function( startMenu ) { 2594 if ( !startMenu ) { 2595 startMenu = this.active ? this.active.parent() : this.element; 2596 } 2597 2598 startMenu 2599 .find( ".ui-menu" ) 2600 .hide() 2601 .attr( "aria-hidden", "true" ) 2602 .attr( "aria-expanded", "false" ) 2603 .end() 2604 .find( ".ui-state-active" ).not( ".ui-state-focus" ) 2605 .removeClass( "ui-state-active" ); 2606 }, 2607 2608 _closeOnDocumentClick: function( event ) { 2609 return !$( event.target ).closest( ".ui-menu" ).length; 2610 }, 2611 2612 _isDivider: function( item ) { 2613 2614 // Match hyphen, em dash, en dash 2615 return !/[^\-\u2014\u2013\s]/.test( item.text() ); 2616 }, 2617 2618 collapse: function( event ) { 2619 var newItem = this.active && 2620 this.active.parent().closest( ".ui-menu-item", this.element ); 2621 if ( newItem && newItem.length ) { 2622 this._close(); 2623 this.focus( event, newItem ); 2624 } 2625 }, 2626 2627 expand: function( event ) { 2628 var newItem = this.active && 2629 this.active 2630 .children( ".ui-menu " ) 2631 .find( this.options.items ) 2632 .first(); 2633 2634 if ( newItem && newItem.length ) { 2635 this._open( newItem.parent() ); 2636 2637 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT 2638 this._delay(function() { 2639 this.focus( event, newItem ); 2640 }); 2641 } 2642 }, 2643 2644 next: function( event ) { 2645 this._move( "next", "first", event ); 2646 }, 2647 2648 previous: function( event ) { 2649 this._move( "prev", "last", event ); 2650 }, 2651 2652 isFirstItem: function() { 2653 return this.active && !this.active.prevAll( ".ui-menu-item" ).length; 2654 }, 2655 2656 isLastItem: function() { 2657 return this.active && !this.active.nextAll( ".ui-menu-item" ).length; 2658 }, 2659 2660 _move: function( direction, filter, event ) { 2661 var next; 2662 if ( this.active ) { 2663 if ( direction === "first" || direction === "last" ) { 2664 next = this.active 2665 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) 2666 .eq( -1 ); 2667 } else { 2668 next = this.active 2669 [ direction + "All" ]( ".ui-menu-item" ) 2670 .eq( 0 ); 2671 } 2672 } 2673 if ( !next || !next.length || !this.active ) { 2674 next = this.activeMenu.find( this.options.items )[ filter ](); 2675 } 2676 2677 this.focus( event, next ); 2678 }, 2679 2680 nextPage: function( event ) { 2681 var item, base, height; 2682 2683 if ( !this.active ) { 2684 this.next( event ); 2685 return; 2686 } 2687 if ( this.isLastItem() ) { 2688 return; 2689 } 2690 if ( this._hasScroll() ) { 2691 base = this.active.offset().top; 2692 height = this.element.height(); 2693 this.active.nextAll( ".ui-menu-item" ).each(function() { 2694 item = $( this ); 2695 return item.offset().top - base - height < 0; 2696 }); 2697 2698 this.focus( event, item ); 2699 } else { 2700 this.focus( event, this.activeMenu.find( this.options.items ) 2701 [ !this.active ? "first" : "last" ]() ); 2702 } 2703 }, 2704 2705 previousPage: function( event ) { 2706 var item, base, height; 2707 if ( !this.active ) { 2708 this.next( event ); 2709 return; 2710 } 2711 if ( this.isFirstItem() ) { 2712 return; 2713 } 2714 if ( this._hasScroll() ) { 2715 base = this.active.offset().top; 2716 height = this.element.height(); 2717 this.active.prevAll( ".ui-menu-item" ).each(function() { 2718 item = $( this ); 2719 return item.offset().top - base + height > 0; 2720 }); 2721 2722 this.focus( event, item ); 2723 } else { 2724 this.focus( event, this.activeMenu.find( this.options.items ).first() ); 2725 } 2726 }, 2727 2728 _hasScroll: function() { 2729 return this.element.outerHeight() < this.element.prop( "scrollHeight" ); 2730 }, 2731 2732 select: function( event ) { 2733 // TODO: It should never be possible to not have an active item at this 2734 // point, but the tests don't trigger mouseenter before click. 2735 this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); 2736 var ui = { item: this.active }; 2737 if ( !this.active.has( ".ui-menu" ).length ) { 2738 this.collapseAll( event, true ); 2739 } 2740 this._trigger( "select", event, ui ); 2741 }, 2742 2743 _filterMenuItems: function(character) { 2744 var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), 2745 regex = new RegExp( "^" + escapedCharacter, "i" ); 2746 2747 return this.activeMenu 2748 .find( this.options.items ) 2749 2750 // Only match on items, not dividers or other content (#10571) 2751 .filter( ".ui-menu-item" ) 2752 .filter(function() { 2753 return regex.test( $.trim( $( this ).text() ) ); 2754 }); 2755 } 2756 }); 2757 2758 2759 /*! 2760 * jQuery UI Autocomplete 1.11.4 2761 * http://jqueryui.com 2762 * 2763 * Copyright jQuery Foundation and other contributors 2764 * Released under the MIT license. 2765 * http://jquery.org/license 2766 * 2767 * http://api.jqueryui.com/autocomplete/ 2768 */ 2769 2770 2771 $.widget( "ui.autocomplete", { 2772 version: "1.11.4", 2773 defaultElement: "<input>", 2774 options: { 2775 appendTo: null, 2776 autoFocus: false, 2777 delay: 300, 2778 minLength: 1, 2779 position: { 2780 my: "left top", 2781 at: "left bottom", 2782 collision: "none" 2783 }, 2784 source: null, 2785 2786 // callbacks 2787 change: null, 2788 close: null, 2789 focus: null, 2790 open: null, 2791 response: null, 2792 search: null, 2793 select: null 2794 }, 2795 2796 requestIndex: 0, 2797 pending: 0, 2798 2799 _create: function() { 2800 // Some browsers only repeat keydown events, not keypress events, 2801 // so we use the suppressKeyPress flag to determine if we've already 2802 // handled the keydown event. #7269 2803 // Unfortunately the code for & in keypress is the same as the up arrow, 2804 // so we use the suppressKeyPressRepeat flag to avoid handling keypress 2805 // events when we know the keydown event was used to modify the 2806 // search term. #7799 2807 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, 2808 nodeName = this.element[ 0 ].nodeName.toLowerCase(), 2809 isTextarea = nodeName === "textarea", 2810 isInput = nodeName === "input"; 2811 2812 this.isMultiLine = 2813 // Textareas are always multi-line 2814 isTextarea ? true : 2815 // Inputs are always single-line, even if inside a contentEditable element 2816 // IE also treats inputs as contentEditable 2817 isInput ? false : 2818 // All other element types are determined by whether or not they're contentEditable 2819 this.element.prop( "isContentEditable" ); 2820 2821 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; 2822 this.isNewMenu = true; 2823 2824 this.element 2825 .addClass( "ui-autocomplete-input" ) 2826 .attr( "autocomplete", "off" ); 2827 2828 this._on( this.element, { 2829 keydown: function( event ) { 2830 if ( this.element.prop( "readOnly" ) ) { 2831 suppressKeyPress = true; 2832 suppressInput = true; 2833 suppressKeyPressRepeat = true; 2834 return; 2835 } 2836 2837 suppressKeyPress = false; 2838 suppressInput = false; 2839 suppressKeyPressRepeat = false; 2840 var keyCode = $.ui.keyCode; 2841 switch ( event.keyCode ) { 2842 case keyCode.PAGE_UP: 2843 suppressKeyPress = true; 2844 this._move( "previousPage", event ); 2845 break; 2846 case keyCode.PAGE_DOWN: 2847 suppressKeyPress = true; 2848 this._move( "nextPage", event ); 2849 break; 2850 case keyCode.UP: 2851 suppressKeyPress = true; 2852 this._keyEvent( "previous", event ); 2853 break; 2854 case keyCode.DOWN: 2855 suppressKeyPress = true; 2856 this._keyEvent( "next", event ); 2857 break; 2858 case keyCode.ENTER: 2859 // when menu is open and has focus 2860 if ( this.menu.active ) { 2861 // #6055 - Opera still allows the keypress to occur 2862 // which causes forms to submit 2863 suppressKeyPress = true; 2864 event.preventDefault(); 2865 this.menu.select( event ); 2866 } 2867 break; 2868 case keyCode.TAB: 2869 if ( this.menu.active ) { 2870 this.menu.select( event ); 2871 } 2872 break; 2873 case keyCode.ESCAPE: 2874 if ( this.menu.element.is( ":visible" ) ) { 2875 if ( !this.isMultiLine ) { 2876 this._value( this.term ); 2877 } 2878 this.close( event ); 2879 // Different browsers have different default behavior for escape 2880 // Single press can mean undo or clear 2881 // Double press in IE means clear the whole form 2882 event.preventDefault(); 2883 } 2884 break; 2885 default: 2886 suppressKeyPressRepeat = true; 2887 // search timeout should be triggered before the input value is changed 2888 this._searchTimeout( event ); 2889 break; 2890 } 2891 }, 2892 keypress: function( event ) { 2893 if ( suppressKeyPress ) { 2894 suppressKeyPress = false; 2895 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 2896 event.preventDefault(); 2897 } 2898 return; 2899 } 2900 if ( suppressKeyPressRepeat ) { 2901 return; 2902 } 2903 2904 // replicate some key handlers to allow them to repeat in Firefox and Opera 2905 var keyCode = $.ui.keyCode; 2906 switch ( event.keyCode ) { 2907 case keyCode.PAGE_UP: 2908 this._move( "previousPage", event ); 2909 break; 2910 case keyCode.PAGE_DOWN: 2911 this._move( "nextPage", event ); 2912 break; 2913 case keyCode.UP: 2914 this._keyEvent( "previous", event ); 2915 break; 2916 case keyCode.DOWN: 2917 this._keyEvent( "next", event ); 2918 break; 2919 } 2920 }, 2921 input: function( event ) { 2922 if ( suppressInput ) { 2923 suppressInput = false; 2924 event.preventDefault(); 2925 return; 2926 } 2927 this._searchTimeout( event ); 2928 }, 2929 focus: function() { 2930 this.selectedItem = null; 2931 this.previous = this._value(); 2932 }, 2933 blur: function( event ) { 2934 if ( this.cancelBlur ) { 2935 delete this.cancelBlur; 2936 return; 2937 } 2938 2939 clearTimeout( this.searching ); 2940 this.close( event ); 2941 this._change( event ); 2942 } 2943 }); 2944 2945 this._initSource(); 2946 this.menu = $( "<ul>" ) 2947 .addClass( "ui-autocomplete ui-front" ) 2948 .appendTo( this._appendTo() ) 2949 .menu({ 2950 // disable ARIA support, the live region takes care of that 2951 role: null 2952 }) 2953 .hide() 2954 .menu( "instance" ); 2955 2956 this._on( this.menu.element, { 2957 mousedown: function( event ) { 2958 // prevent moving focus out of the text field 2959 event.preventDefault(); 2960 2961 // IE doesn't prevent moving focus even with event.preventDefault() 2962 // so we set a flag to know when we should ignore the blur event 2963 this.cancelBlur = true; 2964 this._delay(function() { 2965 delete this.cancelBlur; 2966 }); 2967 2968 // clicking on the scrollbar causes focus to shift to the body 2969 // but we can't detect a mouseup or a click immediately afterward 2970 // so we have to track the next mousedown and close the menu if 2971 // the user clicks somewhere outside of the autocomplete 2972 var menuElement = this.menu.element[ 0 ]; 2973 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { 2974 this._delay(function() { 2975 var that = this; 2976 this.document.one( "mousedown", function( event ) { 2977 if ( event.target !== that.element[ 0 ] && 2978 event.target !== menuElement && 2979 !$.contains( menuElement, event.target ) ) { 2980 that.close(); 2981 } 2982 }); 2983 }); 2984 } 2985 }, 2986 menufocus: function( event, ui ) { 2987 var label, item; 2988 // support: Firefox 2989 // Prevent accidental activation of menu items in Firefox (#7024 #9118) 2990 if ( this.isNewMenu ) { 2991 this.isNewMenu = false; 2992 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { 2993 this.menu.blur(); 2994 2995 this.document.one( "mousemove", function() { 2996 $( event.target ).trigger( event.originalEvent ); 2997 }); 2998 2999 return; 3000 } 3001 } 3002 3003 item = ui.item.data( "ui-autocomplete-item" ); 3004 if ( false !== this._trigger( "focus", event, { item: item } ) ) { 3005 // use value to match what will end up in the input, if it was a key event 3006 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { 3007 this._value( item.value ); 3008 } 3009 } 3010 3011 // Announce the value in the liveRegion 3012 label = ui.item.attr( "aria-label" ) || item.value; 3013 if ( label && $.trim( label ).length ) { 3014 this.liveRegion.children().hide(); 3015 $( "<div>" ).text( label ).appendTo( this.liveRegion ); 3016 } 3017 }, 3018 menuselect: function( event, ui ) { 3019 var item = ui.item.data( "ui-autocomplete-item" ), 3020 previous = this.previous; 3021 3022 // only trigger when focus was lost (click on menu) 3023 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { 3024 this.element.focus(); 3025 this.previous = previous; 3026 // #6109 - IE triggers two focus events and the second 3027 // is asynchronous, so we need to reset the previous 3028 // term synchronously and asynchronously :-( 3029 this._delay(function() { 3030 this.previous = previous; 3031 this.selectedItem = item; 3032 }); 3033 } 3034 3035 if ( false !== this._trigger( "select", event, { item: item } ) ) { 3036 this._value( item.value ); 3037 } 3038 // reset the term after the select event 3039 // this allows custom select handling to work properly 3040 this.term = this._value(); 3041 3042 this.close( event ); 3043 this.selectedItem = item; 3044 } 3045 }); 3046 3047 this.liveRegion = $( "<span>", { 3048 role: "status", 3049 "aria-live": "assertive", 3050 "aria-relevant": "additions" 3051 }) 3052 .addClass( "ui-helper-hidden-accessible" ) 3053 .appendTo( this.document[ 0 ].body ); 3054 3055 // turning off autocomplete prevents the browser from remembering the 3056 // value when navigating through history, so we re-enable autocomplete 3057 // if the page is unloaded before the widget is destroyed. #7790 3058 this._on( this.window, { 3059 beforeunload: function() { 3060 this.element.removeAttr( "autocomplete" ); 3061 } 3062 }); 3063 }, 3064 3065 _destroy: function() { 3066 clearTimeout( this.searching ); 3067 this.element 3068 .removeClass( "ui-autocomplete-input" ) 3069 .removeAttr( "autocomplete" ); 3070 this.menu.element.remove(); 3071 this.liveRegion.remove(); 3072 }, 3073 3074 _setOption: function( key, value ) { 3075 this._super( key, value ); 3076 if ( key === "source" ) { 3077 this._initSource(); 3078 } 3079 if ( key === "appendTo" ) { 3080 this.menu.element.appendTo( this._appendTo() ); 3081 } 3082 if ( key === "disabled" && value && this.xhr ) { 3083 this.xhr.abort(); 3084 } 3085 }, 3086 3087 _appendTo: function() { 3088 var element = this.options.appendTo; 3089 3090 if ( element ) { 3091 element = element.jquery || element.nodeType ? 3092 $( element ) : 3093 this.document.find( element ).eq( 0 ); 3094 } 3095 3096 if ( !element || !element[ 0 ] ) { 3097 element = this.element.closest( ".ui-front" ); 3098 } 3099 3100 if ( !element.length ) { 3101 element = this.document[ 0 ].body; 3102 } 3103 3104 return element; 3105 }, 3106 3107 _initSource: function() { 3108 var array, url, 3109 that = this; 3110 if ( $.isArray( this.options.source ) ) { 3111 array = this.options.source; 3112 this.source = function( request, response ) { 3113 response( $.ui.autocomplete.filter( array, request.term ) ); 3114 }; 3115 } else if ( typeof this.options.source === "string" ) { 3116 url = this.options.source; 3117 this.source = function( request, response ) { 3118 if ( that.xhr ) { 3119 that.xhr.abort(); 3120 } 3121 that.xhr = $.ajax({ 3122 url: url, 3123 data: request, 3124 dataType: "json", 3125 success: function( data ) { 3126 response( data ); 3127 }, 3128 error: function() { 3129 response([]); 3130 } 3131 }); 3132 }; 3133 } else { 3134 this.source = this.options.source; 3135 } 3136 }, 3137 3138 _searchTimeout: function( event ) { 3139 clearTimeout( this.searching ); 3140 this.searching = this._delay(function() { 3141 3142 // Search if the value has changed, or if the user retypes the same value (see #7434) 3143 var equalValues = this.term === this._value(), 3144 menuVisible = this.menu.element.is( ":visible" ), 3145 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; 3146 3147 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { 3148 this.selectedItem = null; 3149 this.search( null, event ); 3150 } 3151 }, this.options.delay ); 3152 }, 3153 3154 search: function( value, event ) { 3155 value = value != null ? value : this._value(); 3156 3157 // always save the actual value, not the one passed as an argument 3158 this.term = this._value(); 3159 3160 if ( value.length < this.options.minLength ) { 3161 return this.close( event ); 3162 } 3163 3164 if ( this._trigger( "search", event ) === false ) { 3165 return; 3166 } 3167 3168 return this._search( value ); 3169 }, 3170 3171 _search: function( value ) { 3172 this.pending++; 3173 this.element.addClass( "ui-autocomplete-loading" ); 3174 this.cancelSearch = false; 3175 3176 this.source( { term: value }, this._response() ); 3177 }, 3178 3179 _response: function() { 3180 var index = ++this.requestIndex; 3181 3182 return $.proxy(function( content ) { 3183 if ( index === this.requestIndex ) { 3184 this.__response( content ); 3185 } 3186 3187 this.pending--; 3188 if ( !this.pending ) { 3189 this.element.removeClass( "ui-autocomplete-loading" ); 3190 } 3191 }, this ); 3192 }, 3193 3194 __response: function( content ) { 3195 if ( content ) { 3196 content = this._normalize( content ); 3197 } 3198 this._trigger( "response", null, { content: content } ); 3199 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { 3200 this._suggest( content ); 3201 this._trigger( "open" ); 3202 } else { 3203 // use ._close() instead of .close() so we don't cancel future searches 3204 this._close(); 3205 } 3206 }, 3207 3208 close: function( event ) { 3209 this.cancelSearch = true; 3210 this._close( event ); 3211 }, 3212 3213 _close: function( event ) { 3214 if ( this.menu.element.is( ":visible" ) ) { 3215 this.menu.element.hide(); 3216 this.menu.blur(); 3217 this.isNewMenu = true; 3218 this._trigger( "close", event ); 3219 } 3220 }, 3221 3222 _change: function( event ) { 3223 if ( this.previous !== this._value() ) { 3224 this._trigger( "change", event, { item: this.selectedItem } ); 3225 } 3226 }, 3227 3228 _normalize: function( items ) { 3229 // assume all items have the right format when the first item is complete 3230 if ( items.length && items[ 0 ].label && items[ 0 ].value ) { 3231 return items; 3232 } 3233 return $.map( items, function( item ) { 3234 if ( typeof item === "string" ) { 3235 return { 3236 label: item, 3237 value: item 3238 }; 3239 } 3240 return $.extend( {}, item, { 3241 label: item.label || item.value, 3242 value: item.value || item.label 3243 }); 3244 }); 3245 }, 3246 3247 _suggest: function( items ) { 3248 var ul = this.menu.element.empty(); 3249 this._renderMenu( ul, items ); 3250 this.isNewMenu = true; 3251 this.menu.refresh(); 3252 3253 // size and position menu 3254 ul.show(); 3255 this._resizeMenu(); 3256 ul.position( $.extend({ 3257 of: this.element 3258 }, this.options.position ) ); 3259 3260 if ( this.options.autoFocus ) { 3261 this.menu.next(); 3262 } 3263 }, 3264 3265 _resizeMenu: function() { 3266 var ul = this.menu.element; 3267 ul.outerWidth( Math.max( 3268 // Firefox wraps long text (possibly a rounding bug) 3269 // so we add 1px to avoid the wrapping (#7513) 3270 ul.width( "" ).outerWidth() + 1, 3271 this.element.outerWidth() 3272 ) ); 3273 }, 3274 3275 _renderMenu: function( ul, items ) { 3276 var that = this; 3277 $.each( items, function( index, item ) { 3278 that._renderItemData( ul, item ); 3279 }); 3280 }, 3281 3282 _renderItemData: function( ul, item ) { 3283 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 3284 }, 3285 3286 _renderItem: function( ul, item ) { 3287 return $( "<li>" ).text( item.label ).appendTo( ul ); 3288 }, 3289 3290 _move: function( direction, event ) { 3291 if ( !this.menu.element.is( ":visible" ) ) { 3292 this.search( null, event ); 3293 return; 3294 } 3295 if ( this.menu.isFirstItem() && /^previous/.test( direction ) || 3296 this.menu.isLastItem() && /^next/.test( direction ) ) { 3297 3298 if ( !this.isMultiLine ) { 3299 this._value( this.term ); 3300 } 3301 3302 this.menu.blur(); 3303 return; 3304 } 3305 this.menu[ direction ]( event ); 3306 }, 3307 3308 widget: function() { 3309 return this.menu.element; 3310 }, 3311 3312 _value: function() { 3313 return this.valueMethod.apply( this.element, arguments ); 3314 }, 3315 3316 _keyEvent: function( keyEvent, event ) { 3317 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 3318 this._move( keyEvent, event ); 3319 3320 // prevents moving cursor to beginning/end of the text field in some browsers 3321 event.preventDefault(); 3322 } 3323 } 3324 }); 3325 3326 $.extend( $.ui.autocomplete, { 3327 escapeRegex: function( value ) { 3328 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 3329 }, 3330 filter: function( array, term ) { 3331 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 3332 return $.grep( array, function( value ) { 3333 return matcher.test( value.label || value.value || value ); 3334 }); 3335 } 3336 }); 3337 3338 // live region extension, adding a `messages` option 3339 // NOTE: This is an experimental API. We are still investigating 3340 // a full solution for string manipulation and internationalization. 3341 $.widget( "ui.autocomplete", $.ui.autocomplete, { 3342 options: { 3343 messages: { 3344 noResults: "No search results.", 3345 results: function( amount ) { 3346 return amount + ( amount > 1 ? " results are" : " result is" ) + 3347 " available, use up and down arrow keys to navigate."; 3348 } 3349 } 3350 }, 3351 3352 __response: function( content ) { 3353 var message; 3354 this._superApply( arguments ); 3355 if ( this.options.disabled || this.cancelSearch ) { 3356 return; 3357 } 3358 if ( content && content.length ) { 3359 message = this.options.messages.results( content.length ); 3360 } else { 3361 message = this.options.messages.noResults; 3362 } 3363 this.liveRegion.children().hide(); 3364 $( "<div>" ).text( message ).appendTo( this.liveRegion ); 3365 } 3366 }); 3367 3368 var autocomplete = $.ui.autocomplete; 3369 3370 3371 /*! 3372 * jQuery UI Button 1.11.4 3373 * http://jqueryui.com 3374 * 3375 * Copyright jQuery Foundation and other contributors 3376 * Released under the MIT license. 3377 * http://jquery.org/license 3378 * 3379 * http://api.jqueryui.com/button/ 3380 */ 3381 3382 3383 var lastActive, 3384 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", 3385 typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only", 3386 formResetHandler = function() { 3387 var form = $( this ); 3388 setTimeout(function() { 3389 form.find( ":ui-button" ).button( "refresh" ); 3390 }, 1 ); 3391 }, 3392 radioGroup = function( radio ) { 3393 var name = radio.name, 3394 form = radio.form, 3395 radios = $( [] ); 3396 if ( name ) { 3397 name = name.replace( /'/g, "\\'" ); 3398 if ( form ) { 3399 radios = $( form ).find( "[name='" + name + "'][type=radio]" ); 3400 } else { 3401 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument ) 3402 .filter(function() { 3403 return !this.form; 3404 }); 3405 } 3406 } 3407 return radios; 3408 }; 3409 3410 $.widget( "ui.button", { 3411 version: "1.11.4", 3412 defaultElement: "<button>", 3413 options: { 3414 disabled: null, 3415 text: true, 3416 label: null, 3417 icons: { 3418 primary: null, 3419 secondary: null 3420 } 3421 }, 3422 _create: function() { 3423 this.element.closest( "form" ) 3424 .unbind( "reset" + this.eventNamespace ) 3425 .bind( "reset" + this.eventNamespace, formResetHandler ); 3426 3427 if ( typeof this.options.disabled !== "boolean" ) { 3428 this.options.disabled = !!this.element.prop( "disabled" ); 3429 } else { 3430 this.element.prop( "disabled", this.options.disabled ); 3431 } 3432 3433 this._determineButtonType(); 3434 this.hasTitle = !!this.buttonElement.attr( "title" ); 3435 3436 var that = this, 3437 options = this.options, 3438 toggleButton = this.type === "checkbox" || this.type === "radio", 3439 activeClass = !toggleButton ? "ui-state-active" : ""; 3440 3441 if ( options.label === null ) { 3442 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); 3443 } 3444 3445 this._hoverable( this.buttonElement ); 3446 3447 this.buttonElement 3448 .addClass( baseClasses ) 3449 .attr( "role", "button" ) 3450 .bind( "mouseenter" + this.eventNamespace, function() { 3451 if ( options.disabled ) { 3452 return; 3453 } 3454 if ( this === lastActive ) { 3455 $( this ).addClass( "ui-state-active" ); 3456 } 3457 }) 3458 .bind( "mouseleave" + this.eventNamespace, function() { 3459 if ( options.disabled ) { 3460 return; 3461 } 3462 $( this ).removeClass( activeClass ); 3463 }) 3464 .bind( "click" + this.eventNamespace, function( event ) { 3465 if ( options.disabled ) { 3466 event.preventDefault(); 3467 event.stopImmediatePropagation(); 3468 } 3469 }); 3470 3471 // Can't use _focusable() because the element that receives focus 3472 // and the element that gets the ui-state-focus class are different 3473 this._on({ 3474 focus: function() { 3475 this.buttonElement.addClass( "ui-state-focus" ); 3476 }, 3477 blur: function() { 3478 this.buttonElement.removeClass( "ui-state-focus" ); 3479 } 3480 }); 3481 3482 if ( toggleButton ) { 3483 this.element.bind( "change" + this.eventNamespace, function() { 3484 that.refresh(); 3485 }); 3486 } 3487 3488 if ( this.type === "checkbox" ) { 3489 this.buttonElement.bind( "click" + this.eventNamespace, function() { 3490 if ( options.disabled ) { 3491 return false; 3492 } 3493 }); 3494 } else if ( this.type === "radio" ) { 3495 this.buttonElement.bind( "click" + this.eventNamespace, function() { 3496 if ( options.disabled ) { 3497 return false; 3498 } 3499 $( this ).addClass( "ui-state-active" ); 3500 that.buttonElement.attr( "aria-pressed", "true" ); 3501 3502 var radio = that.element[ 0 ]; 3503 radioGroup( radio ) 3504 .not( radio ) 3505 .map(function() { 3506 return $( this ).button( "widget" )[ 0 ]; 3507 }) 3508 .removeClass( "ui-state-active" ) 3509 .attr( "aria-pressed", "false" ); 3510 }); 3511 } else { 3512 this.buttonElement 3513 .bind( "mousedown" + this.eventNamespace, function() { 3514 if ( options.disabled ) { 3515 return false; 3516 } 3517 $( this ).addClass( "ui-state-active" ); 3518 lastActive = this; 3519 that.document.one( "mouseup", function() { 3520 lastActive = null; 3521 }); 3522 }) 3523 .bind( "mouseup" + this.eventNamespace, function() { 3524 if ( options.disabled ) { 3525 return false; 3526 } 3527 $( this ).removeClass( "ui-state-active" ); 3528 }) 3529 .bind( "keydown" + this.eventNamespace, function(event) { 3530 if ( options.disabled ) { 3531 return false; 3532 } 3533 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { 3534 $( this ).addClass( "ui-state-active" ); 3535 } 3536 }) 3537 // see #8559, we bind to blur here in case the button element loses 3538 // focus between keydown and keyup, it would be left in an "active" state 3539 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { 3540 $( this ).removeClass( "ui-state-active" ); 3541 }); 3542 3543 if ( this.buttonElement.is("a") ) { 3544 this.buttonElement.keyup(function(event) { 3545 if ( event.keyCode === $.ui.keyCode.SPACE ) { 3546 // TODO pass through original event correctly (just as 2nd argument doesn't work) 3547 $( this ).click(); 3548 } 3549 }); 3550 } 3551 } 3552 3553 this._setOption( "disabled", options.disabled ); 3554 this._resetButton(); 3555 }, 3556 3557 _determineButtonType: function() { 3558 var ancestor, labelSelector, checked; 3559 3560 if ( this.element.is("[type=checkbox]") ) { 3561 this.type = "checkbox"; 3562 } else if ( this.element.is("[type=radio]") ) { 3563 this.type = "radio"; 3564 } else if ( this.element.is("input") ) { 3565 this.type = "input"; 3566 } else { 3567 this.type = "button"; 3568 } 3569 3570 if ( this.type === "checkbox" || this.type === "radio" ) { 3571 // we don't search against the document in case the element 3572 // is disconnected from the DOM 3573 ancestor = this.element.parents().last(); 3574 labelSelector = "label[for='" + this.element.attr("id") + "']"; 3575 this.buttonElement = ancestor.find( labelSelector ); 3576 if ( !this.buttonElement.length ) { 3577 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); 3578 this.buttonElement = ancestor.filter( labelSelector ); 3579 if ( !this.buttonElement.length ) { 3580 this.buttonElement = ancestor.find( labelSelector ); 3581 } 3582 } 3583 this.element.addClass( "ui-helper-hidden-accessible" ); 3584 3585 checked = this.element.is( ":checked" ); 3586 if ( checked ) { 3587 this.buttonElement.addClass( "ui-state-active" ); 3588 } 3589 this.buttonElement.prop( "aria-pressed", checked ); 3590 } else { 3591 this.buttonElement = this.element; 3592 } 3593 }, 3594 3595 widget: function() { 3596 return this.buttonElement; 3597 }, 3598 3599 _destroy: function() { 3600 this.element 3601 .removeClass( "ui-helper-hidden-accessible" ); 3602 this.buttonElement 3603 .removeClass( baseClasses + " ui-state-active " + typeClasses ) 3604 .removeAttr( "role" ) 3605 .removeAttr( "aria-pressed" ) 3606 .html( this.buttonElement.find(".ui-button-text").html() ); 3607 3608 if ( !this.hasTitle ) { 3609 this.buttonElement.removeAttr( "title" ); 3610 } 3611 }, 3612 3613 _setOption: function( key, value ) { 3614 this._super( key, value ); 3615 if ( key === "disabled" ) { 3616 this.widget().toggleClass( "ui-state-disabled", !!value ); 3617 this.element.prop( "disabled", !!value ); 3618 if ( value ) { 3619 if ( this.type === "checkbox" || this.type === "radio" ) { 3620 this.buttonElement.removeClass( "ui-state-focus" ); 3621 } else { 3622 this.buttonElement.removeClass( "ui-state-focus ui-state-active" ); 3623 } 3624 } 3625 return; 3626 } 3627 this._resetButton(); 3628 }, 3629 3630 refresh: function() { 3631 //See #8237 & #8828 3632 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); 3633 3634 if ( isDisabled !== this.options.disabled ) { 3635 this._setOption( "disabled", isDisabled ); 3636 } 3637 if ( this.type === "radio" ) { 3638 radioGroup( this.element[0] ).each(function() { 3639 if ( $( this ).is( ":checked" ) ) { 3640 $( this ).button( "widget" ) 3641 .addClass( "ui-state-active" ) 3642 .attr( "aria-pressed", "true" ); 3643 } else { 3644 $( this ).button( "widget" ) 3645 .removeClass( "ui-state-active" ) 3646 .attr( "aria-pressed", "false" ); 3647 } 3648 }); 3649 } else if ( this.type === "checkbox" ) { 3650 if ( this.element.is( ":checked" ) ) { 3651 this.buttonElement 3652 .addClass( "ui-state-active" ) 3653 .attr( "aria-pressed", "true" ); 3654 } else { 3655 this.buttonElement 3656 .removeClass( "ui-state-active" ) 3657 .attr( "aria-pressed", "false" ); 3658 } 3659 } 3660 }, 3661 3662 _resetButton: function() { 3663 if ( this.type === "input" ) { 3664 if ( this.options.label ) { 3665 this.element.val( this.options.label ); 3666 } 3667 return; 3668 } 3669 var buttonElement = this.buttonElement.removeClass( typeClasses ), 3670 buttonText = $( "<span></span>", this.document[0] ) 3671 .addClass( "ui-button-text" ) 3672 .html( this.options.label ) 3673 .appendTo( buttonElement.empty() ) 3674 .text(), 3675 icons = this.options.icons, 3676 multipleIcons = icons.primary && icons.secondary, 3677 buttonClasses = []; 3678 3679 if ( icons.primary || icons.secondary ) { 3680 if ( this.options.text ) { 3681 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); 3682 } 3683 3684 if ( icons.primary ) { 3685 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); 3686 } 3687 3688 if ( icons.secondary ) { 3689 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); 3690 } 3691 3692 if ( !this.options.text ) { 3693 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); 3694 3695 if ( !this.hasTitle ) { 3696 buttonElement.attr( "title", $.trim( buttonText ) ); 3697 } 3698 } 3699 } else { 3700 buttonClasses.push( "ui-button-text-only" ); 3701 } 3702 buttonElement.addClass( buttonClasses.join( " " ) ); 3703 } 3704 }); 3705 3706 $.widget( "ui.buttonset", { 3707 version: "1.11.4", 3708 options: { 3709 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" 3710 }, 3711 3712 _create: function() { 3713 this.element.addClass( "ui-buttonset" ); 3714 }, 3715 3716 _init: function() { 3717 this.refresh(); 3718 }, 3719 3720 _setOption: function( key, value ) { 3721 if ( key === "disabled" ) { 3722 this.buttons.button( "option", key, value ); 3723 } 3724 3725 this._super( key, value ); 3726 }, 3727 3728 refresh: function() { 3729 var rtl = this.element.css( "direction" ) === "rtl", 3730 allButtons = this.element.find( this.options.items ), 3731 existingButtons = allButtons.filter( ":ui-button" ); 3732 3733 // Initialize new buttons 3734 allButtons.not( ":ui-button" ).button(); 3735 3736 // Refresh existing buttons 3737 existingButtons.button( "refresh" ); 3738 3739 this.buttons = allButtons 3740 .map(function() { 3741 return $( this ).button( "widget" )[ 0 ]; 3742 }) 3743 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) 3744 .filter( ":first" ) 3745 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) 3746 .end() 3747 .filter( ":last" ) 3748 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) 3749 .end() 3750 .end(); 3751 }, 3752 3753 _destroy: function() { 3754 this.element.removeClass( "ui-buttonset" ); 3755 this.buttons 3756 .map(function() { 3757 return $( this ).button( "widget" )[ 0 ]; 3758 }) 3759 .removeClass( "ui-corner-left ui-corner-right" ) 3760 .end() 3761 .button( "destroy" ); 3762 } 3763 }); 3764 3765 var button = $.ui.button; 3766 3767 3768 /*! 3769 * jQuery UI Datepicker 1.11.4 3770 * http://jqueryui.com 3771 * 3772 * Copyright jQuery Foundation and other contributors 3773 * Released under the MIT license. 3774 * http://jquery.org/license 3775 * 3776 * http://api.jqueryui.com/datepicker/ 3777 */ 3778 3779 3780 $.extend($.ui, { datepicker: { version: "1.11.4" } }); 3781 3782 var datepicker_instActive; 3783 3784 function datepicker_getZindex( elem ) { 3785 var position, value; 3786 while ( elem.length && elem[ 0 ] !== document ) { 3787 // Ignore z-index if position is set to a value where z-index is ignored by the browser 3788 // This makes behavior of this function consistent across browsers 3789 // WebKit always returns auto if the element is positioned 3790 position = elem.css( "position" ); 3791 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 3792 // IE returns 0 when zIndex is not specified 3793 // other browsers return a string 3794 // we ignore the case of nested elements with an explicit value of 0 3795 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 3796 value = parseInt( elem.css( "zIndex" ), 10 ); 3797 if ( !isNaN( value ) && value !== 0 ) { 3798 return value; 3799 } 3800 } 3801 elem = elem.parent(); 3802 } 3803 3804 return 0; 3805 } 3806 /* Date picker manager. 3807 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 3808 Settings for (groups of) date pickers are maintained in an instance object, 3809 allowing multiple different settings on the same page. */ 3810 3811 function Datepicker() { 3812 this._curInst = null; // The current instance in use 3813 this._keyEvent = false; // If the last event was a key event 3814 this._disabledInputs = []; // List of date picker inputs that have been disabled 3815 this._datepickerShowing = false; // True if the popup picker is showing , false if not 3816 this._inDialog = false; // True if showing within a "dialog", false if not 3817 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 3818 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 3819 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 3820 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 3821 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 3822 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 3823 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 3824 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 3825 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 3826 this.regional = []; // Available regional settings, indexed by language code 3827 this.regional[""] = { // Default regional settings 3828 closeText: "Done", // Display text for close link 3829 prevText: "Prev", // Display text for previous month link 3830 nextText: "Next", // Display text for next month link 3831 currentText: "Today", // Display text for current month link 3832 monthNames: ["January","February","March","April","May","June", 3833 "July","August","September","October","November","December"], // Names of months for drop-down and formatting 3834 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting 3835 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting 3836 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting 3837 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday 3838 weekHeader: "Wk", // Column header for week of the year 3839 dateFormat: "mm/dd/yy", // See format options on parseDate 3840 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 3841 isRTL: false, // True if right-to-left language, false if left-to-right 3842 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 3843 yearSuffix: "" // Additional text to append to the year in the month headers 3844 }; 3845 this._defaults = { // Global defaults for all the date picker instances 3846 showOn: "focus", // "focus" for popup on focus, 3847 // "button" for trigger button, or "both" for either 3848 showAnim: "fadeIn", // Name of jQuery animation for popup 3849 showOptions: {}, // Options for enhanced animations 3850 defaultDate: null, // Used when field is blank: actual date, 3851 // +/-number for offset from today, null for today 3852 appendText: "", // Display text following the input box, e.g. showing the format 3853 buttonText: "...", // Text for trigger button 3854 buttonImage: "", // URL for trigger button image 3855 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 3856 hideIfNoPrevNext: false, // True to hide next/previous month links 3857 // if not applicable, false to just disable them 3858 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 3859 gotoCurrent: false, // True if today link goes back to current selection instead 3860 changeMonth: false, // True if month can be selected directly, false if only prev/next 3861 changeYear: false, // True if year can be selected directly, false if only prev/next 3862 yearRange: "c-10:c+10", // Range of years to display in drop-down, 3863 // either relative to today's year (-nn:+nn), relative to currently displayed year 3864 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 3865 showOtherMonths: false, // True to show dates in other months, false to leave blank 3866 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 3867 showWeek: false, // True to show week of the year, false to not show it 3868 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 3869 // takes a Date and returns the number of the week for it 3870 shortYearCutoff: "+10", // Short year values < this are in the current century, 3871 // > this are in the previous century, 3872 // string value starting with "+" for current year + value 3873 minDate: null, // The earliest selectable date, or null for no limit 3874 maxDate: null, // The latest selectable date, or null for no limit 3875 duration: "fast", // Duration of display/closure 3876 beforeShowDay: null, // Function that takes a date and returns an array with 3877 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 3878 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 3879 beforeShow: null, // Function that takes an input field and 3880 // returns a set of custom settings for the date picker 3881 onSelect: null, // Define a callback function when a date is selected 3882 onChangeMonthYear: null, // Define a callback function when the month or year is changed 3883 onClose: null, // Define a callback function when the datepicker is closed 3884 numberOfMonths: 1, // Number of months to show at a time 3885 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 3886 stepMonths: 1, // Number of months to step back/forward 3887 stepBigMonths: 12, // Number of months to step back/forward for the big links 3888 altField: "", // Selector for an alternate field to store selected dates into 3889 altFormat: "", // The date format to use for the alternate field 3890 constrainInput: true, // The input is constrained by the current date format 3891 showButtonPanel: false, // True to show button panel, false to not show it 3892 autoSize: false, // True to size the input for the date format, false to leave as is 3893 disabled: false // The initial disabled state 3894 }; 3895 $.extend(this._defaults, this.regional[""]); 3896 this.regional.en = $.extend( true, {}, this.regional[ "" ]); 3897 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 3898 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")); 3899 } 3900 3901 $.extend(Datepicker.prototype, { 3902 /* Class name added to elements to indicate already configured with a date picker. */ 3903 markerClassName: "hasDatepicker", 3904 3905 //Keep track of the maximum number of rows displayed (see #7043) 3906 maxRows: 4, 3907 3908 // TODO rename to "widget" when switching to widget factory 3909 _widgetDatepicker: function() { 3910 return this.dpDiv; 3911 }, 3912 3913 /* Override the default settings for all instances of the date picker. 3914 * @param settings object - the new settings to use as defaults (anonymous object) 3915 * @return the manager object 3916 */ 3917 setDefaults: function(settings) { 3918 datepicker_extendRemove(this._defaults, settings || {}); 3919 return this; 3920 }, 3921 3922 /* Attach the date picker to a jQuery selection. 3923 * @param target element - the target input field or division or span 3924 * @param settings object - the new settings to use for this date picker instance (anonymous) 3925 */ 3926 _attachDatepicker: function(target, settings) { 3927 var nodeName, inline, inst; 3928 nodeName = target.nodeName.toLowerCase(); 3929 inline = (nodeName === "div" || nodeName === "span"); 3930 if (!target.id) { 3931 this.uuid += 1; 3932 target.id = "dp" + this.uuid; 3933 } 3934 inst = this._newInst($(target), inline); 3935 inst.settings = $.extend({}, settings || {}); 3936 if (nodeName === "input") { 3937 this._connectDatepicker(target, inst); 3938 } else if (inline) { 3939 this._inlineDatepicker(target, inst); 3940 } 3941 }, 3942 3943 /* Create a new instance object. */ 3944 _newInst: function(target, inline) { 3945 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars 3946 return {id: id, input: target, // associated target 3947 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 3948 drawMonth: 0, drawYear: 0, // month being drawn 3949 inline: inline, // is datepicker inline or not 3950 dpDiv: (!inline ? this.dpDiv : // presentation div 3951 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))}; 3952 }, 3953 3954 /* Attach the date picker to an input field. */ 3955 _connectDatepicker: function(target, inst) { 3956 var input = $(target); 3957 inst.append = $([]); 3958 inst.trigger = $([]); 3959 if (input.hasClass(this.markerClassName)) { 3960 return; 3961 } 3962 this._attachments(input, inst); 3963 input.addClass(this.markerClassName).keydown(this._doKeyDown). 3964 keypress(this._doKeyPress).keyup(this._doKeyUp); 3965 this._autoSize(inst); 3966 $.data(target, "datepicker", inst); 3967 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 3968 if( inst.settings.disabled ) { 3969 this._disableDatepicker( target ); 3970 } 3971 }, 3972 3973 /* Make attachments based on settings. */ 3974 _attachments: function(input, inst) { 3975 var showOn, buttonText, buttonImage, 3976 appendText = this._get(inst, "appendText"), 3977 isRTL = this._get(inst, "isRTL"); 3978 3979 if (inst.append) { 3980 inst.append.remove(); 3981 } 3982 if (appendText) { 3983 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); 3984 input[isRTL ? "before" : "after"](inst.append); 3985 } 3986 3987 input.unbind("focus", this._showDatepicker); 3988 3989 if (inst.trigger) { 3990 inst.trigger.remove(); 3991 } 3992 3993 showOn = this._get(inst, "showOn"); 3994 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field 3995 input.focus(this._showDatepicker); 3996 } 3997 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked 3998 buttonText = this._get(inst, "buttonText"); 3999 buttonImage = this._get(inst, "buttonImage"); 4000 inst.trigger = $(this._get(inst, "buttonImageOnly") ? 4001 $("<img/>").addClass(this._triggerClass). 4002 attr({ src: buttonImage, alt: buttonText, title: buttonText }) : 4003 $("<button type='button'></button>").addClass(this._triggerClass). 4004 html(!buttonImage ? buttonText : $("<img/>").attr( 4005 { src:buttonImage, alt:buttonText, title:buttonText }))); 4006 input[isRTL ? "before" : "after"](inst.trigger); 4007 inst.trigger.click(function() { 4008 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { 4009 $.datepicker._hideDatepicker(); 4010 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { 4011 $.datepicker._hideDatepicker(); 4012 $.datepicker._showDatepicker(input[0]); 4013 } else { 4014 $.datepicker._showDatepicker(input[0]); 4015 } 4016 return false; 4017 }); 4018 } 4019 }, 4020 4021 /* Apply the maximum length for the date format. */ 4022 _autoSize: function(inst) { 4023 if (this._get(inst, "autoSize") && !inst.inline) { 4024 var findMax, max, maxI, i, 4025 date = new Date(2009, 12 - 1, 20), // Ensure double digits 4026 dateFormat = this._get(inst, "dateFormat"); 4027 4028 if (dateFormat.match(/[DM]/)) { 4029 findMax = function(names) { 4030 max = 0; 4031 maxI = 0; 4032 for (i = 0; i < names.length; i++) { 4033 if (names[i].length > max) { 4034 max = names[i].length; 4035 maxI = i; 4036 } 4037 } 4038 return maxI; 4039 }; 4040 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? 4041 "monthNames" : "monthNamesShort")))); 4042 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? 4043 "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); 4044 } 4045 inst.input.attr("size", this._formatDate(inst, date).length); 4046 } 4047 }, 4048 4049 /* Attach an inline date picker to a div. */ 4050 _inlineDatepicker: function(target, inst) { 4051 var divSpan = $(target); 4052 if (divSpan.hasClass(this.markerClassName)) { 4053 return; 4054 } 4055 divSpan.addClass(this.markerClassName).append(inst.dpDiv); 4056 $.data(target, "datepicker", inst); 4057 this._setDate(inst, this._getDefaultDate(inst), true); 4058 this._updateDatepicker(inst); 4059 this._updateAlternate(inst); 4060 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 4061 if( inst.settings.disabled ) { 4062 this._disableDatepicker( target ); 4063 } 4064 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 4065 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 4066 inst.dpDiv.css( "display", "block" ); 4067 }, 4068 4069 /* Pop-up the date picker in a "dialog" box. 4070 * @param input element - ignored 4071 * @param date string or Date - the initial date to display 4072 * @param onSelect function - the function to call when a date is selected 4073 * @param settings object - update the dialog date picker instance's settings (anonymous object) 4074 * @param pos int[2] - coordinates for the dialog's position within the screen or 4075 * event - with x/y coordinates or 4076 * leave empty for default (screen centre) 4077 * @return the manager object 4078 */ 4079 _dialogDatepicker: function(input, date, onSelect, settings, pos) { 4080 var id, browserWidth, browserHeight, scrollX, scrollY, 4081 inst = this._dialogInst; // internal instance 4082 4083 if (!inst) { 4084 this.uuid += 1; 4085 id = "dp" + this.uuid; 4086 this._dialogInput = $("<input type='text' id='" + id + 4087 "' style='position: absolute; top: -100px; width: 0px;'/>"); 4088 this._dialogInput.keydown(this._doKeyDown); 4089 $("body").append(this._dialogInput); 4090 inst = this._dialogInst = this._newInst(this._dialogInput, false); 4091 inst.settings = {}; 4092 $.data(this._dialogInput[0], "datepicker", inst); 4093 } 4094 datepicker_extendRemove(inst.settings, settings || {}); 4095 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); 4096 this._dialogInput.val(date); 4097 4098 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); 4099 if (!this._pos) { 4100 browserWidth = document.documentElement.clientWidth; 4101 browserHeight = document.documentElement.clientHeight; 4102 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 4103 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 4104 this._pos = // should use actual width/height below 4105 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; 4106 } 4107 4108 // move input on screen for focus, but hidden behind dialog 4109 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); 4110 inst.settings.onSelect = onSelect; 4111 this._inDialog = true; 4112 this.dpDiv.addClass(this._dialogClass); 4113 this._showDatepicker(this._dialogInput[0]); 4114 if ($.blockUI) { 4115 $.blockUI(this.dpDiv); 4116 } 4117 $.data(this._dialogInput[0], "datepicker", inst); 4118 return this; 4119 }, 4120 4121 /* Detach a datepicker from its control. 4122 * @param target element - the target input field or division or span 4123 */ 4124 _destroyDatepicker: function(target) { 4125 var nodeName, 4126 $target = $(target), 4127 inst = $.data(target, "datepicker"); 4128 4129 if (!$target.hasClass(this.markerClassName)) { 4130 return; 4131 } 4132 4133 nodeName = target.nodeName.toLowerCase(); 4134 $.removeData(target, "datepicker"); 4135 if (nodeName === "input") { 4136 inst.append.remove(); 4137 inst.trigger.remove(); 4138 $target.removeClass(this.markerClassName). 4139 unbind("focus", this._showDatepicker). 4140 unbind("keydown", this._doKeyDown). 4141 unbind("keypress", this._doKeyPress). 4142 unbind("keyup", this._doKeyUp); 4143 } else if (nodeName === "div" || nodeName === "span") { 4144 $target.removeClass(this.markerClassName).empty(); 4145 } 4146 4147 if ( datepicker_instActive === inst ) { 4148 datepicker_instActive = null; 4149 } 4150 }, 4151 4152 /* Enable the date picker to a jQuery selection. 4153 * @param target element - the target input field or division or span 4154 */ 4155 _enableDatepicker: function(target) { 4156 var nodeName, inline, 4157 $target = $(target), 4158 inst = $.data(target, "datepicker"); 4159 4160 if (!$target.hasClass(this.markerClassName)) { 4161 return; 4162 } 4163 4164 nodeName = target.nodeName.toLowerCase(); 4165 if (nodeName === "input") { 4166 target.disabled = false; 4167 inst.trigger.filter("button"). 4168 each(function() { this.disabled = false; }).end(). 4169 filter("img").css({opacity: "1.0", cursor: ""}); 4170 } else if (nodeName === "div" || nodeName === "span") { 4171 inline = $target.children("." + this._inlineClass); 4172 inline.children().removeClass("ui-state-disabled"); 4173 inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). 4174 prop("disabled", false); 4175 } 4176 this._disabledInputs = $.map(this._disabledInputs, 4177 function(value) { return (value === target ? null : value); }); // delete entry 4178 }, 4179 4180 /* Disable the date picker to a jQuery selection. 4181 * @param target element - the target input field or division or span 4182 */ 4183 _disableDatepicker: function(target) { 4184 var nodeName, inline, 4185 $target = $(target), 4186 inst = $.data(target, "datepicker"); 4187 4188 if (!$target.hasClass(this.markerClassName)) { 4189 return; 4190 } 4191 4192 nodeName = target.nodeName.toLowerCase(); 4193 if (nodeName === "input") { 4194 target.disabled = true; 4195 inst.trigger.filter("button"). 4196 each(function() { this.disabled = true; }).end(). 4197 filter("img").css({opacity: "0.5", cursor: "default"}); 4198 } else if (nodeName === "div" || nodeName === "span") { 4199 inline = $target.children("." + this._inlineClass); 4200 inline.children().addClass("ui-state-disabled"); 4201 inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). 4202 prop("disabled", true); 4203 } 4204 this._disabledInputs = $.map(this._disabledInputs, 4205 function(value) { return (value === target ? null : value); }); // delete entry 4206 this._disabledInputs[this._disabledInputs.length] = target; 4207 }, 4208 4209 /* Is the first field in a jQuery collection disabled as a datepicker? 4210 * @param target element - the target input field or division or span 4211 * @return boolean - true if disabled, false if enabled 4212 */ 4213 _isDisabledDatepicker: function(target) { 4214 if (!target) { 4215 return false; 4216 } 4217 for (var i = 0; i < this._disabledInputs.length; i++) { 4218 if (this._disabledInputs[i] === target) { 4219 return true; 4220 } 4221 } 4222 return false; 4223 }, 4224 4225 /* Retrieve the instance data for the target control. 4226 * @param target element - the target input field or division or span 4227 * @return object - the associated instance data 4228 * @throws error if a jQuery problem getting data 4229 */ 4230 _getInst: function(target) { 4231 try { 4232 return $.data(target, "datepicker"); 4233 } 4234 catch (err) { 4235 throw "Missing instance data for this datepicker"; 4236 } 4237 }, 4238 4239 /* Update or retrieve the settings for a date picker attached to an input field or division. 4240 * @param target element - the target input field or division or span 4241 * @param name object - the new settings to update or 4242 * string - the name of the setting to change or retrieve, 4243 * when retrieving also "all" for all instance settings or 4244 * "defaults" for all global defaults 4245 * @param value any - the new value for the setting 4246 * (omit if above is an object or to retrieve a value) 4247 */ 4248 _optionDatepicker: function(target, name, value) { 4249 var settings, date, minDate, maxDate, 4250 inst = this._getInst(target); 4251 4252 if (arguments.length === 2 && typeof name === "string") { 4253 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : 4254 (inst ? (name === "all" ? $.extend({}, inst.settings) : 4255 this._get(inst, name)) : null)); 4256 } 4257 4258 settings = name || {}; 4259 if (typeof name === "string") { 4260 settings = {}; 4261 settings[name] = value; 4262 } 4263 4264 if (inst) { 4265 if (this._curInst === inst) { 4266 this._hideDatepicker(); 4267 } 4268 4269 date = this._getDateDatepicker(target, true); 4270 minDate = this._getMinMaxDate(inst, "min"); 4271 maxDate = this._getMinMaxDate(inst, "max"); 4272 datepicker_extendRemove(inst.settings, settings); 4273 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 4274 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { 4275 inst.settings.minDate = this._formatDate(inst, minDate); 4276 } 4277 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { 4278 inst.settings.maxDate = this._formatDate(inst, maxDate); 4279 } 4280 if ( "disabled" in settings ) { 4281 if ( settings.disabled ) { 4282 this._disableDatepicker(target); 4283 } else { 4284 this._enableDatepicker(target); 4285 } 4286 } 4287 this._attachments($(target), inst); 4288 this._autoSize(inst); 4289 this._setDate(inst, date); 4290 this._updateAlternate(inst); 4291 this._updateDatepicker(inst); 4292 } 4293 }, 4294 4295 // change method deprecated 4296 _changeDatepicker: function(target, name, value) { 4297 this._optionDatepicker(target, name, value); 4298 }, 4299 4300 /* Redraw the date picker attached to an input field or division. 4301 * @param target element - the target input field or division or span 4302 */ 4303 _refreshDatepicker: function(target) { 4304 var inst = this._getInst(target); 4305 if (inst) { 4306 this._updateDatepicker(inst); 4307 } 4308 }, 4309 4310 /* Set the dates for a jQuery selection. 4311 * @param target element - the target input field or division or span 4312 * @param date Date - the new date 4313 */ 4314 _setDateDatepicker: function(target, date) { 4315 var inst = this._getInst(target); 4316 if (inst) { 4317 this._setDate(inst, date); 4318 this._updateDatepicker(inst); 4319 this._updateAlternate(inst); 4320 } 4321 }, 4322 4323 /* Get the date(s) for the first entry in a jQuery selection. 4324 * @param target element - the target input field or division or span 4325 * @param noDefault boolean - true if no default date is to be used 4326 * @return Date - the current date 4327 */ 4328 _getDateDatepicker: function(target, noDefault) { 4329 var inst = this._getInst(target); 4330 if (inst && !inst.inline) { 4331 this._setDateFromField(inst, noDefault); 4332 } 4333 return (inst ? this._getDate(inst) : null); 4334 }, 4335 4336 /* Handle keystrokes. */ 4337 _doKeyDown: function(event) { 4338 var onSelect, dateStr, sel, 4339 inst = $.datepicker._getInst(event.target), 4340 handled = true, 4341 isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); 4342 4343 inst._keyEvent = true; 4344 if ($.datepicker._datepickerShowing) { 4345 switch (event.keyCode) { 4346 case 9: $.datepicker._hideDatepicker(); 4347 handled = false; 4348 break; // hide on tab out 4349 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + 4350 $.datepicker._currentClass + ")", inst.dpDiv); 4351 if (sel[0]) { 4352 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); 4353 } 4354 4355 onSelect = $.datepicker._get(inst, "onSelect"); 4356 if (onSelect) { 4357 dateStr = $.datepicker._formatDate(inst); 4358 4359 // trigger custom callback 4360 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); 4361 } else { 4362 $.datepicker._hideDatepicker(); 4363 } 4364 4365 return false; // don't submit the form 4366 case 27: $.datepicker._hideDatepicker(); 4367 break; // hide on escape 4368 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4369 -$.datepicker._get(inst, "stepBigMonths") : 4370 -$.datepicker._get(inst, "stepMonths")), "M"); 4371 break; // previous month/year on page up/+ ctrl 4372 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4373 +$.datepicker._get(inst, "stepBigMonths") : 4374 +$.datepicker._get(inst, "stepMonths")), "M"); 4375 break; // next month/year on page down/+ ctrl 4376 case 35: if (event.ctrlKey || event.metaKey) { 4377 $.datepicker._clearDate(event.target); 4378 } 4379 handled = event.ctrlKey || event.metaKey; 4380 break; // clear on ctrl or command +end 4381 case 36: if (event.ctrlKey || event.metaKey) { 4382 $.datepicker._gotoToday(event.target); 4383 } 4384 handled = event.ctrlKey || event.metaKey; 4385 break; // current on ctrl or command +home 4386 case 37: if (event.ctrlKey || event.metaKey) { 4387 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); 4388 } 4389 handled = event.ctrlKey || event.metaKey; 4390 // -1 day on ctrl or command +left 4391 if (event.originalEvent.altKey) { 4392 $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4393 -$.datepicker._get(inst, "stepBigMonths") : 4394 -$.datepicker._get(inst, "stepMonths")), "M"); 4395 } 4396 // next month/year on alt +left on Mac 4397 break; 4398 case 38: if (event.ctrlKey || event.metaKey) { 4399 $.datepicker._adjustDate(event.target, -7, "D"); 4400 } 4401 handled = event.ctrlKey || event.metaKey; 4402 break; // -1 week on ctrl or command +up 4403 case 39: if (event.ctrlKey || event.metaKey) { 4404 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); 4405 } 4406 handled = event.ctrlKey || event.metaKey; 4407 // +1 day on ctrl or command +right 4408 if (event.originalEvent.altKey) { 4409 $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4410 +$.datepicker._get(inst, "stepBigMonths") : 4411 +$.datepicker._get(inst, "stepMonths")), "M"); 4412 } 4413 // next month/year on alt +right 4414 break; 4415 case 40: if (event.ctrlKey || event.metaKey) { 4416 $.datepicker._adjustDate(event.target, +7, "D"); 4417 } 4418 handled = event.ctrlKey || event.metaKey; 4419 break; // +1 week on ctrl or command +down 4420 default: handled = false; 4421 } 4422 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home 4423 $.datepicker._showDatepicker(this); 4424 } else { 4425 handled = false; 4426 } 4427 4428 if (handled) { 4429 event.preventDefault(); 4430 event.stopPropagation(); 4431 } 4432 }, 4433 4434 /* Filter entered characters - based on date format. */ 4435 _doKeyPress: function(event) { 4436 var chars, chr, 4437 inst = $.datepicker._getInst(event.target); 4438 4439 if ($.datepicker._get(inst, "constrainInput")) { 4440 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); 4441 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); 4442 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); 4443 } 4444 }, 4445 4446 /* Synchronise manual entry and field/alternate field. */ 4447 _doKeyUp: function(event) { 4448 var date, 4449 inst = $.datepicker._getInst(event.target); 4450 4451 if (inst.input.val() !== inst.lastVal) { 4452 try { 4453 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), 4454 (inst.input ? inst.input.val() : null), 4455 $.datepicker._getFormatConfig(inst)); 4456 4457 if (date) { // only if valid 4458 $.datepicker._setDateFromField(inst); 4459 $.datepicker._updateAlternate(inst); 4460 $.datepicker._updateDatepicker(inst); 4461 } 4462 } 4463 catch (err) { 4464 } 4465 } 4466 return true; 4467 }, 4468 4469 /* Pop-up the date picker for a given input field. 4470 * If false returned from beforeShow event handler do not show. 4471 * @param input element - the input field attached to the date picker or 4472 * event - if triggered by focus 4473 */ 4474 _showDatepicker: function(input) { 4475 input = input.target || input; 4476 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger 4477 input = $("input", input.parentNode)[0]; 4478 } 4479 4480 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here 4481 return; 4482 } 4483 4484 var inst, beforeShow, beforeShowSettings, isFixed, 4485 offset, showAnim, duration; 4486 4487 inst = $.datepicker._getInst(input); 4488 if ($.datepicker._curInst && $.datepicker._curInst !== inst) { 4489 $.datepicker._curInst.dpDiv.stop(true, true); 4490 if ( inst && $.datepicker._datepickerShowing ) { 4491 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); 4492 } 4493 } 4494 4495 beforeShow = $.datepicker._get(inst, "beforeShow"); 4496 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; 4497 if(beforeShowSettings === false){ 4498 return; 4499 } 4500 datepicker_extendRemove(inst.settings, beforeShowSettings); 4501 4502 inst.lastVal = null; 4503 $.datepicker._lastInput = input; 4504 $.datepicker._setDateFromField(inst); 4505 4506 if ($.datepicker._inDialog) { // hide cursor 4507 input.value = ""; 4508 } 4509 if (!$.datepicker._pos) { // position below input 4510 $.datepicker._pos = $.datepicker._findPos(input); 4511 $.datepicker._pos[1] += input.offsetHeight; // add the height 4512 } 4513 4514 isFixed = false; 4515 $(input).parents().each(function() { 4516 isFixed |= $(this).css("position") === "fixed"; 4517 return !isFixed; 4518 }); 4519 4520 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; 4521 $.datepicker._pos = null; 4522 //to avoid flashes on Firefox 4523 inst.dpDiv.empty(); 4524 // determine sizing offscreen 4525 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); 4526 $.datepicker._updateDatepicker(inst); 4527 // fix width for dynamic number of date pickers 4528 // and adjust position before showing 4529 offset = $.datepicker._checkOffset(inst, offset, isFixed); 4530 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? 4531 "static" : (isFixed ? "fixed" : "absolute")), display: "none", 4532 left: offset.left + "px", top: offset.top + "px"}); 4533 4534 if (!inst.inline) { 4535 showAnim = $.datepicker._get(inst, "showAnim"); 4536 duration = $.datepicker._get(inst, "duration"); 4537 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 4538 $.datepicker._datepickerShowing = true; 4539 4540 if ( $.effects && $.effects.effect[ showAnim ] ) { 4541 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); 4542 } else { 4543 inst.dpDiv[showAnim || "show"](showAnim ? duration : null); 4544 } 4545 4546 if ( $.datepicker._shouldFocusInput( inst ) ) { 4547 inst.input.focus(); 4548 } 4549 4550 $.datepicker._curInst = inst; 4551 } 4552 }, 4553 4554 /* Generate the date picker content. */ 4555 _updateDatepicker: function(inst) { 4556 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 4557 datepicker_instActive = inst; // for delegate hover events 4558 inst.dpDiv.empty().append(this._generateHTML(inst)); 4559 this._attachHandlers(inst); 4560 4561 var origyearshtml, 4562 numMonths = this._getNumberOfMonths(inst), 4563 cols = numMonths[1], 4564 width = 17, 4565 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); 4566 4567 if ( activeCell.length > 0 ) { 4568 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 4569 } 4570 4571 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); 4572 if (cols > 1) { 4573 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); 4574 } 4575 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + 4576 "Class"]("ui-datepicker-multi"); 4577 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + 4578 "Class"]("ui-datepicker-rtl"); 4579 4580 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 4581 inst.input.focus(); 4582 } 4583 4584 // deffered render of the years select (to avoid flashes on Firefox) 4585 if( inst.yearshtml ){ 4586 origyearshtml = inst.yearshtml; 4587 setTimeout(function(){ 4588 //assure that inst.yearshtml didn't change. 4589 if( origyearshtml === inst.yearshtml && inst.yearshtml ){ 4590 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); 4591 } 4592 origyearshtml = inst.yearshtml = null; 4593 }, 0); 4594 } 4595 }, 4596 4597 // #6694 - don't focus the input if it's already focused 4598 // this breaks the change event in IE 4599 // Support: IE and jQuery <1.9 4600 _shouldFocusInput: function( inst ) { 4601 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); 4602 }, 4603 4604 /* Check positioning to remain on screen. */ 4605 _checkOffset: function(inst, offset, isFixed) { 4606 var dpWidth = inst.dpDiv.outerWidth(), 4607 dpHeight = inst.dpDiv.outerHeight(), 4608 inputWidth = inst.input ? inst.input.outerWidth() : 0, 4609 inputHeight = inst.input ? inst.input.outerHeight() : 0, 4610 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), 4611 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); 4612 4613 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); 4614 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; 4615 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; 4616 4617 // now check if datepicker is showing outside window viewport - move to a better place if so. 4618 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? 4619 Math.abs(offset.left + dpWidth - viewWidth) : 0); 4620 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? 4621 Math.abs(dpHeight + inputHeight) : 0); 4622 4623 return offset; 4624 }, 4625 4626 /* Find an object's position on the screen. */ 4627 _findPos: function(obj) { 4628 var position, 4629 inst = this._getInst(obj), 4630 isRTL = this._get(inst, "isRTL"); 4631 4632 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { 4633 obj = obj[isRTL ? "previousSibling" : "nextSibling"]; 4634 } 4635 4636 position = $(obj).offset(); 4637 return [position.left, position.top]; 4638 }, 4639 4640 /* Hide the date picker from view. 4641 * @param input element - the input field attached to the date picker 4642 */ 4643 _hideDatepicker: function(input) { 4644 var showAnim, duration, postProcess, onClose, 4645 inst = this._curInst; 4646 4647 if (!inst || (input && inst !== $.data(input, "datepicker"))) { 4648 return; 4649 } 4650 4651 if (this._datepickerShowing) { 4652 showAnim = this._get(inst, "showAnim"); 4653 duration = this._get(inst, "duration"); 4654 postProcess = function() { 4655 $.datepicker._tidyDialog(inst); 4656 }; 4657 4658 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 4659 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 4660 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); 4661 } else { 4662 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : 4663 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); 4664 } 4665 4666 if (!showAnim) { 4667 postProcess(); 4668 } 4669 this._datepickerShowing = false; 4670 4671 onClose = this._get(inst, "onClose"); 4672 if (onClose) { 4673 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); 4674 } 4675 4676 this._lastInput = null; 4677 if (this._inDialog) { 4678 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); 4679 if ($.blockUI) { 4680 $.unblockUI(); 4681 $("body").append(this.dpDiv); 4682 } 4683 } 4684 this._inDialog = false; 4685 } 4686 }, 4687 4688 /* Tidy up after a dialog display. */ 4689 _tidyDialog: function(inst) { 4690 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); 4691 }, 4692 4693 /* Close date picker if clicked elsewhere. */ 4694 _checkExternalClick: function(event) { 4695 if (!$.datepicker._curInst) { 4696 return; 4697 } 4698 4699 var $target = $(event.target), 4700 inst = $.datepicker._getInst($target[0]); 4701 4702 if ( ( ( $target[0].id !== $.datepicker._mainDivId && 4703 $target.parents("#" + $.datepicker._mainDivId).length === 0 && 4704 !$target.hasClass($.datepicker.markerClassName) && 4705 !$target.closest("." + $.datepicker._triggerClass).length && 4706 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || 4707 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { 4708 $.datepicker._hideDatepicker(); 4709 } 4710 }, 4711 4712 /* Adjust one of the date sub-fields. */ 4713 _adjustDate: function(id, offset, period) { 4714 var target = $(id), 4715 inst = this._getInst(target[0]); 4716 4717 if (this._isDisabledDatepicker(target[0])) { 4718 return; 4719 } 4720 this._adjustInstDate(inst, offset + 4721 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning 4722 period); 4723 this._updateDatepicker(inst); 4724 }, 4725 4726 /* Action for current link. */ 4727 _gotoToday: function(id) { 4728 var date, 4729 target = $(id), 4730 inst = this._getInst(target[0]); 4731 4732 if (this._get(inst, "gotoCurrent") && inst.currentDay) { 4733 inst.selectedDay = inst.currentDay; 4734 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 4735 inst.drawYear = inst.selectedYear = inst.currentYear; 4736 } else { 4737 date = new Date(); 4738 inst.selectedDay = date.getDate(); 4739 inst.drawMonth = inst.selectedMonth = date.getMonth(); 4740 inst.drawYear = inst.selectedYear = date.getFullYear(); 4741 } 4742 this._notifyChange(inst); 4743 this._adjustDate(target); 4744 }, 4745 4746 /* Action for selecting a new month/year. */ 4747 _selectMonthYear: function(id, select, period) { 4748 var target = $(id), 4749 inst = this._getInst(target[0]); 4750 4751 inst["selected" + (period === "M" ? "Month" : "Year")] = 4752 inst["draw" + (period === "M" ? "Month" : "Year")] = 4753 parseInt(select.options[select.selectedIndex].value,10); 4754 4755 this._notifyChange(inst); 4756 this._adjustDate(target); 4757 }, 4758 4759 /* Action for selecting a day. */ 4760 _selectDay: function(id, month, year, td) { 4761 var inst, 4762 target = $(id); 4763 4764 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { 4765 return; 4766 } 4767 4768 inst = this._getInst(target[0]); 4769 inst.selectedDay = inst.currentDay = $("a", td).html(); 4770 inst.selectedMonth = inst.currentMonth = month; 4771 inst.selectedYear = inst.currentYear = year; 4772 this._selectDate(id, this._formatDate(inst, 4773 inst.currentDay, inst.currentMonth, inst.currentYear)); 4774 }, 4775 4776 /* Erase the input field and hide the date picker. */ 4777 _clearDate: function(id) { 4778 var target = $(id); 4779 this._selectDate(target, ""); 4780 }, 4781 4782 /* Update the input field with the selected date. */ 4783 _selectDate: function(id, dateStr) { 4784 var onSelect, 4785 target = $(id), 4786 inst = this._getInst(target[0]); 4787 4788 dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); 4789 if (inst.input) { 4790 inst.input.val(dateStr); 4791 } 4792 this._updateAlternate(inst); 4793 4794 onSelect = this._get(inst, "onSelect"); 4795 if (onSelect) { 4796 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback 4797 } else if (inst.input) { 4798 inst.input.trigger("change"); // fire the change event 4799 } 4800 4801 if (inst.inline){ 4802 this._updateDatepicker(inst); 4803 } else { 4804 this._hideDatepicker(); 4805 this._lastInput = inst.input[0]; 4806 if (typeof(inst.input[0]) !== "object") { 4807 inst.input.focus(); // restore focus 4808 } 4809 this._lastInput = null; 4810 } 4811 }, 4812 4813 /* Update any alternate field to synchronise with the main field. */ 4814 _updateAlternate: function(inst) { 4815 var altFormat, date, dateStr, 4816 altField = this._get(inst, "altField"); 4817 4818 if (altField) { // update alternate field too 4819 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); 4820 date = this._getDate(inst); 4821 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); 4822 $(altField).each(function() { $(this).val(dateStr); }); 4823 } 4824 }, 4825 4826 /* Set as beforeShowDay function to prevent selection of weekends. 4827 * @param date Date - the date to customise 4828 * @return [boolean, string] - is this date selectable?, what is its CSS class? 4829 */ 4830 noWeekends: function(date) { 4831 var day = date.getDay(); 4832 return [(day > 0 && day < 6), ""]; 4833 }, 4834 4835 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 4836 * @param date Date - the date to get the week for 4837 * @return number - the number of the week within the year that contains this date 4838 */ 4839 iso8601Week: function(date) { 4840 var time, 4841 checkDate = new Date(date.getTime()); 4842 4843 // Find Thursday of this week starting on Monday 4844 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); 4845 4846 time = checkDate.getTime(); 4847 checkDate.setMonth(0); // Compare with Jan 1 4848 checkDate.setDate(1); 4849 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; 4850 }, 4851 4852 /* Parse a string value into a date object. 4853 * See formatDate below for the possible formats. 4854 * 4855 * @param format string - the expected format of the date 4856 * @param value string - the date in the above format 4857 * @param settings Object - attributes include: 4858 * shortYearCutoff number - the cutoff year for determining the century (optional) 4859 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 4860 * dayNames string[7] - names of the days from Sunday (optional) 4861 * monthNamesShort string[12] - abbreviated names of the months (optional) 4862 * monthNames string[12] - names of the months (optional) 4863 * @return Date - the extracted date value or null if value is blank 4864 */ 4865 parseDate: function (format, value, settings) { 4866 if (format == null || value == null) { 4867 throw "Invalid arguments"; 4868 } 4869 4870 value = (typeof value === "object" ? value.toString() : value + ""); 4871 if (value === "") { 4872 return null; 4873 } 4874 4875 var iFormat, dim, extra, 4876 iValue = 0, 4877 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, 4878 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 4879 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), 4880 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, 4881 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, 4882 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, 4883 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, 4884 year = -1, 4885 month = -1, 4886 day = -1, 4887 doy = -1, 4888 literal = false, 4889 date, 4890 // Check whether a format character is doubled 4891 lookAhead = function(match) { 4892 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); 4893 if (matches) { 4894 iFormat++; 4895 } 4896 return matches; 4897 }, 4898 // Extract a number from the string value 4899 getNumber = function(match) { 4900 var isDoubled = lookAhead(match), 4901 size = (match === "@" ? 14 : (match === "!" ? 20 : 4902 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), 4903 minSize = (match === "y" ? size : 1), 4904 digits = new RegExp("^\\d{" + minSize + "," + size + "}"), 4905 num = value.substring(iValue).match(digits); 4906 if (!num) { 4907 throw "Missing number at position " + iValue; 4908 } 4909 iValue += num[0].length; 4910 return parseInt(num[0], 10); 4911 }, 4912 // Extract a name from the string value and convert to an index 4913 getName = function(match, shortNames, longNames) { 4914 var index = -1, 4915 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { 4916 return [ [k, v] ]; 4917 }).sort(function (a, b) { 4918 return -(a[1].length - b[1].length); 4919 }); 4920 4921 $.each(names, function (i, pair) { 4922 var name = pair[1]; 4923 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { 4924 index = pair[0]; 4925 iValue += name.length; 4926 return false; 4927 } 4928 }); 4929 if (index !== -1) { 4930 return index + 1; 4931 } else { 4932 throw "Unknown name at position " + iValue; 4933 } 4934 }, 4935 // Confirm that a literal character matches the string value 4936 checkLiteral = function() { 4937 if (value.charAt(iValue) !== format.charAt(iFormat)) { 4938 throw "Unexpected literal at position " + iValue; 4939 } 4940 iValue++; 4941 }; 4942 4943 for (iFormat = 0; iFormat < format.length; iFormat++) { 4944 if (literal) { 4945 if (format.charAt(iFormat) === "'" && !lookAhead("'")) { 4946 literal = false; 4947 } else { 4948 checkLiteral(); 4949 } 4950 } else { 4951 switch (format.charAt(iFormat)) { 4952 case "d": 4953 day = getNumber("d"); 4954 break; 4955 case "D": 4956 getName("D", dayNamesShort, dayNames); 4957 break; 4958 case "o": 4959 doy = getNumber("o"); 4960 break; 4961 case "m": 4962 month = getNumber("m"); 4963 break; 4964 case "M": 4965 month = getName("M", monthNamesShort, monthNames); 4966 break; 4967 case "y": 4968 year = getNumber("y"); 4969 break; 4970 case "@": 4971 date = new Date(getNumber("@")); 4972 year = date.getFullYear(); 4973 month = date.getMonth() + 1; 4974 day = date.getDate(); 4975 break; 4976 case "!": 4977 date = new Date((getNumber("!") - this._ticksTo1970) / 10000); 4978 year = date.getFullYear(); 4979 month = date.getMonth() + 1; 4980 day = date.getDate(); 4981 break; 4982 case "'": 4983 if (lookAhead("'")){ 4984 checkLiteral(); 4985 } else { 4986 literal = true; 4987 } 4988 break; 4989 default: 4990 checkLiteral(); 4991 } 4992 } 4993 } 4994 4995 if (iValue < value.length){ 4996 extra = value.substr(iValue); 4997 if (!/^\s+/.test(extra)) { 4998 throw "Extra/unparsed characters found in date: " + extra; 4999 } 5000 } 5001 5002 if (year === -1) { 5003 year = new Date().getFullYear(); 5004 } else if (year < 100) { 5005 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 5006 (year <= shortYearCutoff ? 0 : -100); 5007 } 5008 5009 if (doy > -1) { 5010 month = 1; 5011 day = doy; 5012 do { 5013 dim = this._getDaysInMonth(year, month - 1); 5014 if (day <= dim) { 5015 break; 5016 } 5017 month++; 5018 day -= dim; 5019 } while (true); 5020 } 5021 5022 date = this._daylightSavingAdjust(new Date(year, month - 1, day)); 5023 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { 5024 throw "Invalid date"; // E.g. 31/02/00 5025 } 5026 return date; 5027 }, 5028 5029 /* Standard date formats. */ 5030 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 5031 COOKIE: "D, dd M yy", 5032 ISO_8601: "yy-mm-dd", 5033 RFC_822: "D, d M y", 5034 RFC_850: "DD, dd-M-y", 5035 RFC_1036: "D, d M y", 5036 RFC_1123: "D, d M yy", 5037 RFC_2822: "D, d M yy", 5038 RSS: "D, d M y", // RFC 822 5039 TICKS: "!", 5040 TIMESTAMP: "@", 5041 W3C: "yy-mm-dd", // ISO 8601 5042 5043 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + 5044 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), 5045 5046 /* Format a date object into a string value. 5047 * The format can be combinations of the following: 5048 * d - day of month (no leading zero) 5049 * dd - day of month (two digit) 5050 * o - day of year (no leading zeros) 5051 * oo - day of year (three digit) 5052 * D - day name short 5053 * DD - day name long 5054 * m - month of year (no leading zero) 5055 * mm - month of year (two digit) 5056 * M - month name short 5057 * MM - month name long 5058 * y - year (two digit) 5059 * yy - year (four digit) 5060 * @ - Unix timestamp (ms since 01/01/1970) 5061 * ! - Windows ticks (100ns since 01/01/0001) 5062 * "..." - literal text 5063 * '' - single quote 5064 * 5065 * @param format string - the desired format of the date 5066 * @param date Date - the date value to format 5067 * @param settings Object - attributes include: 5068 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 5069 * dayNames string[7] - names of the days from Sunday (optional) 5070 * monthNamesShort string[12] - abbreviated names of the months (optional) 5071 * monthNames string[12] - names of the months (optional) 5072 * @return string - the date in the above format 5073 */ 5074 formatDate: function (format, date, settings) { 5075 if (!date) { 5076 return ""; 5077 } 5078 5079 var iFormat, 5080 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, 5081 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, 5082 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, 5083 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, 5084 // Check whether a format character is doubled 5085 lookAhead = function(match) { 5086 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); 5087 if (matches) { 5088 iFormat++; 5089 } 5090 return matches; 5091 }, 5092 // Format a number, with leading zero if necessary 5093 formatNumber = function(match, value, len) { 5094 var num = "" + value; 5095 if (lookAhead(match)) { 5096 while (num.length < len) { 5097 num = "0" + num; 5098 } 5099 } 5100 return num; 5101 }, 5102 // Format a name, short or long as requested 5103 formatName = function(match, value, shortNames, longNames) { 5104 return (lookAhead(match) ? longNames[value] : shortNames[value]); 5105 }, 5106 output = "", 5107 literal = false; 5108 5109 if (date) { 5110 for (iFormat = 0; iFormat < format.length; iFormat++) { 5111 if (literal) { 5112 if (format.charAt(iFormat) === "'" && !lookAhead("'")) { 5113 literal = false; 5114 } else { 5115 output += format.charAt(iFormat); 5116 } 5117 } else { 5118 switch (format.charAt(iFormat)) { 5119 case "d": 5120 output += formatNumber("d", date.getDate(), 2); 5121 break; 5122 case "D": 5123 output += formatName("D", date.getDay(), dayNamesShort, dayNames); 5124 break; 5125 case "o": 5126 output += formatNumber("o", 5127 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); 5128 break; 5129 case "m": 5130 output += formatNumber("m", date.getMonth() + 1, 2); 5131 break; 5132 case "M": 5133 output += formatName("M", date.getMonth(), monthNamesShort, monthNames); 5134 break; 5135 case "y": 5136 output += (lookAhead("y") ? date.getFullYear() : 5137 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); 5138 break; 5139 case "@": 5140 output += date.getTime(); 5141 break; 5142 case "!": 5143 output += date.getTime() * 10000 + this._ticksTo1970; 5144 break; 5145 case "'": 5146 if (lookAhead("'")) { 5147 output += "'"; 5148 } else { 5149 literal = true; 5150 } 5151 break; 5152 default: 5153 output += format.charAt(iFormat); 5154 } 5155 } 5156 } 5157 } 5158 return output; 5159 }, 5160 5161 /* Extract all possible characters from the date format. */ 5162 _possibleChars: function (format) { 5163 var iFormat, 5164 chars = "", 5165 literal = false, 5166 // Check whether a format character is doubled 5167 lookAhead = function(match) { 5168 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); 5169 if (matches) { 5170 iFormat++; 5171 } 5172 return matches; 5173 }; 5174 5175 for (iFormat = 0; iFormat < format.length; iFormat++) { 5176 if (literal) { 5177 if (format.charAt(iFormat) === "'" && !lookAhead("'")) { 5178 literal = false; 5179 } else { 5180 chars += format.charAt(iFormat); 5181 } 5182 } else { 5183 switch (format.charAt(iFormat)) { 5184 case "d": case "m": case "y": case "@": 5185 chars += "0123456789"; 5186 break; 5187 case "D": case "M": 5188 return null; // Accept anything 5189 case "'": 5190 if (lookAhead("'")) { 5191 chars += "'"; 5192 } else { 5193 literal = true; 5194 } 5195 break; 5196 default: 5197 chars += format.charAt(iFormat); 5198 } 5199 } 5200 } 5201 return chars; 5202 }, 5203 5204 /* Get a setting value, defaulting if necessary. */ 5205 _get: function(inst, name) { 5206 return inst.settings[name] !== undefined ? 5207 inst.settings[name] : this._defaults[name]; 5208 }, 5209 5210 /* Parse existing date and initialise date picker. */ 5211 _setDateFromField: function(inst, noDefault) { 5212 if (inst.input.val() === inst.lastVal) { 5213 return; 5214 } 5215 5216 var dateFormat = this._get(inst, "dateFormat"), 5217 dates = inst.lastVal = inst.input ? inst.input.val() : null, 5218 defaultDate = this._getDefaultDate(inst), 5219 date = defaultDate, 5220 settings = this._getFormatConfig(inst); 5221 5222 try { 5223 date = this.parseDate(dateFormat, dates, settings) || defaultDate; 5224 } catch (event) { 5225 dates = (noDefault ? "" : dates); 5226 } 5227 inst.selectedDay = date.getDate(); 5228 inst.drawMonth = inst.selectedMonth = date.getMonth(); 5229 inst.drawYear = inst.selectedYear = date.getFullYear(); 5230 inst.currentDay = (dates ? date.getDate() : 0); 5231 inst.currentMonth = (dates ? date.getMonth() : 0); 5232 inst.currentYear = (dates ? date.getFullYear() : 0); 5233 this._adjustInstDate(inst); 5234 }, 5235 5236 /* Retrieve the default date shown on opening. */ 5237 _getDefaultDate: function(inst) { 5238 return this._restrictMinMax(inst, 5239 this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); 5240 }, 5241 5242 /* A date may be specified as an exact value or a relative one. */ 5243 _determineDate: function(inst, date, defaultDate) { 5244 var offsetNumeric = function(offset) { 5245 var date = new Date(); 5246 date.setDate(date.getDate() + offset); 5247 return date; 5248 }, 5249 offsetString = function(offset) { 5250 try { 5251 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), 5252 offset, $.datepicker._getFormatConfig(inst)); 5253 } 5254 catch (e) { 5255 // Ignore 5256 } 5257 5258 var date = (offset.toLowerCase().match(/^c/) ? 5259 $.datepicker._getDate(inst) : null) || new Date(), 5260 year = date.getFullYear(), 5261 month = date.getMonth(), 5262 day = date.getDate(), 5263 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 5264 matches = pattern.exec(offset); 5265 5266 while (matches) { 5267 switch (matches[2] || "d") { 5268 case "d" : case "D" : 5269 day += parseInt(matches[1],10); break; 5270 case "w" : case "W" : 5271 day += parseInt(matches[1],10) * 7; break; 5272 case "m" : case "M" : 5273 month += parseInt(matches[1],10); 5274 day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); 5275 break; 5276 case "y": case "Y" : 5277 year += parseInt(matches[1],10); 5278 day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); 5279 break; 5280 } 5281 matches = pattern.exec(offset); 5282 } 5283 return new Date(year, month, day); 5284 }, 5285 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : 5286 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); 5287 5288 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); 5289 if (newDate) { 5290 newDate.setHours(0); 5291 newDate.setMinutes(0); 5292 newDate.setSeconds(0); 5293 newDate.setMilliseconds(0); 5294 } 5295 return this._daylightSavingAdjust(newDate); 5296 }, 5297 5298 /* Handle switch to/from daylight saving. 5299 * Hours may be non-zero on daylight saving cut-over: 5300 * > 12 when midnight changeover, but then cannot generate 5301 * midnight datetime, so jump to 1AM, otherwise reset. 5302 * @param date (Date) the date to check 5303 * @return (Date) the corrected date 5304 */ 5305 _daylightSavingAdjust: function(date) { 5306 if (!date) { 5307 return null; 5308 } 5309 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); 5310 return date; 5311 }, 5312 5313 /* Set the date(s) directly. */ 5314 _setDate: function(inst, date, noChange) { 5315 var clear = !date, 5316 origMonth = inst.selectedMonth, 5317 origYear = inst.selectedYear, 5318 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); 5319 5320 inst.selectedDay = inst.currentDay = newDate.getDate(); 5321 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 5322 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 5323 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { 5324 this._notifyChange(inst); 5325 } 5326 this._adjustInstDate(inst); 5327 if (inst.input) { 5328 inst.input.val(clear ? "" : this._formatDate(inst)); 5329 } 5330 }, 5331 5332 /* Retrieve the date(s) directly. */ 5333 _getDate: function(inst) { 5334 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : 5335 this._daylightSavingAdjust(new Date( 5336 inst.currentYear, inst.currentMonth, inst.currentDay))); 5337 return startDate; 5338 }, 5339 5340 /* Attach the onxxx handlers. These are declared statically so 5341 * they work with static code transformers like Caja. 5342 */ 5343 _attachHandlers: function(inst) { 5344 var stepMonths = this._get(inst, "stepMonths"), 5345 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 5346 inst.dpDiv.find("[data-handler]").map(function () { 5347 var handler = { 5348 prev: function () { 5349 $.datepicker._adjustDate(id, -stepMonths, "M"); 5350 }, 5351 next: function () { 5352 $.datepicker._adjustDate(id, +stepMonths, "M"); 5353 }, 5354 hide: function () { 5355 $.datepicker._hideDatepicker(); 5356 }, 5357 today: function () { 5358 $.datepicker._gotoToday(id); 5359 }, 5360 selectDay: function () { 5361 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); 5362 return false; 5363 }, 5364 selectMonth: function () { 5365 $.datepicker._selectMonthYear(id, this, "M"); 5366 return false; 5367 }, 5368 selectYear: function () { 5369 $.datepicker._selectMonthYear(id, this, "Y"); 5370 return false; 5371 } 5372 }; 5373 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); 5374 }); 5375 }, 5376 5377 /* Generate the HTML for the current state of the date picker. */ 5378 _generateHTML: function(inst) { 5379 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 5380 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 5381 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 5382 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 5383 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 5384 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 5385 tempDate = new Date(), 5386 today = this._daylightSavingAdjust( 5387 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time 5388 isRTL = this._get(inst, "isRTL"), 5389 showButtonPanel = this._get(inst, "showButtonPanel"), 5390 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), 5391 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), 5392 numMonths = this._getNumberOfMonths(inst), 5393 showCurrentAtPos = this._get(inst, "showCurrentAtPos"), 5394 stepMonths = this._get(inst, "stepMonths"), 5395 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), 5396 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : 5397 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), 5398 minDate = this._getMinMaxDate(inst, "min"), 5399 maxDate = this._getMinMaxDate(inst, "max"), 5400 drawMonth = inst.drawMonth - showCurrentAtPos, 5401 drawYear = inst.drawYear; 5402 5403 if (drawMonth < 0) { 5404 drawMonth += 12; 5405 drawYear--; 5406 } 5407 if (maxDate) { 5408 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), 5409 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); 5410 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); 5411 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { 5412 drawMonth--; 5413 if (drawMonth < 0) { 5414 drawMonth = 11; 5415 drawYear--; 5416 } 5417 } 5418 } 5419 inst.drawMonth = drawMonth; 5420 inst.drawYear = drawYear; 5421 5422 prevText = this._get(inst, "prevText"); 5423 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, 5424 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), 5425 this._getFormatConfig(inst))); 5426 5427 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? 5428 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + 5429 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" : 5430 (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>")); 5431 5432 nextText = this._get(inst, "nextText"); 5433 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, 5434 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), 5435 this._getFormatConfig(inst))); 5436 5437 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? 5438 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + 5439 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" : 5440 (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>")); 5441 5442 currentText = this._get(inst, "currentText"); 5443 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); 5444 currentText = (!navigationAsDateFormat ? currentText : 5445 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); 5446 5447 controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" + 5448 this._get(inst, "closeText") + "</button>" : ""); 5449 5450 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") + 5451 (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" + 5452 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : ""; 5453 5454 firstDay = parseInt(this._get(inst, "firstDay"),10); 5455 firstDay = (isNaN(firstDay) ? 0 : firstDay); 5456 5457 showWeek = this._get(inst, "showWeek"); 5458 dayNames = this._get(inst, "dayNames"); 5459 dayNamesMin = this._get(inst, "dayNamesMin"); 5460 monthNames = this._get(inst, "monthNames"); 5461 monthNamesShort = this._get(inst, "monthNamesShort"); 5462 beforeShowDay = this._get(inst, "beforeShowDay"); 5463 showOtherMonths = this._get(inst, "showOtherMonths"); 5464 selectOtherMonths = this._get(inst, "selectOtherMonths"); 5465 defaultDate = this._getDefaultDate(inst); 5466 html = ""; 5467 dow; 5468 for (row = 0; row < numMonths[0]; row++) { 5469 group = ""; 5470 this.maxRows = 4; 5471 for (col = 0; col < numMonths[1]; col++) { 5472 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); 5473 cornerClass = " ui-corner-all"; 5474 calender = ""; 5475 if (isMultiMonth) { 5476 calender += "<div class='ui-datepicker-group"; 5477 if (numMonths[1] > 1) { 5478 switch (col) { 5479 case 0: calender += " ui-datepicker-group-first"; 5480 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break; 5481 case numMonths[1]-1: calender += " ui-datepicker-group-last"; 5482 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break; 5483 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 5484 } 5485 } 5486 calender += "'>"; 5487 } 5488 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 5489 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + 5490 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + 5491 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, 5492 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers 5493 "</div><table class='ui-datepicker-calendar'><thead>" + 5494 "<tr>"; 5495 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : ""); 5496 for (dow = 0; dow < 7; dow++) { // days of the week 5497 day = (dow + firstDay) % 7; 5498 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + 5499 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>"; 5500 } 5501 calender += thead + "</tr></thead><tbody>"; 5502 daysInMonth = this._getDaysInMonth(drawYear, drawMonth); 5503 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { 5504 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); 5505 } 5506 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; 5507 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate 5508 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) 5509 this.maxRows = numRows; 5510 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); 5511 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows 5512 calender += "<tr>"; 5513 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 5514 this._get(inst, "calculateWeek")(printDate) + "</td>"); 5515 for (dow = 0; dow < 7; dow++) { // create date picker days 5516 daySettings = (beforeShowDay ? 5517 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); 5518 otherMonth = (printDate.getMonth() !== drawMonth); 5519 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || 5520 (minDate && printDate < minDate) || (maxDate && printDate > maxDate); 5521 tbody += "<td class='" + 5522 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends 5523 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months 5524 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key 5525 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ? 5526 // or defaultDate is current printedDate and defaultDate is selectedDate 5527 " " + this._dayOverClass : "") + // highlight selected day 5528 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days 5529 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates 5530 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day 5531 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different) 5532 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title 5533 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions 5534 (otherMonth && !showOtherMonths ? " " : // display for other months 5535 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 5536 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") + 5537 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day 5538 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months 5539 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date 5540 printDate.setDate(printDate.getDate() + 1); 5541 printDate = this._daylightSavingAdjust(printDate); 5542 } 5543 calender += tbody + "</tr>"; 5544 } 5545 drawMonth++; 5546 if (drawMonth > 11) { 5547 drawMonth = 0; 5548 drawYear++; 5549 } 5550 calender += "</tbody></table>" + (isMultiMonth ? "</div>" + 5551 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : ""); 5552 group += calender; 5553 } 5554 html += group; 5555 } 5556 html += buttonPanel; 5557 inst._keyEvent = false; 5558 return html; 5559 }, 5560 5561 /* Generate the month and year header. */ 5562 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, 5563 secondary, monthNames, monthNamesShort) { 5564 5565 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 5566 changeMonth = this._get(inst, "changeMonth"), 5567 changeYear = this._get(inst, "changeYear"), 5568 showMonthAfterYear = this._get(inst, "showMonthAfterYear"), 5569 html = "<div class='ui-datepicker-title'>", 5570 monthHtml = ""; 5571 5572 // month selection 5573 if (secondary || !changeMonth) { 5574 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>"; 5575 } else { 5576 inMinYear = (minDate && minDate.getFullYear() === drawYear); 5577 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); 5578 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; 5579 for ( month = 0; month < 12; month++) { 5580 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) { 5581 monthHtml += "<option value='" + month + "'" + 5582 (month === drawMonth ? " selected='selected'" : "") + 5583 ">" + monthNamesShort[month] + "</option>"; 5584 } 5585 } 5586 monthHtml += "</select>"; 5587 } 5588 5589 if (!showMonthAfterYear) { 5590 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); 5591 } 5592 5593 // year selection 5594 if ( !inst.yearshtml ) { 5595 inst.yearshtml = ""; 5596 if (secondary || !changeYear) { 5597 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 5598 } else { 5599 // determine range of years to display 5600 years = this._get(inst, "yearRange").split(":"); 5601 thisYear = new Date().getFullYear(); 5602 determineYear = function(value) { 5603 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : 5604 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : 5605 parseInt(value, 10))); 5606 return (isNaN(year) ? thisYear : year); 5607 }; 5608 year = determineYear(years[0]); 5609 endYear = Math.max(year, determineYear(years[1] || "")); 5610 year = (minDate ? Math.max(year, minDate.getFullYear()) : year); 5611 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); 5612 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; 5613 for (; year <= endYear; year++) { 5614 inst.yearshtml += "<option value='" + year + "'" + 5615 (year === drawYear ? " selected='selected'" : "") + 5616 ">" + year + "</option>"; 5617 } 5618 inst.yearshtml += "</select>"; 5619 5620 html += inst.yearshtml; 5621 inst.yearshtml = null; 5622 } 5623 } 5624 5625 html += this._get(inst, "yearSuffix"); 5626 if (showMonthAfterYear) { 5627 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; 5628 } 5629 html += "</div>"; // Close datepicker_header 5630 return html; 5631 }, 5632 5633 /* Adjust one of the date sub-fields. */ 5634 _adjustInstDate: function(inst, offset, period) { 5635 var year = inst.drawYear + (period === "Y" ? offset : 0), 5636 month = inst.drawMonth + (period === "M" ? offset : 0), 5637 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), 5638 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); 5639 5640 inst.selectedDay = date.getDate(); 5641 inst.drawMonth = inst.selectedMonth = date.getMonth(); 5642 inst.drawYear = inst.selectedYear = date.getFullYear(); 5643 if (period === "M" || period === "Y") { 5644 this._notifyChange(inst); 5645 } 5646 }, 5647 5648 /* Ensure a date is within any min/max bounds. */ 5649 _restrictMinMax: function(inst, date) { 5650 var minDate = this._getMinMaxDate(inst, "min"), 5651 maxDate = this._getMinMaxDate(inst, "max"), 5652 newDate = (minDate && date < minDate ? minDate : date); 5653 return (maxDate && newDate > maxDate ? maxDate : newDate); 5654 }, 5655 5656 /* Notify change of month/year. */ 5657 _notifyChange: function(inst) { 5658 var onChange = this._get(inst, "onChangeMonthYear"); 5659 if (onChange) { 5660 onChange.apply((inst.input ? inst.input[0] : null), 5661 [inst.selectedYear, inst.selectedMonth + 1, inst]); 5662 } 5663 }, 5664 5665 /* Determine the number of months to show. */ 5666 _getNumberOfMonths: function(inst) { 5667 var numMonths = this._get(inst, "numberOfMonths"); 5668 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); 5669 }, 5670 5671 /* Determine the current maximum date - ensure no time components are set. */ 5672 _getMinMaxDate: function(inst, minMax) { 5673 return this._determineDate(inst, this._get(inst, minMax + "Date"), null); 5674 }, 5675 5676 /* Find the number of days in a given month. */ 5677 _getDaysInMonth: function(year, month) { 5678 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); 5679 }, 5680 5681 /* Find the day of the week of the first of a month. */ 5682 _getFirstDayOfMonth: function(year, month) { 5683 return new Date(year, month, 1).getDay(); 5684 }, 5685 5686 /* Determines if we should allow a "next/prev" month display change. */ 5687 _canAdjustMonth: function(inst, offset, curYear, curMonth) { 5688 var numMonths = this._getNumberOfMonths(inst), 5689 date = this._daylightSavingAdjust(new Date(curYear, 5690 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); 5691 5692 if (offset < 0) { 5693 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); 5694 } 5695 return this._isInRange(inst, date); 5696 }, 5697 5698 /* Is the given date in the accepted range? */ 5699 _isInRange: function(inst, date) { 5700 var yearSplit, currentYear, 5701 minDate = this._getMinMaxDate(inst, "min"), 5702 maxDate = this._getMinMaxDate(inst, "max"), 5703 minYear = null, 5704 maxYear = null, 5705 years = this._get(inst, "yearRange"); 5706 if (years){ 5707 yearSplit = years.split(":"); 5708 currentYear = new Date().getFullYear(); 5709 minYear = parseInt(yearSplit[0], 10); 5710 maxYear = parseInt(yearSplit[1], 10); 5711 if ( yearSplit[0].match(/[+\-].*/) ) { 5712 minYear += currentYear; 5713 } 5714 if ( yearSplit[1].match(/[+\-].*/) ) { 5715 maxYear += currentYear; 5716 } 5717 } 5718 5719 return ((!minDate || date.getTime() >= minDate.getTime()) && 5720 (!maxDate || date.getTime() <= maxDate.getTime()) && 5721 (!minYear || date.getFullYear() >= minYear) && 5722 (!maxYear || date.getFullYear() <= maxYear)); 5723 }, 5724 5725 /* Provide the configuration settings for formatting/parsing. */ 5726 _getFormatConfig: function(inst) { 5727 var shortYearCutoff = this._get(inst, "shortYearCutoff"); 5728 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : 5729 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); 5730 return {shortYearCutoff: shortYearCutoff, 5731 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), 5732 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; 5733 }, 5734 5735 /* Format the given date for display. */ 5736 _formatDate: function(inst, day, month, year) { 5737 if (!day) { 5738 inst.currentDay = inst.selectedDay; 5739 inst.currentMonth = inst.selectedMonth; 5740 inst.currentYear = inst.selectedYear; 5741 } 5742 var date = (day ? (typeof day === "object" ? day : 5743 this._daylightSavingAdjust(new Date(year, month, day))) : 5744 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); 5745 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); 5746 } 5747 }); 5748 5749 /* 5750 * Bind hover events for datepicker elements. 5751 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 5752 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 5753 */ 5754 function datepicker_bindHover(dpDiv) { 5755 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 5756 return dpDiv.delegate(selector, "mouseout", function() { 5757 $(this).removeClass("ui-state-hover"); 5758 if (this.className.indexOf("ui-datepicker-prev") !== -1) { 5759 $(this).removeClass("ui-datepicker-prev-hover"); 5760 } 5761 if (this.className.indexOf("ui-datepicker-next") !== -1) { 5762 $(this).removeClass("ui-datepicker-next-hover"); 5763 } 5764 }) 5765 .delegate( selector, "mouseover", datepicker_handleMouseover ); 5766 } 5767 5768 function datepicker_handleMouseover() { 5769 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) { 5770 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); 5771 $(this).addClass("ui-state-hover"); 5772 if (this.className.indexOf("ui-datepicker-prev") !== -1) { 5773 $(this).addClass("ui-datepicker-prev-hover"); 5774 } 5775 if (this.className.indexOf("ui-datepicker-next") !== -1) { 5776 $(this).addClass("ui-datepicker-next-hover"); 5777 } 5778 } 5779 } 5780 5781 /* jQuery extend now ignores nulls! */ 5782 function datepicker_extendRemove(target, props) { 5783 $.extend(target, props); 5784 for (var name in props) { 5785 if (props[name] == null) { 5786 target[name] = props[name]; 5787 } 5788 } 5789 return target; 5790 } 5791 5792 /* Invoke the datepicker functionality. 5793 @param options string - a command, optionally followed by additional parameters or 5794 Object - settings for attaching new datepicker functionality 5795 @return jQuery object */ 5796 $.fn.datepicker = function(options){ 5797 5798 /* Verify an empty collection wasn't passed - Fixes #6976 */ 5799 if ( !this.length ) { 5800 return this; 5801 } 5802 5803 /* Initialise the date picker. */ 5804 if (!$.datepicker.initialized) { 5805 $(document).mousedown($.datepicker._checkExternalClick); 5806 $.datepicker.initialized = true; 5807 } 5808 5809 /* Append datepicker main container to body if not exist. */ 5810 if ($("#"+$.datepicker._mainDivId).length === 0) { 5811 $("body").append($.datepicker.dpDiv); 5812 } 5813 5814 var otherArgs = Array.prototype.slice.call(arguments, 1); 5815 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { 5816 return $.datepicker["_" + options + "Datepicker"]. 5817 apply($.datepicker, [this[0]].concat(otherArgs)); 5818 } 5819 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { 5820 return $.datepicker["_" + options + "Datepicker"]. 5821 apply($.datepicker, [this[0]].concat(otherArgs)); 5822 } 5823 return this.each(function() { 5824 typeof options === "string" ? 5825 $.datepicker["_" + options + "Datepicker"]. 5826 apply($.datepicker, [this].concat(otherArgs)) : 5827 $.datepicker._attachDatepicker(this, options); 5828 }); 5829 }; 5830 5831 $.datepicker = new Datepicker(); // singleton instance 5832 $.datepicker.initialized = false; 5833 $.datepicker.uuid = new Date().getTime(); 5834 $.datepicker.version = "1.11.4"; 5835 5836 var datepicker = $.datepicker; 5837 5838 5839 /*! 5840 * jQuery UI Draggable 1.11.4 5841 * http://jqueryui.com 5842 * 5843 * Copyright jQuery Foundation and other contributors 5844 * Released under the MIT license. 5845 * http://jquery.org/license 5846 * 5847 * http://api.jqueryui.com/draggable/ 5848 */ 5849 5850 5851 $.widget("ui.draggable", $.ui.mouse, { 5852 version: "1.11.4", 5853 widgetEventPrefix: "drag", 5854 options: { 5855 addClasses: true, 5856 appendTo: "parent", 5857 axis: false, 5858 connectToSortable: false, 5859 containment: false, 5860 cursor: "auto", 5861 cursorAt: false, 5862 grid: false, 5863 handle: false, 5864 helper: "original", 5865 iframeFix: false, 5866 opacity: false, 5867 refreshPositions: false, 5868 revert: false, 5869 revertDuration: 500, 5870 scope: "default", 5871 scroll: true, 5872 scrollSensitivity: 20, 5873 scrollSpeed: 20, 5874 snap: false, 5875 snapMode: "both", 5876 snapTolerance: 20, 5877 stack: false, 5878 zIndex: false, 5879 5880 // callbacks 5881 drag: null, 5882 start: null, 5883 stop: null 5884 }, 5885 _create: function() { 5886 5887 if ( this.options.helper === "original" ) { 5888 this._setPositionRelative(); 5889 } 5890 if (this.options.addClasses){ 5891 this.element.addClass("ui-draggable"); 5892 } 5893 if (this.options.disabled){ 5894 this.element.addClass("ui-draggable-disabled"); 5895 } 5896 this._setHandleClassName(); 5897 5898 this._mouseInit(); 5899 }, 5900 5901 _setOption: function( key, value ) { 5902 this._super( key, value ); 5903 if ( key === "handle" ) { 5904 this._removeHandleClassName(); 5905 this._setHandleClassName(); 5906 } 5907 }, 5908 5909 _destroy: function() { 5910 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { 5911 this.destroyOnClear = true; 5912 return; 5913 } 5914 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); 5915 this._removeHandleClassName(); 5916 this._mouseDestroy(); 5917 }, 5918 5919 _mouseCapture: function(event) { 5920 var o = this.options; 5921 5922 this._blurActiveElement( event ); 5923 5924 // among others, prevent a drag on a resizable-handle 5925 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { 5926 return false; 5927 } 5928 5929 //Quit if we're not on a valid handle 5930 this.handle = this._getHandle(event); 5931 if (!this.handle) { 5932 return false; 5933 } 5934 5935 this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix ); 5936 5937 return true; 5938 5939 }, 5940 5941 _blockFrames: function( selector ) { 5942 this.iframeBlocks = this.document.find( selector ).map(function() { 5943 var iframe = $( this ); 5944 5945 return $( "<div>" ) 5946 .css( "position", "absolute" ) 5947 .appendTo( iframe.parent() ) 5948 .outerWidth( iframe.outerWidth() ) 5949 .outerHeight( iframe.outerHeight() ) 5950 .offset( iframe.offset() )[ 0 ]; 5951 }); 5952 }, 5953 5954 _unblockFrames: function() { 5955 if ( this.iframeBlocks ) { 5956 this.iframeBlocks.remove(); 5957 delete this.iframeBlocks; 5958 } 5959 }, 5960 5961 _blurActiveElement: function( event ) { 5962 var document = this.document[ 0 ]; 5963 5964 // Only need to blur if the event occurred on the draggable itself, see #10527 5965 if ( !this.handleElement.is( event.target ) ) { 5966 return; 5967 } 5968 5969 // support: IE9 5970 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 5971 try { 5972 5973 // Support: IE9, IE10 5974 // If the <body> is blurred, IE will switch windows, see #9520 5975 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) { 5976 5977 // Blur any element that currently has focus, see #4261 5978 $( document.activeElement ).blur(); 5979 } 5980 } catch ( error ) {} 5981 }, 5982 5983 _mouseStart: function(event) { 5984 5985 var o = this.options; 5986 5987 //Create and append the visible helper 5988 this.helper = this._createHelper(event); 5989 5990 this.helper.addClass("ui-draggable-dragging"); 5991 5992 //Cache the helper size 5993 this._cacheHelperProportions(); 5994 5995 //If ddmanager is used for droppables, set the global draggable 5996 if ($.ui.ddmanager) { 5997 $.ui.ddmanager.current = this; 5998 } 5999 6000 /* 6001 * - Position generation - 6002 * This block generates everything position related - it's the core of draggables. 6003 */ 6004 6005 //Cache the margins of the original element 6006 this._cacheMargins(); 6007 6008 //Store the helper's css position 6009 this.cssPosition = this.helper.css( "position" ); 6010 this.scrollParent = this.helper.scrollParent( true ); 6011 this.offsetParent = this.helper.offsetParent(); 6012 this.hasFixedAncestor = this.helper.parents().filter(function() { 6013 return $( this ).css( "position" ) === "fixed"; 6014 }).length > 0; 6015 6016 //The element's absolute position on the page minus margins 6017 this.positionAbs = this.element.offset(); 6018 this._refreshOffsets( event ); 6019 6020 //Generate the original position 6021 this.originalPosition = this.position = this._generatePosition( event, false ); 6022 this.originalPageX = event.pageX; 6023 this.originalPageY = event.pageY; 6024 6025 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 6026 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); 6027 6028 //Set a containment if given in the options 6029 this._setContainment(); 6030 6031 //Trigger event + callbacks 6032 if (this._trigger("start", event) === false) { 6033 this._clear(); 6034 return false; 6035 } 6036 6037 //Recache the helper size 6038 this._cacheHelperProportions(); 6039 6040 //Prepare the droppable offsets 6041 if ($.ui.ddmanager && !o.dropBehaviour) { 6042 $.ui.ddmanager.prepareOffsets(this, event); 6043 } 6044 6045 // Reset helper's right/bottom css if they're set and set explicit width/height instead 6046 // as this prevents resizing of elements with right/bottom set (see #7772) 6047 this._normalizeRightBottom(); 6048 6049 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position 6050 6051 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) 6052 if ( $.ui.ddmanager ) { 6053 $.ui.ddmanager.dragStart(this, event); 6054 } 6055 6056 return true; 6057 }, 6058 6059 _refreshOffsets: function( event ) { 6060 this.offset = { 6061 top: this.positionAbs.top - this.margins.top, 6062 left: this.positionAbs.left - this.margins.left, 6063 scroll: false, 6064 parent: this._getParentOffset(), 6065 relative: this._getRelativeOffset() 6066 }; 6067 6068 this.offset.click = { 6069 left: event.pageX - this.offset.left, 6070 top: event.pageY - this.offset.top 6071 }; 6072 }, 6073 6074 _mouseDrag: function(event, noPropagation) { 6075 // reset any necessary cached properties (see #5009) 6076 if ( this.hasFixedAncestor ) { 6077 this.offset.parent = this._getParentOffset(); 6078 } 6079 6080 //Compute the helpers position 6081 this.position = this._generatePosition( event, true ); 6082 this.positionAbs = this._convertPositionTo("absolute"); 6083 6084 //Call plugins and callbacks and use the resulting position if something is returned 6085 if (!noPropagation) { 6086 var ui = this._uiHash(); 6087 if (this._trigger("drag", event, ui) === false) { 6088 this._mouseUp({}); 6089 return false; 6090 } 6091 this.position = ui.position; 6092 } 6093 6094 this.helper[ 0 ].style.left = this.position.left + "px"; 6095 this.helper[ 0 ].style.top = this.position.top + "px"; 6096 6097 if ($.ui.ddmanager) { 6098 $.ui.ddmanager.drag(this, event); 6099 } 6100 6101 return false; 6102 }, 6103 6104 _mouseStop: function(event) { 6105 6106 //If we are using droppables, inform the manager about the drop 6107 var that = this, 6108 dropped = false; 6109 if ($.ui.ddmanager && !this.options.dropBehaviour) { 6110 dropped = $.ui.ddmanager.drop(this, event); 6111 } 6112 6113 //if a drop comes from outside (a sortable) 6114 if (this.dropped) { 6115 dropped = this.dropped; 6116 this.dropped = false; 6117 } 6118 6119 if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { 6120 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { 6121 if (that._trigger("stop", event) !== false) { 6122 that._clear(); 6123 } 6124 }); 6125 } else { 6126 if (this._trigger("stop", event) !== false) { 6127 this._clear(); 6128 } 6129 } 6130 6131 return false; 6132 }, 6133 6134 _mouseUp: function( event ) { 6135 this._unblockFrames(); 6136 6137 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) 6138 if ( $.ui.ddmanager ) { 6139 $.ui.ddmanager.dragStop(this, event); 6140 } 6141 6142 // Only need to focus if the event occurred on the draggable itself, see #10527 6143 if ( this.handleElement.is( event.target ) ) { 6144 // The interaction is over; whether or not the click resulted in a drag, focus the element 6145 this.element.focus(); 6146 } 6147 6148 return $.ui.mouse.prototype._mouseUp.call(this, event); 6149 }, 6150 6151 cancel: function() { 6152 6153 if (this.helper.is(".ui-draggable-dragging")) { 6154 this._mouseUp({}); 6155 } else { 6156 this._clear(); 6157 } 6158 6159 return this; 6160 6161 }, 6162 6163 _getHandle: function(event) { 6164 return this.options.handle ? 6165 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : 6166 true; 6167 }, 6168 6169 _setHandleClassName: function() { 6170 this.handleElement = this.options.handle ? 6171 this.element.find( this.options.handle ) : this.element; 6172 this.handleElement.addClass( "ui-draggable-handle" ); 6173 }, 6174 6175 _removeHandleClassName: function() { 6176 this.handleElement.removeClass( "ui-draggable-handle" ); 6177 }, 6178 6179 _createHelper: function(event) { 6180 6181 var o = this.options, 6182 helperIsFunction = $.isFunction( o.helper ), 6183 helper = helperIsFunction ? 6184 $( o.helper.apply( this.element[ 0 ], [ event ] ) ) : 6185 ( o.helper === "clone" ? 6186 this.element.clone().removeAttr( "id" ) : 6187 this.element ); 6188 6189 if (!helper.parents("body").length) { 6190 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); 6191 } 6192 6193 // http://bugs.jqueryui.com/ticket/9446 6194 // a helper function can return the original element 6195 // which wouldn't have been set to relative in _create 6196 if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) { 6197 this._setPositionRelative(); 6198 } 6199 6200 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { 6201 helper.css("position", "absolute"); 6202 } 6203 6204 return helper; 6205 6206 }, 6207 6208 _setPositionRelative: function() { 6209 if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) { 6210 this.element[ 0 ].style.position = "relative"; 6211 } 6212 }, 6213 6214 _adjustOffsetFromHelper: function(obj) { 6215 if (typeof obj === "string") { 6216 obj = obj.split(" "); 6217 } 6218 if ($.isArray(obj)) { 6219 obj = { left: +obj[0], top: +obj[1] || 0 }; 6220 } 6221 if ("left" in obj) { 6222 this.offset.click.left = obj.left + this.margins.left; 6223 } 6224 if ("right" in obj) { 6225 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 6226 } 6227 if ("top" in obj) { 6228 this.offset.click.top = obj.top + this.margins.top; 6229 } 6230 if ("bottom" in obj) { 6231 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 6232 } 6233 }, 6234 6235 _isRootNode: function( element ) { 6236 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; 6237 }, 6238 6239 _getParentOffset: function() { 6240 6241 //Get the offsetParent and cache its position 6242 var po = this.offsetParent.offset(), 6243 document = this.document[ 0 ]; 6244 6245 // This is a special case where we need to modify a offset calculated on start, since the following happened: 6246 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent 6247 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that 6248 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag 6249 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { 6250 po.left += this.scrollParent.scrollLeft(); 6251 po.top += this.scrollParent.scrollTop(); 6252 } 6253 6254 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { 6255 po = { top: 0, left: 0 }; 6256 } 6257 6258 return { 6259 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0), 6260 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0) 6261 }; 6262 6263 }, 6264 6265 _getRelativeOffset: function() { 6266 if ( this.cssPosition !== "relative" ) { 6267 return { top: 0, left: 0 }; 6268 } 6269 6270 var p = this.element.position(), 6271 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 6272 6273 return { 6274 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), 6275 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) 6276 }; 6277 6278 }, 6279 6280 _cacheMargins: function() { 6281 this.margins = { 6282 left: (parseInt(this.element.css("marginLeft"), 10) || 0), 6283 top: (parseInt(this.element.css("marginTop"), 10) || 0), 6284 right: (parseInt(this.element.css("marginRight"), 10) || 0), 6285 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0) 6286 }; 6287 }, 6288 6289 _cacheHelperProportions: function() { 6290 this.helperProportions = { 6291 width: this.helper.outerWidth(), 6292 height: this.helper.outerHeight() 6293 }; 6294 }, 6295 6296 _setContainment: function() { 6297 6298 var isUserScrollable, c, ce, 6299 o = this.options, 6300 document = this.document[ 0 ]; 6301 6302 this.relativeContainer = null; 6303 6304 if ( !o.containment ) { 6305 this.containment = null; 6306 return; 6307 } 6308 6309 if ( o.containment === "window" ) { 6310 this.containment = [ 6311 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 6312 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, 6313 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, 6314 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top 6315 ]; 6316 return; 6317 } 6318 6319 if ( o.containment === "document") { 6320 this.containment = [ 6321 0, 6322 0, 6323 $( document ).width() - this.helperProportions.width - this.margins.left, 6324 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top 6325 ]; 6326 return; 6327 } 6328 6329 if ( o.containment.constructor === Array ) { 6330 this.containment = o.containment; 6331 return; 6332 } 6333 6334 if ( o.containment === "parent" ) { 6335 o.containment = this.helper[ 0 ].parentNode; 6336 } 6337 6338 c = $( o.containment ); 6339 ce = c[ 0 ]; 6340 6341 if ( !ce ) { 6342 return; 6343 } 6344 6345 isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) ); 6346 6347 this.containment = [ 6348 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), 6349 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), 6350 ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - 6351 ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - 6352 ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - 6353 this.helperProportions.width - 6354 this.margins.left - 6355 this.margins.right, 6356 ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - 6357 ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - 6358 ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - 6359 this.helperProportions.height - 6360 this.margins.top - 6361 this.margins.bottom 6362 ]; 6363 this.relativeContainer = c; 6364 }, 6365 6366 _convertPositionTo: function(d, pos) { 6367 6368 if (!pos) { 6369 pos = this.position; 6370 } 6371 6372 var mod = d === "absolute" ? 1 : -1, 6373 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 6374 6375 return { 6376 top: ( 6377 pos.top + // The absolute mouse position 6378 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 6379 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) 6380 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod) 6381 ), 6382 left: ( 6383 pos.left + // The absolute mouse position 6384 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 6385 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) 6386 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod) 6387 ) 6388 }; 6389 6390 }, 6391 6392 _generatePosition: function( event, constrainPosition ) { 6393 6394 var containment, co, top, left, 6395 o = this.options, 6396 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), 6397 pageX = event.pageX, 6398 pageY = event.pageY; 6399 6400 // Cache the scroll 6401 if ( !scrollIsRootNode || !this.offset.scroll ) { 6402 this.offset.scroll = { 6403 top: this.scrollParent.scrollTop(), 6404 left: this.scrollParent.scrollLeft() 6405 }; 6406 } 6407 6408 /* 6409 * - Position constraining - 6410 * Constrain the position to a mix of grid, containment. 6411 */ 6412 6413 // If we are not dragging yet, we won't check for options 6414 if ( constrainPosition ) { 6415 if ( this.containment ) { 6416 if ( this.relativeContainer ){ 6417 co = this.relativeContainer.offset(); 6418 containment = [ 6419 this.containment[ 0 ] + co.left, 6420 this.containment[ 1 ] + co.top, 6421 this.containment[ 2 ] + co.left, 6422 this.containment[ 3 ] + co.top 6423 ]; 6424 } else { 6425 containment = this.containment; 6426 } 6427 6428 if (event.pageX - this.offset.click.left < containment[0]) { 6429 pageX = containment[0] + this.offset.click.left; 6430 } 6431 if (event.pageY - this.offset.click.top < containment[1]) { 6432 pageY = containment[1] + this.offset.click.top; 6433 } 6434 if (event.pageX - this.offset.click.left > containment[2]) { 6435 pageX = containment[2] + this.offset.click.left; 6436 } 6437 if (event.pageY - this.offset.click.top > containment[3]) { 6438 pageY = containment[3] + this.offset.click.top; 6439 } 6440 } 6441 6442 if (o.grid) { 6443 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) 6444 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; 6445 pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; 6446 6447 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; 6448 pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; 6449 } 6450 6451 if ( o.axis === "y" ) { 6452 pageX = this.originalPageX; 6453 } 6454 6455 if ( o.axis === "x" ) { 6456 pageY = this.originalPageY; 6457 } 6458 } 6459 6460 return { 6461 top: ( 6462 pageY - // The absolute mouse position 6463 this.offset.click.top - // Click offset (relative to the element) 6464 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent 6465 this.offset.parent.top + // The offsetParent's offset without borders (offset + border) 6466 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) 6467 ), 6468 left: ( 6469 pageX - // The absolute mouse position 6470 this.offset.click.left - // Click offset (relative to the element) 6471 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent 6472 this.offset.parent.left + // The offsetParent's offset without borders (offset + border) 6473 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) 6474 ) 6475 }; 6476 6477 }, 6478 6479 _clear: function() { 6480 this.helper.removeClass("ui-draggable-dragging"); 6481 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { 6482 this.helper.remove(); 6483 } 6484 this.helper = null; 6485 this.cancelHelperRemoval = false; 6486 if ( this.destroyOnClear ) { 6487 this.destroy(); 6488 } 6489 }, 6490 6491 _normalizeRightBottom: function() { 6492 if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) { 6493 this.helper.width( this.helper.width() ); 6494 this.helper.css( "right", "auto" ); 6495 } 6496 if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) { 6497 this.helper.height( this.helper.height() ); 6498 this.helper.css( "bottom", "auto" ); 6499 } 6500 }, 6501 6502 // From now on bulk stuff - mainly helpers 6503 6504 _trigger: function( type, event, ui ) { 6505 ui = ui || this._uiHash(); 6506 $.ui.plugin.call( this, type, [ event, ui, this ], true ); 6507 6508 // Absolute position and offset (see #6884 ) have to be recalculated after plugins 6509 if ( /^(drag|start|stop)/.test( type ) ) { 6510 this.positionAbs = this._convertPositionTo( "absolute" ); 6511 ui.offset = this.positionAbs; 6512 } 6513 return $.Widget.prototype._trigger.call( this, type, event, ui ); 6514 }, 6515 6516 plugins: {}, 6517 6518 _uiHash: function() { 6519 return { 6520 helper: this.helper, 6521 position: this.position, 6522 originalPosition: this.originalPosition, 6523 offset: this.positionAbs 6524 }; 6525 } 6526 6527 }); 6528 6529 $.ui.plugin.add( "draggable", "connectToSortable", { 6530 start: function( event, ui, draggable ) { 6531 var uiSortable = $.extend( {}, ui, { 6532 item: draggable.element 6533 }); 6534 6535 draggable.sortables = []; 6536 $( draggable.options.connectToSortable ).each(function() { 6537 var sortable = $( this ).sortable( "instance" ); 6538 6539 if ( sortable && !sortable.options.disabled ) { 6540 draggable.sortables.push( sortable ); 6541 6542 // refreshPositions is called at drag start to refresh the containerCache 6543 // which is used in drag. This ensures it's initialized and synchronized 6544 // with any changes that might have happened on the page since initialization. 6545 sortable.refreshPositions(); 6546 sortable._trigger("activate", event, uiSortable); 6547 } 6548 }); 6549 }, 6550 stop: function( event, ui, draggable ) { 6551 var uiSortable = $.extend( {}, ui, { 6552 item: draggable.element 6553 }); 6554 6555 draggable.cancelHelperRemoval = false; 6556 6557 $.each( draggable.sortables, function() { 6558 var sortable = this; 6559 6560 if ( sortable.isOver ) { 6561 sortable.isOver = 0; 6562 6563 // Allow this sortable to handle removing the helper 6564 draggable.cancelHelperRemoval = true; 6565 sortable.cancelHelperRemoval = false; 6566 6567 // Use _storedCSS To restore properties in the sortable, 6568 // as this also handles revert (#9675) since the draggable 6569 // may have modified them in unexpected ways (#8809) 6570 sortable._storedCSS = { 6571 position: sortable.placeholder.css( "position" ), 6572 top: sortable.placeholder.css( "top" ), 6573 left: sortable.placeholder.css( "left" ) 6574 }; 6575 6576 sortable._mouseStop(event); 6577 6578 // Once drag has ended, the sortable should return to using 6579 // its original helper, not the shared helper from draggable 6580 sortable.options.helper = sortable.options._helper; 6581 } else { 6582 // Prevent this Sortable from removing the helper. 6583 // However, don't set the draggable to remove the helper 6584 // either as another connected Sortable may yet handle the removal. 6585 sortable.cancelHelperRemoval = true; 6586 6587 sortable._trigger( "deactivate", event, uiSortable ); 6588 } 6589 }); 6590 }, 6591 drag: function( event, ui, draggable ) { 6592 $.each( draggable.sortables, function() { 6593 var innermostIntersecting = false, 6594 sortable = this; 6595 6596 // Copy over variables that sortable's _intersectsWith uses 6597 sortable.positionAbs = draggable.positionAbs; 6598 sortable.helperProportions = draggable.helperProportions; 6599 sortable.offset.click = draggable.offset.click; 6600 6601 if ( sortable._intersectsWith( sortable.containerCache ) ) { 6602 innermostIntersecting = true; 6603 6604 $.each( draggable.sortables, function() { 6605 // Copy over variables that sortable's _intersectsWith uses 6606 this.positionAbs = draggable.positionAbs; 6607 this.helperProportions = draggable.helperProportions; 6608 this.offset.click = draggable.offset.click; 6609 6610 if ( this !== sortable && 6611 this._intersectsWith( this.containerCache ) && 6612 $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) { 6613 innermostIntersecting = false; 6614 } 6615 6616 return innermostIntersecting; 6617 }); 6618 } 6619 6620 if ( innermostIntersecting ) { 6621 // If it intersects, we use a little isOver variable and set it once, 6622 // so that the move-in stuff gets fired only once. 6623 if ( !sortable.isOver ) { 6624 sortable.isOver = 1; 6625 6626 // Store draggable's parent in case we need to reappend to it later. 6627 draggable._parent = ui.helper.parent(); 6628 6629 sortable.currentItem = ui.helper 6630 .appendTo( sortable.element ) 6631 .data( "ui-sortable-item", true ); 6632 6633 // Store helper option to later restore it 6634 sortable.options._helper = sortable.options.helper; 6635 6636 sortable.options.helper = function() { 6637 return ui.helper[ 0 ]; 6638 }; 6639 6640 // Fire the start events of the sortable with our passed browser event, 6641 // and our own helper (so it doesn't create a new one) 6642 event.target = sortable.currentItem[ 0 ]; 6643 sortable._mouseCapture( event, true ); 6644 sortable._mouseStart( event, true, true ); 6645 6646 // Because the browser event is way off the new appended portlet, 6647 // modify necessary variables to reflect the changes 6648 sortable.offset.click.top = draggable.offset.click.top; 6649 sortable.offset.click.left = draggable.offset.click.left; 6650 sortable.offset.parent.left -= draggable.offset.parent.left - 6651 sortable.offset.parent.left; 6652 sortable.offset.parent.top -= draggable.offset.parent.top - 6653 sortable.offset.parent.top; 6654 6655 draggable._trigger( "toSortable", event ); 6656 6657 // Inform draggable that the helper is in a valid drop zone, 6658 // used solely in the revert option to handle "valid/invalid". 6659 draggable.dropped = sortable.element; 6660 6661 // Need to refreshPositions of all sortables in the case that 6662 // adding to one sortable changes the location of the other sortables (#9675) 6663 $.each( draggable.sortables, function() { 6664 this.refreshPositions(); 6665 }); 6666 6667 // hack so receive/update callbacks work (mostly) 6668 draggable.currentItem = draggable.element; 6669 sortable.fromOutside = draggable; 6670 } 6671 6672 if ( sortable.currentItem ) { 6673 sortable._mouseDrag( event ); 6674 // Copy the sortable's position because the draggable's can potentially reflect 6675 // a relative position, while sortable is always absolute, which the dragged 6676 // element has now become. (#8809) 6677 ui.position = sortable.position; 6678 } 6679 } else { 6680 // If it doesn't intersect with the sortable, and it intersected before, 6681 // we fake the drag stop of the sortable, but make sure it doesn't remove 6682 // the helper by using cancelHelperRemoval. 6683 if ( sortable.isOver ) { 6684 6685 sortable.isOver = 0; 6686 sortable.cancelHelperRemoval = true; 6687 6688 // Calling sortable's mouseStop would trigger a revert, 6689 // so revert must be temporarily false until after mouseStop is called. 6690 sortable.options._revert = sortable.options.revert; 6691 sortable.options.revert = false; 6692 6693 sortable._trigger( "out", event, sortable._uiHash( sortable ) ); 6694 sortable._mouseStop( event, true ); 6695 6696 // restore sortable behaviors that were modfied 6697 // when the draggable entered the sortable area (#9481) 6698 sortable.options.revert = sortable.options._revert; 6699 sortable.options.helper = sortable.options._helper; 6700 6701 if ( sortable.placeholder ) { 6702 sortable.placeholder.remove(); 6703 } 6704 6705 // Restore and recalculate the draggable's offset considering the sortable 6706 // may have modified them in unexpected ways. (#8809, #10669) 6707 ui.helper.appendTo( draggable._parent ); 6708 draggable._refreshOffsets( event ); 6709 ui.position = draggable._generatePosition( event, true ); 6710 6711 draggable._trigger( "fromSortable", event ); 6712 6713 // Inform draggable that the helper is no longer in a valid drop zone 6714 draggable.dropped = false; 6715 6716 // Need to refreshPositions of all sortables just in case removing 6717 // from one sortable changes the location of other sortables (#9675) 6718 $.each( draggable.sortables, function() { 6719 this.refreshPositions(); 6720 }); 6721 } 6722 } 6723 }); 6724 } 6725 }); 6726 6727 $.ui.plugin.add("draggable", "cursor", { 6728 start: function( event, ui, instance ) { 6729 var t = $( "body" ), 6730 o = instance.options; 6731 6732 if (t.css("cursor")) { 6733 o._cursor = t.css("cursor"); 6734 } 6735 t.css("cursor", o.cursor); 6736 }, 6737 stop: function( event, ui, instance ) { 6738 var o = instance.options; 6739 if (o._cursor) { 6740 $("body").css("cursor", o._cursor); 6741 } 6742 } 6743 }); 6744 6745 $.ui.plugin.add("draggable", "opacity", { 6746 start: function( event, ui, instance ) { 6747 var t = $( ui.helper ), 6748 o = instance.options; 6749 if (t.css("opacity")) { 6750 o._opacity = t.css("opacity"); 6751 } 6752 t.css("opacity", o.opacity); 6753 }, 6754 stop: function( event, ui, instance ) { 6755 var o = instance.options; 6756 if (o._opacity) { 6757 $(ui.helper).css("opacity", o._opacity); 6758 } 6759 } 6760 }); 6761 6762 $.ui.plugin.add("draggable", "scroll", { 6763 start: function( event, ui, i ) { 6764 if ( !i.scrollParentNotHidden ) { 6765 i.scrollParentNotHidden = i.helper.scrollParent( false ); 6766 } 6767 6768 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { 6769 i.overflowOffset = i.scrollParentNotHidden.offset(); 6770 } 6771 }, 6772 drag: function( event, ui, i ) { 6773 6774 var o = i.options, 6775 scrolled = false, 6776 scrollParent = i.scrollParentNotHidden[ 0 ], 6777 document = i.document[ 0 ]; 6778 6779 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { 6780 if ( !o.axis || o.axis !== "x" ) { 6781 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) { 6782 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; 6783 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { 6784 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; 6785 } 6786 } 6787 6788 if ( !o.axis || o.axis !== "y" ) { 6789 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) { 6790 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; 6791 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { 6792 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; 6793 } 6794 } 6795 6796 } else { 6797 6798 if (!o.axis || o.axis !== "x") { 6799 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) { 6800 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 6801 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { 6802 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 6803 } 6804 } 6805 6806 if (!o.axis || o.axis !== "y") { 6807 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { 6808 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 6809 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { 6810 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 6811 } 6812 } 6813 6814 } 6815 6816 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { 6817 $.ui.ddmanager.prepareOffsets(i, event); 6818 } 6819 6820 } 6821 }); 6822 6823 $.ui.plugin.add("draggable", "snap", { 6824 start: function( event, ui, i ) { 6825 6826 var o = i.options; 6827 6828 i.snapElements = []; 6829 6830 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { 6831 var $t = $(this), 6832 $o = $t.offset(); 6833 if (this !== i.element[0]) { 6834 i.snapElements.push({ 6835 item: this, 6836 width: $t.outerWidth(), height: $t.outerHeight(), 6837 top: $o.top, left: $o.left 6838 }); 6839 } 6840 }); 6841 6842 }, 6843 drag: function( event, ui, inst ) { 6844 6845 var ts, bs, ls, rs, l, r, t, b, i, first, 6846 o = inst.options, 6847 d = o.snapTolerance, 6848 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 6849 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 6850 6851 for (i = inst.snapElements.length - 1; i >= 0; i--){ 6852 6853 l = inst.snapElements[i].left - inst.margins.left; 6854 r = l + inst.snapElements[i].width; 6855 t = inst.snapElements[i].top - inst.margins.top; 6856 b = t + inst.snapElements[i].height; 6857 6858 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { 6859 if (inst.snapElements[i].snapping) { 6860 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); 6861 } 6862 inst.snapElements[i].snapping = false; 6863 continue; 6864 } 6865 6866 if (o.snapMode !== "inner") { 6867 ts = Math.abs(t - y2) <= d; 6868 bs = Math.abs(b - y1) <= d; 6869 ls = Math.abs(l - x2) <= d; 6870 rs = Math.abs(r - x1) <= d; 6871 if (ts) { 6872 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top; 6873 } 6874 if (bs) { 6875 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top; 6876 } 6877 if (ls) { 6878 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left; 6879 } 6880 if (rs) { 6881 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left; 6882 } 6883 } 6884 6885 first = (ts || bs || ls || rs); 6886 6887 if (o.snapMode !== "outer") { 6888 ts = Math.abs(t - y1) <= d; 6889 bs = Math.abs(b - y2) <= d; 6890 ls = Math.abs(l - x1) <= d; 6891 rs = Math.abs(r - x2) <= d; 6892 if (ts) { 6893 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top; 6894 } 6895 if (bs) { 6896 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top; 6897 } 6898 if (ls) { 6899 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left; 6900 } 6901 if (rs) { 6902 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left; 6903 } 6904 } 6905 6906 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { 6907 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); 6908 } 6909 inst.snapElements[i].snapping = (ts || bs || ls || rs || first); 6910 6911 } 6912 6913 } 6914 }); 6915 6916 $.ui.plugin.add("draggable", "stack", { 6917 start: function( event, ui, instance ) { 6918 var min, 6919 o = instance.options, 6920 group = $.makeArray($(o.stack)).sort(function(a, b) { 6921 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0); 6922 }); 6923 6924 if (!group.length) { return; } 6925 6926 min = parseInt($(group[0]).css("zIndex"), 10) || 0; 6927 $(group).each(function(i) { 6928 $(this).css("zIndex", min + i); 6929 }); 6930 this.css("zIndex", (min + group.length)); 6931 } 6932 }); 6933 6934 $.ui.plugin.add("draggable", "zIndex", { 6935 start: function( event, ui, instance ) { 6936 var t = $( ui.helper ), 6937 o = instance.options; 6938 6939 if (t.css("zIndex")) { 6940 o._zIndex = t.css("zIndex"); 6941 } 6942 t.css("zIndex", o.zIndex); 6943 }, 6944 stop: function( event, ui, instance ) { 6945 var o = instance.options; 6946 6947 if (o._zIndex) { 6948 $(ui.helper).css("zIndex", o._zIndex); 6949 } 6950 } 6951 }); 6952 6953 var draggable = $.ui.draggable; 6954 6955 6956 /*! 6957 * jQuery UI Resizable 1.11.4 6958 * http://jqueryui.com 6959 * 6960 * Copyright jQuery Foundation and other contributors 6961 * Released under the MIT license. 6962 * http://jquery.org/license 6963 * 6964 * http://api.jqueryui.com/resizable/ 6965 */ 6966 6967 6968 $.widget("ui.resizable", $.ui.mouse, { 6969 version: "1.11.4", 6970 widgetEventPrefix: "resize", 6971 options: { 6972 alsoResize: false, 6973 animate: false, 6974 animateDuration: "slow", 6975 animateEasing: "swing", 6976 aspectRatio: false, 6977 autoHide: false, 6978 containment: false, 6979 ghost: false, 6980 grid: false, 6981 handles: "e,s,se", 6982 helper: false, 6983 maxHeight: null, 6984 maxWidth: null, 6985 minHeight: 10, 6986 minWidth: 10, 6987 // See #7960 6988 zIndex: 90, 6989 6990 // callbacks 6991 resize: null, 6992 start: null, 6993 stop: null 6994 }, 6995 6996 _num: function( value ) { 6997 return parseInt( value, 10 ) || 0; 6998 }, 6999 7000 _isNumber: function( value ) { 7001 return !isNaN( parseInt( value, 10 ) ); 7002 }, 7003 7004 _hasScroll: function( el, a ) { 7005 7006 if ( $( el ).css( "overflow" ) === "hidden") { 7007 return false; 7008 } 7009 7010 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", 7011 has = false; 7012 7013 if ( el[ scroll ] > 0 ) { 7014 return true; 7015 } 7016 7017 // TODO: determine which cases actually cause this to happen 7018 // if the element doesn't have the scroll set, see if it's possible to 7019 // set the scroll 7020 el[ scroll ] = 1; 7021 has = ( el[ scroll ] > 0 ); 7022 el[ scroll ] = 0; 7023 return has; 7024 }, 7025 7026 _create: function() { 7027 7028 var n, i, handle, axis, hname, 7029 that = this, 7030 o = this.options; 7031 this.element.addClass("ui-resizable"); 7032 7033 $.extend(this, { 7034 _aspectRatio: !!(o.aspectRatio), 7035 aspectRatio: o.aspectRatio, 7036 originalElement: this.element, 7037 _proportionallyResizeElements: [], 7038 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null 7039 }); 7040 7041 // Wrap the element if it cannot hold child nodes 7042 if (this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)) { 7043 7044 this.element.wrap( 7045 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ 7046 position: this.element.css("position"), 7047 width: this.element.outerWidth(), 7048 height: this.element.outerHeight(), 7049 top: this.element.css("top"), 7050 left: this.element.css("left") 7051 }) 7052 ); 7053 7054 this.element = this.element.parent().data( 7055 "ui-resizable", this.element.resizable( "instance" ) 7056 ); 7057 7058 this.elementIsWrapper = true; 7059 7060 this.element.css({ 7061 marginLeft: this.originalElement.css("marginLeft"), 7062 marginTop: this.originalElement.css("marginTop"), 7063 marginRight: this.originalElement.css("marginRight"), 7064 marginBottom: this.originalElement.css("marginBottom") 7065 }); 7066 this.originalElement.css({ 7067 marginLeft: 0, 7068 marginTop: 0, 7069 marginRight: 0, 7070 marginBottom: 0 7071 }); 7072 // support: Safari 7073 // Prevent Safari textarea resize 7074 this.originalResizeStyle = this.originalElement.css("resize"); 7075 this.originalElement.css("resize", "none"); 7076 7077 this._proportionallyResizeElements.push( this.originalElement.css({ 7078 position: "static", 7079 zoom: 1, 7080 display: "block" 7081 }) ); 7082 7083 // support: IE9 7084 // avoid IE jump (hard set the margin) 7085 this.originalElement.css({ margin: this.originalElement.css("margin") }); 7086 7087 this._proportionallyResize(); 7088 } 7089 7090 this.handles = o.handles || 7091 ( !$(".ui-resizable-handle", this.element).length ? 7092 "e,s,se" : { 7093 n: ".ui-resizable-n", 7094 e: ".ui-resizable-e", 7095 s: ".ui-resizable-s", 7096 w: ".ui-resizable-w", 7097 se: ".ui-resizable-se", 7098 sw: ".ui-resizable-sw", 7099 ne: ".ui-resizable-ne", 7100 nw: ".ui-resizable-nw" 7101 } ); 7102 7103 this._handles = $(); 7104 if ( this.handles.constructor === String ) { 7105 7106 if ( this.handles === "all") { 7107 this.handles = "n,e,s,w,se,sw,ne,nw"; 7108 } 7109 7110 n = this.handles.split(","); 7111 this.handles = {}; 7112 7113 for (i = 0; i < n.length; i++) { 7114 7115 handle = $.trim(n[i]); 7116 hname = "ui-resizable-" + handle; 7117 axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); 7118 7119 axis.css({ zIndex: o.zIndex }); 7120 7121 // TODO : What's going on here? 7122 if ("se" === handle) { 7123 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); 7124 } 7125 7126 this.handles[handle] = ".ui-resizable-" + handle; 7127 this.element.append(axis); 7128 } 7129 7130 } 7131 7132 this._renderAxis = function(target) { 7133 7134 var i, axis, padPos, padWrapper; 7135 7136 target = target || this.element; 7137 7138 for (i in this.handles) { 7139 7140 if (this.handles[i].constructor === String) { 7141 this.handles[i] = this.element.children( this.handles[ i ] ).first().show(); 7142 } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) { 7143 this.handles[ i ] = $( this.handles[ i ] ); 7144 this._on( this.handles[ i ], { "mousedown": that._mouseDown }); 7145 } 7146 7147 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)) { 7148 7149 axis = $(this.handles[i], this.element); 7150 7151 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); 7152 7153 padPos = [ "padding", 7154 /ne|nw|n/.test(i) ? "Top" : 7155 /se|sw|s/.test(i) ? "Bottom" : 7156 /^e$/.test(i) ? "Right" : "Left" ].join(""); 7157 7158 target.css(padPos, padWrapper); 7159 7160 this._proportionallyResize(); 7161 } 7162 7163 this._handles = this._handles.add( this.handles[ i ] ); 7164 } 7165 }; 7166 7167 // TODO: make renderAxis a prototype function 7168 this._renderAxis(this.element); 7169 7170 this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) ); 7171 this._handles.disableSelection(); 7172 7173 this._handles.mouseover(function() { 7174 if (!that.resizing) { 7175 if (this.className) { 7176 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); 7177 } 7178 that.axis = axis && axis[1] ? axis[1] : "se"; 7179 } 7180 }); 7181 7182 if (o.autoHide) { 7183 this._handles.hide(); 7184 $(this.element) 7185 .addClass("ui-resizable-autohide") 7186 .mouseenter(function() { 7187 if (o.disabled) { 7188 return; 7189 } 7190 $(this).removeClass("ui-resizable-autohide"); 7191 that._handles.show(); 7192 }) 7193 .mouseleave(function() { 7194 if (o.disabled) { 7195 return; 7196 } 7197 if (!that.resizing) { 7198 $(this).addClass("ui-resizable-autohide"); 7199 that._handles.hide(); 7200 } 7201 }); 7202 } 7203 7204 this._mouseInit(); 7205 }, 7206 7207 _destroy: function() { 7208 7209 this._mouseDestroy(); 7210 7211 var wrapper, 7212 _destroy = function(exp) { 7213 $(exp) 7214 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") 7215 .removeData("resizable") 7216 .removeData("ui-resizable") 7217 .unbind(".resizable") 7218 .find(".ui-resizable-handle") 7219 .remove(); 7220 }; 7221 7222 // TODO: Unwrap at same DOM position 7223 if (this.elementIsWrapper) { 7224 _destroy(this.element); 7225 wrapper = this.element; 7226 this.originalElement.css({ 7227 position: wrapper.css("position"), 7228 width: wrapper.outerWidth(), 7229 height: wrapper.outerHeight(), 7230 top: wrapper.css("top"), 7231 left: wrapper.css("left") 7232 }).insertAfter( wrapper ); 7233 wrapper.remove(); 7234 } 7235 7236 this.originalElement.css("resize", this.originalResizeStyle); 7237 _destroy(this.originalElement); 7238 7239 return this; 7240 }, 7241 7242 _mouseCapture: function(event) { 7243 var i, handle, 7244 capture = false; 7245 7246 for (i in this.handles) { 7247 handle = $(this.handles[i])[0]; 7248 if (handle === event.target || $.contains(handle, event.target)) { 7249 capture = true; 7250 } 7251 } 7252 7253 return !this.options.disabled && capture; 7254 }, 7255 7256 _mouseStart: function(event) { 7257 7258 var curleft, curtop, cursor, 7259 o = this.options, 7260 el = this.element; 7261 7262 this.resizing = true; 7263 7264 this._renderProxy(); 7265 7266 curleft = this._num(this.helper.css("left")); 7267 curtop = this._num(this.helper.css("top")); 7268 7269 if (o.containment) { 7270 curleft += $(o.containment).scrollLeft() || 0; 7271 curtop += $(o.containment).scrollTop() || 0; 7272 } 7273 7274 this.offset = this.helper.offset(); 7275 this.position = { left: curleft, top: curtop }; 7276 7277 this.size = this._helper ? { 7278 width: this.helper.width(), 7279 height: this.helper.height() 7280 } : { 7281 width: el.width(), 7282 height: el.height() 7283 }; 7284 7285 this.originalSize = this._helper ? { 7286 width: el.outerWidth(), 7287 height: el.outerHeight() 7288 } : { 7289 width: el.width(), 7290 height: el.height() 7291 }; 7292 7293 this.sizeDiff = { 7294 width: el.outerWidth() - el.width(), 7295 height: el.outerHeight() - el.height() 7296 }; 7297 7298 this.originalPosition = { left: curleft, top: curtop }; 7299 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 7300 7301 this.aspectRatio = (typeof o.aspectRatio === "number") ? 7302 o.aspectRatio : 7303 ((this.originalSize.width / this.originalSize.height) || 1); 7304 7305 cursor = $(".ui-resizable-" + this.axis).css("cursor"); 7306 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); 7307 7308 el.addClass("ui-resizable-resizing"); 7309 this._propagate("start", event); 7310 return true; 7311 }, 7312 7313 _mouseDrag: function(event) { 7314 7315 var data, props, 7316 smp = this.originalMousePosition, 7317 a = this.axis, 7318 dx = (event.pageX - smp.left) || 0, 7319 dy = (event.pageY - smp.top) || 0, 7320 trigger = this._change[a]; 7321 7322 this._updatePrevProperties(); 7323 7324 if (!trigger) { 7325 return false; 7326 } 7327 7328 data = trigger.apply(this, [ event, dx, dy ]); 7329 7330 this._updateVirtualBoundaries(event.shiftKey); 7331 if (this._aspectRatio || event.shiftKey) { 7332 data = this._updateRatio(data, event); 7333 } 7334 7335 data = this._respectSize(data, event); 7336 7337 this._updateCache(data); 7338 7339 this._propagate("resize", event); 7340 7341 props = this._applyChanges(); 7342 7343 if ( !this._helper && this._proportionallyResizeElements.length ) { 7344 this._proportionallyResize(); 7345 } 7346 7347 if ( !$.isEmptyObject( props ) ) { 7348 this._updatePrevProperties(); 7349 this._trigger( "resize", event, this.ui() ); 7350 this._applyChanges(); 7351 } 7352 7353 return false; 7354 }, 7355 7356 _mouseStop: function(event) { 7357 7358 this.resizing = false; 7359 var pr, ista, soffseth, soffsetw, s, left, top, 7360 o = this.options, that = this; 7361 7362 if (this._helper) { 7363 7364 pr = this._proportionallyResizeElements; 7365 ista = pr.length && (/textarea/i).test(pr[0].nodeName); 7366 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height; 7367 soffsetw = ista ? 0 : that.sizeDiff.width; 7368 7369 s = { 7370 width: (that.helper.width() - soffsetw), 7371 height: (that.helper.height() - soffseth) 7372 }; 7373 left = (parseInt(that.element.css("left"), 10) + 7374 (that.position.left - that.originalPosition.left)) || null; 7375 top = (parseInt(that.element.css("top"), 10) + 7376 (that.position.top - that.originalPosition.top)) || null; 7377 7378 if (!o.animate) { 7379 this.element.css($.extend(s, { top: top, left: left })); 7380 } 7381 7382 that.helper.height(that.size.height); 7383 that.helper.width(that.size.width); 7384 7385 if (this._helper && !o.animate) { 7386 this._proportionallyResize(); 7387 } 7388 } 7389 7390 $("body").css("cursor", "auto"); 7391 7392 this.element.removeClass("ui-resizable-resizing"); 7393 7394 this._propagate("stop", event); 7395 7396 if (this._helper) { 7397 this.helper.remove(); 7398 } 7399 7400 return false; 7401 7402 }, 7403 7404 _updatePrevProperties: function() { 7405 this.prevPosition = { 7406 top: this.position.top, 7407 left: this.position.left 7408 }; 7409 this.prevSize = { 7410 width: this.size.width, 7411 height: this.size.height 7412 }; 7413 }, 7414 7415 _applyChanges: function() { 7416 var props = {}; 7417 7418 if ( this.position.top !== this.prevPosition.top ) { 7419 props.top = this.position.top + "px"; 7420 } 7421 if ( this.position.left !== this.prevPosition.left ) { 7422 props.left = this.position.left + "px"; 7423 } 7424 if ( this.size.width !== this.prevSize.width ) { 7425 props.width = this.size.width + "px"; 7426 } 7427 if ( this.size.height !== this.prevSize.height ) { 7428 props.height = this.size.height + "px"; 7429 } 7430 7431 this.helper.css( props ); 7432 7433 return props; 7434 }, 7435 7436 _updateVirtualBoundaries: function(forceAspectRatio) { 7437 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, 7438 o = this.options; 7439 7440 b = { 7441 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0, 7442 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity, 7443 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0, 7444 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity 7445 }; 7446 7447 if (this._aspectRatio || forceAspectRatio) { 7448 pMinWidth = b.minHeight * this.aspectRatio; 7449 pMinHeight = b.minWidth / this.aspectRatio; 7450 pMaxWidth = b.maxHeight * this.aspectRatio; 7451 pMaxHeight = b.maxWidth / this.aspectRatio; 7452 7453 if (pMinWidth > b.minWidth) { 7454 b.minWidth = pMinWidth; 7455 } 7456 if (pMinHeight > b.minHeight) { 7457 b.minHeight = pMinHeight; 7458 } 7459 if (pMaxWidth < b.maxWidth) { 7460 b.maxWidth = pMaxWidth; 7461 } 7462 if (pMaxHeight < b.maxHeight) { 7463 b.maxHeight = pMaxHeight; 7464 } 7465 } 7466 this._vBoundaries = b; 7467 }, 7468 7469 _updateCache: function(data) { 7470 this.offset = this.helper.offset(); 7471 if (this._isNumber(data.left)) { 7472 this.position.left = data.left; 7473 } 7474 if (this._isNumber(data.top)) { 7475 this.position.top = data.top; 7476 } 7477 if (this._isNumber(data.height)) { 7478 this.size.height = data.height; 7479 } 7480 if (this._isNumber(data.width)) { 7481 this.size.width = data.width; 7482 } 7483 }, 7484 7485 _updateRatio: function( data ) { 7486 7487 var cpos = this.position, 7488 csize = this.size, 7489 a = this.axis; 7490 7491 if (this._isNumber(data.height)) { 7492 data.width = (data.height * this.aspectRatio); 7493 } else if (this._isNumber(data.width)) { 7494 data.height = (data.width / this.aspectRatio); 7495 } 7496 7497 if (a === "sw") { 7498 data.left = cpos.left + (csize.width - data.width); 7499 data.top = null; 7500 } 7501 if (a === "nw") { 7502 data.top = cpos.top + (csize.height - data.height); 7503 data.left = cpos.left + (csize.width - data.width); 7504 } 7505 7506 return data; 7507 }, 7508 7509 _respectSize: function( data ) { 7510 7511 var o = this._vBoundaries, 7512 a = this.axis, 7513 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), 7514 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), 7515 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width), 7516 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height), 7517 dw = this.originalPosition.left + this.originalSize.width, 7518 dh = this.position.top + this.size.height, 7519 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); 7520 if (isminw) { 7521 data.width = o.minWidth; 7522 } 7523 if (isminh) { 7524 data.height = o.minHeight; 7525 } 7526 if (ismaxw) { 7527 data.width = o.maxWidth; 7528 } 7529 if (ismaxh) { 7530 data.height = o.maxHeight; 7531 } 7532 7533 if (isminw && cw) { 7534 data.left = dw - o.minWidth; 7535 } 7536 if (ismaxw && cw) { 7537 data.left = dw - o.maxWidth; 7538 } 7539 if (isminh && ch) { 7540 data.top = dh - o.minHeight; 7541 } 7542 if (ismaxh && ch) { 7543 data.top = dh - o.maxHeight; 7544 } 7545 7546 // Fixing jump error on top/left - bug #2330 7547 if (!data.width && !data.height && !data.left && data.top) { 7548 data.top = null; 7549 } else if (!data.width && !data.height && !data.top && data.left) { 7550 data.left = null; 7551 } 7552 7553 return data; 7554 }, 7555 7556 _getPaddingPlusBorderDimensions: function( element ) { 7557 var i = 0, 7558 widths = [], 7559 borders = [ 7560 element.css( "borderTopWidth" ), 7561 element.css( "borderRightWidth" ), 7562 element.css( "borderBottomWidth" ), 7563 element.css( "borderLeftWidth" ) 7564 ], 7565 paddings = [ 7566 element.css( "paddingTop" ), 7567 element.css( "paddingRight" ), 7568 element.css( "paddingBottom" ), 7569 element.css( "paddingLeft" ) 7570 ]; 7571 7572 for ( ; i < 4; i++ ) { 7573 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 ); 7574 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 ); 7575 } 7576 7577 return { 7578 height: widths[ 0 ] + widths[ 2 ], 7579 width: widths[ 1 ] + widths[ 3 ] 7580 }; 7581 }, 7582 7583 _proportionallyResize: function() { 7584 7585 if (!this._proportionallyResizeElements.length) { 7586 return; 7587 } 7588 7589 var prel, 7590 i = 0, 7591 element = this.helper || this.element; 7592 7593 for ( ; i < this._proportionallyResizeElements.length; i++) { 7594 7595 prel = this._proportionallyResizeElements[i]; 7596 7597 // TODO: Seems like a bug to cache this.outerDimensions 7598 // considering that we are in a loop. 7599 if (!this.outerDimensions) { 7600 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); 7601 } 7602 7603 prel.css({ 7604 height: (element.height() - this.outerDimensions.height) || 0, 7605 width: (element.width() - this.outerDimensions.width) || 0 7606 }); 7607 7608 } 7609 7610 }, 7611 7612 _renderProxy: function() { 7613 7614 var el = this.element, o = this.options; 7615 this.elementOffset = el.offset(); 7616 7617 if (this._helper) { 7618 7619 this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); 7620 7621 this.helper.addClass(this._helper).css({ 7622 width: this.element.outerWidth() - 1, 7623 height: this.element.outerHeight() - 1, 7624 position: "absolute", 7625 left: this.elementOffset.left + "px", 7626 top: this.elementOffset.top + "px", 7627 zIndex: ++o.zIndex //TODO: Don't modify option 7628 }); 7629 7630 this.helper 7631 .appendTo("body") 7632 .disableSelection(); 7633 7634 } else { 7635 this.helper = this.element; 7636 } 7637 7638 }, 7639 7640 _change: { 7641 e: function(event, dx) { 7642 return { width: this.originalSize.width + dx }; 7643 }, 7644 w: function(event, dx) { 7645 var cs = this.originalSize, sp = this.originalPosition; 7646 return { left: sp.left + dx, width: cs.width - dx }; 7647 }, 7648 n: function(event, dx, dy) { 7649 var cs = this.originalSize, sp = this.originalPosition; 7650 return { top: sp.top + dy, height: cs.height - dy }; 7651 }, 7652 s: function(event, dx, dy) { 7653 return { height: this.originalSize.height + dy }; 7654 }, 7655 se: function(event, dx, dy) { 7656 return $.extend(this._change.s.apply(this, arguments), 7657 this._change.e.apply(this, [ event, dx, dy ])); 7658 }, 7659 sw: function(event, dx, dy) { 7660 return $.extend(this._change.s.apply(this, arguments), 7661 this._change.w.apply(this, [ event, dx, dy ])); 7662 }, 7663 ne: function(event, dx, dy) { 7664 return $.extend(this._change.n.apply(this, arguments), 7665 this._change.e.apply(this, [ event, dx, dy ])); 7666 }, 7667 nw: function(event, dx, dy) { 7668 return $.extend(this._change.n.apply(this, arguments), 7669 this._change.w.apply(this, [ event, dx, dy ])); 7670 } 7671 }, 7672 7673 _propagate: function(n, event) { 7674 $.ui.plugin.call(this, n, [ event, this.ui() ]); 7675 (n !== "resize" && this._trigger(n, event, this.ui())); 7676 }, 7677 7678 plugins: {}, 7679 7680 ui: function() { 7681 return { 7682 originalElement: this.originalElement, 7683 element: this.element, 7684 helper: this.helper, 7685 position: this.position, 7686 size: this.size, 7687 originalSize: this.originalSize, 7688 originalPosition: this.originalPosition 7689 }; 7690 } 7691 7692 }); 7693 7694 /* 7695 * Resizable Extensions 7696 */ 7697 7698 $.ui.plugin.add("resizable", "animate", { 7699 7700 stop: function( event ) { 7701 var that = $(this).resizable( "instance" ), 7702 o = that.options, 7703 pr = that._proportionallyResizeElements, 7704 ista = pr.length && (/textarea/i).test(pr[0].nodeName), 7705 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height, 7706 soffsetw = ista ? 0 : that.sizeDiff.width, 7707 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, 7708 left = (parseInt(that.element.css("left"), 10) + 7709 (that.position.left - that.originalPosition.left)) || null, 7710 top = (parseInt(that.element.css("top"), 10) + 7711 (that.position.top - that.originalPosition.top)) || null; 7712 7713 that.element.animate( 7714 $.extend(style, top && left ? { top: top, left: left } : {}), { 7715 duration: o.animateDuration, 7716 easing: o.animateEasing, 7717 step: function() { 7718 7719 var data = { 7720 width: parseInt(that.element.css("width"), 10), 7721 height: parseInt(that.element.css("height"), 10), 7722 top: parseInt(that.element.css("top"), 10), 7723 left: parseInt(that.element.css("left"), 10) 7724 }; 7725 7726 if (pr && pr.length) { 7727 $(pr[0]).css({ width: data.width, height: data.height }); 7728 } 7729 7730 // propagating resize, and updating values for each animation step 7731 that._updateCache(data); 7732 that._propagate("resize", event); 7733 7734 } 7735 } 7736 ); 7737 } 7738 7739 }); 7740 7741 $.ui.plugin.add( "resizable", "containment", { 7742 7743 start: function() { 7744 var element, p, co, ch, cw, width, height, 7745 that = $( this ).resizable( "instance" ), 7746 o = that.options, 7747 el = that.element, 7748 oc = o.containment, 7749 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; 7750 7751 if ( !ce ) { 7752 return; 7753 } 7754 7755 that.containerElement = $( ce ); 7756 7757 if ( /document/.test( oc ) || oc === document ) { 7758 that.containerOffset = { 7759 left: 0, 7760 top: 0 7761 }; 7762 that.containerPosition = { 7763 left: 0, 7764 top: 0 7765 }; 7766 7767 that.parentData = { 7768 element: $( document ), 7769 left: 0, 7770 top: 0, 7771 width: $( document ).width(), 7772 height: $( document ).height() || document.body.parentNode.scrollHeight 7773 }; 7774 } else { 7775 element = $( ce ); 7776 p = []; 7777 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) { 7778 p[ i ] = that._num( element.css( "padding" + name ) ); 7779 }); 7780 7781 that.containerOffset = element.offset(); 7782 that.containerPosition = element.position(); 7783 that.containerSize = { 7784 height: ( element.innerHeight() - p[ 3 ] ), 7785 width: ( element.innerWidth() - p[ 1 ] ) 7786 }; 7787 7788 co = that.containerOffset; 7789 ch = that.containerSize.height; 7790 cw = that.containerSize.width; 7791 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw ); 7792 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ; 7793 7794 that.parentData = { 7795 element: ce, 7796 left: co.left, 7797 top: co.top, 7798 width: width, 7799 height: height 7800 }; 7801 } 7802 }, 7803 7804 resize: function( event ) { 7805 var woset, hoset, isParent, isOffsetRelative, 7806 that = $( this ).resizable( "instance" ), 7807 o = that.options, 7808 co = that.containerOffset, 7809 cp = that.position, 7810 pRatio = that._aspectRatio || event.shiftKey, 7811 cop = { 7812 top: 0, 7813 left: 0 7814 }, 7815 ce = that.containerElement, 7816 continueResize = true; 7817 7818 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { 7819 cop = co; 7820 } 7821 7822 if ( cp.left < ( that._helper ? co.left : 0 ) ) { 7823 that.size.width = that.size.width + 7824 ( that._helper ? 7825 ( that.position.left - co.left ) : 7826 ( that.position.left - cop.left ) ); 7827 7828 if ( pRatio ) { 7829 that.size.height = that.size.width / that.aspectRatio; 7830 continueResize = false; 7831 } 7832 that.position.left = o.helper ? co.left : 0; 7833 } 7834 7835 if ( cp.top < ( that._helper ? co.top : 0 ) ) { 7836 that.size.height = that.size.height + 7837 ( that._helper ? 7838 ( that.position.top - co.top ) : 7839 that.position.top ); 7840 7841 if ( pRatio ) { 7842 that.size.width = that.size.height * that.aspectRatio; 7843 continueResize = false; 7844 } 7845 that.position.top = that._helper ? co.top : 0; 7846 } 7847 7848 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); 7849 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); 7850 7851 if ( isParent && isOffsetRelative ) { 7852 that.offset.left = that.parentData.left + that.position.left; 7853 that.offset.top = that.parentData.top + that.position.top; 7854 } else { 7855 that.offset.left = that.element.offset().left; 7856 that.offset.top = that.element.offset().top; 7857 } 7858 7859 woset = Math.abs( that.sizeDiff.width + 7860 (that._helper ? 7861 that.offset.left - cop.left : 7862 (that.offset.left - co.left)) ); 7863 7864 hoset = Math.abs( that.sizeDiff.height + 7865 (that._helper ? 7866 that.offset.top - cop.top : 7867 (that.offset.top - co.top)) ); 7868 7869 if ( woset + that.size.width >= that.parentData.width ) { 7870 that.size.width = that.parentData.width - woset; 7871 if ( pRatio ) { 7872 that.size.height = that.size.width / that.aspectRatio; 7873 continueResize = false; 7874 } 7875 } 7876 7877 if ( hoset + that.size.height >= that.parentData.height ) { 7878 that.size.height = that.parentData.height - hoset; 7879 if ( pRatio ) { 7880 that.size.width = that.size.height * that.aspectRatio; 7881 continueResize = false; 7882 } 7883 } 7884 7885 if ( !continueResize ) { 7886 that.position.left = that.prevPosition.left; 7887 that.position.top = that.prevPosition.top; 7888 that.size.width = that.prevSize.width; 7889 that.size.height = that.prevSize.height; 7890 } 7891 }, 7892 7893 stop: function() { 7894 var that = $( this ).resizable( "instance" ), 7895 o = that.options, 7896 co = that.containerOffset, 7897 cop = that.containerPosition, 7898 ce = that.containerElement, 7899 helper = $( that.helper ), 7900 ho = helper.offset(), 7901 w = helper.outerWidth() - that.sizeDiff.width, 7902 h = helper.outerHeight() - that.sizeDiff.height; 7903 7904 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { 7905 $( this ).css({ 7906 left: ho.left - cop.left - co.left, 7907 width: w, 7908 height: h 7909 }); 7910 } 7911 7912 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { 7913 $( this ).css({ 7914 left: ho.left - cop.left - co.left, 7915 width: w, 7916 height: h 7917 }); 7918 } 7919 } 7920 }); 7921 7922 $.ui.plugin.add("resizable", "alsoResize", { 7923 7924 start: function() { 7925 var that = $(this).resizable( "instance" ), 7926 o = that.options; 7927 7928 $(o.alsoResize).each(function() { 7929 var el = $(this); 7930 el.data("ui-resizable-alsoresize", { 7931 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), 7932 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) 7933 }); 7934 }); 7935 }, 7936 7937 resize: function(event, ui) { 7938 var that = $(this).resizable( "instance" ), 7939 o = that.options, 7940 os = that.originalSize, 7941 op = that.originalPosition, 7942 delta = { 7943 height: (that.size.height - os.height) || 0, 7944 width: (that.size.width - os.width) || 0, 7945 top: (that.position.top - op.top) || 0, 7946 left: (that.position.left - op.left) || 0 7947 }; 7948 7949 $(o.alsoResize).each(function() { 7950 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, 7951 css = el.parents(ui.originalElement[0]).length ? 7952 [ "width", "height" ] : 7953 [ "width", "height", "top", "left" ]; 7954 7955 $.each(css, function(i, prop) { 7956 var sum = (start[prop] || 0) + (delta[prop] || 0); 7957 if (sum && sum >= 0) { 7958 style[prop] = sum || null; 7959 } 7960 }); 7961 7962 el.css(style); 7963 }); 7964 }, 7965 7966 stop: function() { 7967 $(this).removeData("resizable-alsoresize"); 7968 } 7969 }); 7970 7971 $.ui.plugin.add("resizable", "ghost", { 7972 7973 start: function() { 7974 7975 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size; 7976 7977 that.ghost = that.originalElement.clone(); 7978 that.ghost 7979 .css({ 7980 opacity: 0.25, 7981 display: "block", 7982 position: "relative", 7983 height: cs.height, 7984 width: cs.width, 7985 margin: 0, 7986 left: 0, 7987 top: 0 7988 }) 7989 .addClass("ui-resizable-ghost") 7990 .addClass(typeof o.ghost === "string" ? o.ghost : ""); 7991 7992 that.ghost.appendTo(that.helper); 7993 7994 }, 7995 7996 resize: function() { 7997 var that = $(this).resizable( "instance" ); 7998 if (that.ghost) { 7999 that.ghost.css({ 8000 position: "relative", 8001 height: that.size.height, 8002 width: that.size.width 8003 }); 8004 } 8005 }, 8006 8007 stop: function() { 8008 var that = $(this).resizable( "instance" ); 8009 if (that.ghost && that.helper) { 8010 that.helper.get(0).removeChild(that.ghost.get(0)); 8011 } 8012 } 8013 8014 }); 8015 8016 $.ui.plugin.add("resizable", "grid", { 8017 8018 resize: function() { 8019 var outerDimensions, 8020 that = $(this).resizable( "instance" ), 8021 o = that.options, 8022 cs = that.size, 8023 os = that.originalSize, 8024 op = that.originalPosition, 8025 a = that.axis, 8026 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, 8027 gridX = (grid[0] || 1), 8028 gridY = (grid[1] || 1), 8029 ox = Math.round((cs.width - os.width) / gridX) * gridX, 8030 oy = Math.round((cs.height - os.height) / gridY) * gridY, 8031 newWidth = os.width + ox, 8032 newHeight = os.height + oy, 8033 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), 8034 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), 8035 isMinWidth = o.minWidth && (o.minWidth > newWidth), 8036 isMinHeight = o.minHeight && (o.minHeight > newHeight); 8037 8038 o.grid = grid; 8039 8040 if (isMinWidth) { 8041 newWidth += gridX; 8042 } 8043 if (isMinHeight) { 8044 newHeight += gridY; 8045 } 8046 if (isMaxWidth) { 8047 newWidth -= gridX; 8048 } 8049 if (isMaxHeight) { 8050 newHeight -= gridY; 8051 } 8052 8053 if (/^(se|s|e)$/.test(a)) { 8054 that.size.width = newWidth; 8055 that.size.height = newHeight; 8056 } else if (/^(ne)$/.test(a)) { 8057 that.size.width = newWidth; 8058 that.size.height = newHeight; 8059 that.position.top = op.top - oy; 8060 } else if (/^(sw)$/.test(a)) { 8061 that.size.width = newWidth; 8062 that.size.height = newHeight; 8063 that.position.left = op.left - ox; 8064 } else { 8065 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) { 8066 outerDimensions = that._getPaddingPlusBorderDimensions( this ); 8067 } 8068 8069 if ( newHeight - gridY > 0 ) { 8070 that.size.height = newHeight; 8071 that.position.top = op.top - oy; 8072 } else { 8073 newHeight = gridY - outerDimensions.height; 8074 that.size.height = newHeight; 8075 that.position.top = op.top + os.height - newHeight; 8076 } 8077 if ( newWidth - gridX > 0 ) { 8078 that.size.width = newWidth; 8079 that.position.left = op.left - ox; 8080 } else { 8081 newWidth = gridX - outerDimensions.width; 8082 that.size.width = newWidth; 8083 that.position.left = op.left + os.width - newWidth; 8084 } 8085 } 8086 } 8087 8088 }); 8089 8090 var resizable = $.ui.resizable; 8091 8092 8093 /*! 8094 * jQuery UI Dialog 1.11.4 8095 * http://jqueryui.com 8096 * 8097 * Copyright jQuery Foundation and other contributors 8098 * Released under the MIT license. 8099 * http://jquery.org/license 8100 * 8101 * http://api.jqueryui.com/dialog/ 8102 */ 8103 8104 8105 var dialog = $.widget( "ui.dialog", { 8106 version: "1.11.4", 8107 options: { 8108 appendTo: "body", 8109 autoOpen: true, 8110 buttons: [], 8111 closeOnEscape: true, 8112 closeText: "Close", 8113 dialogClass: "", 8114 draggable: true, 8115 hide: null, 8116 height: "auto", 8117 maxHeight: null, 8118 maxWidth: null, 8119 minHeight: 150, 8120 minWidth: 150, 8121 modal: false, 8122 position: { 8123 my: "center", 8124 at: "center", 8125 of: window, 8126 collision: "fit", 8127 // Ensure the titlebar is always visible 8128 using: function( pos ) { 8129 var topOffset = $( this ).css( pos ).offset().top; 8130 if ( topOffset < 0 ) { 8131 $( this ).css( "top", pos.top - topOffset ); 8132 } 8133 } 8134 }, 8135 resizable: true, 8136 show: null, 8137 title: null, 8138 width: 300, 8139 8140 // callbacks 8141 beforeClose: null, 8142 close: null, 8143 drag: null, 8144 dragStart: null, 8145 dragStop: null, 8146 focus: null, 8147 open: null, 8148 resize: null, 8149 resizeStart: null, 8150 resizeStop: null 8151 }, 8152 8153 sizeRelatedOptions: { 8154 buttons: true, 8155 height: true, 8156 maxHeight: true, 8157 maxWidth: true, 8158 minHeight: true, 8159 minWidth: true, 8160 width: true 8161 }, 8162 8163 resizableRelatedOptions: { 8164 maxHeight: true, 8165 maxWidth: true, 8166 minHeight: true, 8167 minWidth: true 8168 }, 8169 8170 _create: function() { 8171 this.originalCss = { 8172 display: this.element[ 0 ].style.display, 8173 width: this.element[ 0 ].style.width, 8174 minHeight: this.element[ 0 ].style.minHeight, 8175 maxHeight: this.element[ 0 ].style.maxHeight, 8176 height: this.element[ 0 ].style.height 8177 }; 8178 this.originalPosition = { 8179 parent: this.element.parent(), 8180 index: this.element.parent().children().index( this.element ) 8181 }; 8182 this.originalTitle = this.element.attr( "title" ); 8183 this.options.title = this.options.title || this.originalTitle; 8184 8185 this._createWrapper(); 8186 8187 this.element 8188 .show() 8189 .removeAttr( "title" ) 8190 .addClass( "ui-dialog-content ui-widget-content" ) 8191 .appendTo( this.uiDialog ); 8192 8193 this._createTitlebar(); 8194 this._createButtonPane(); 8195 8196 if ( this.options.draggable && $.fn.draggable ) { 8197 this._makeDraggable(); 8198 } 8199 if ( this.options.resizable && $.fn.resizable ) { 8200 this._makeResizable(); 8201 } 8202 8203 this._isOpen = false; 8204 8205 this._trackFocus(); 8206 }, 8207 8208 _init: function() { 8209 if ( this.options.autoOpen ) { 8210 this.open(); 8211 } 8212 }, 8213 8214 _appendTo: function() { 8215 var element = this.options.appendTo; 8216 if ( element && (element.jquery || element.nodeType) ) { 8217 return $( element ); 8218 } 8219 return this.document.find( element || "body" ).eq( 0 ); 8220 }, 8221 8222 _destroy: function() { 8223 var next, 8224 originalPosition = this.originalPosition; 8225 8226 this._untrackInstance(); 8227 this._destroyOverlay(); 8228 8229 this.element 8230 .removeUniqueId() 8231 .removeClass( "ui-dialog-content ui-widget-content" ) 8232 .css( this.originalCss ) 8233 // Without detaching first, the following becomes really slow 8234 .detach(); 8235 8236 this.uiDialog.stop( true, true ).remove(); 8237 8238 if ( this.originalTitle ) { 8239 this.element.attr( "title", this.originalTitle ); 8240 } 8241 8242 next = originalPosition.parent.children().eq( originalPosition.index ); 8243 // Don't try to place the dialog next to itself (#8613) 8244 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { 8245 next.before( this.element ); 8246 } else { 8247 originalPosition.parent.append( this.element ); 8248 } 8249 }, 8250 8251 widget: function() { 8252 return this.uiDialog; 8253 }, 8254 8255 disable: $.noop, 8256 enable: $.noop, 8257 8258 close: function( event ) { 8259 var activeElement, 8260 that = this; 8261 8262 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { 8263 return; 8264 } 8265 8266 this._isOpen = false; 8267 this._focusedElement = null; 8268 this._destroyOverlay(); 8269 this._untrackInstance(); 8270 8271 if ( !this.opener.filter( ":focusable" ).focus().length ) { 8272 8273 // support: IE9 8274 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 8275 try { 8276 activeElement = this.document[ 0 ].activeElement; 8277 8278 // Support: IE9, IE10 8279 // If the <body> is blurred, IE will switch windows, see #4520 8280 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) { 8281 8282 // Hiding a focused element doesn't trigger blur in WebKit 8283 // so in case we have nothing to focus on, explicitly blur the active element 8284 // https://bugs.webkit.org/show_bug.cgi?id=47182 8285 $( activeElement ).blur(); 8286 } 8287 } catch ( error ) {} 8288 } 8289 8290 this._hide( this.uiDialog, this.options.hide, function() { 8291 that._trigger( "close", event ); 8292 }); 8293 }, 8294 8295 isOpen: function() { 8296 return this._isOpen; 8297 }, 8298 8299 moveToTop: function() { 8300 this._moveToTop(); 8301 }, 8302 8303 _moveToTop: function( event, silent ) { 8304 var moved = false, 8305 zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map(function() { 8306 return +$( this ).css( "z-index" ); 8307 }).get(), 8308 zIndexMax = Math.max.apply( null, zIndices ); 8309 8310 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { 8311 this.uiDialog.css( "z-index", zIndexMax + 1 ); 8312 moved = true; 8313 } 8314 8315 if ( moved && !silent ) { 8316 this._trigger( "focus", event ); 8317 } 8318 return moved; 8319 }, 8320 8321 open: function() { 8322 var that = this; 8323 if ( this._isOpen ) { 8324 if ( this._moveToTop() ) { 8325 this._focusTabbable(); 8326 } 8327 return; 8328 } 8329 8330 this._isOpen = true; 8331 this.opener = $( this.document[ 0 ].activeElement ); 8332 8333 this._size(); 8334 this._position(); 8335 this._createOverlay(); 8336 this._moveToTop( null, true ); 8337 8338 // Ensure the overlay is moved to the top with the dialog, but only when 8339 // opening. The overlay shouldn't move after the dialog is open so that 8340 // modeless dialogs opened after the modal dialog stack properly. 8341 if ( this.overlay ) { 8342 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); 8343 } 8344 8345 this._show( this.uiDialog, this.options.show, function() { 8346 that._focusTabbable(); 8347 that._trigger( "focus" ); 8348 }); 8349 8350 // Track the dialog immediately upon openening in case a focus event 8351 // somehow occurs outside of the dialog before an element inside the 8352 // dialog is focused (#10152) 8353 this._makeFocusTarget(); 8354 8355 this._trigger( "open" ); 8356 }, 8357 8358 _focusTabbable: function() { 8359 // Set focus to the first match: 8360 // 1. An element that was focused previously 8361 // 2. First element inside the dialog matching [autofocus] 8362 // 3. Tabbable element inside the content element 8363 // 4. Tabbable element inside the buttonpane 8364 // 5. The close button 8365 // 6. The dialog itself 8366 var hasFocus = this._focusedElement; 8367 if ( !hasFocus ) { 8368 hasFocus = this.element.find( "[autofocus]" ); 8369 } 8370 if ( !hasFocus.length ) { 8371 hasFocus = this.element.find( ":tabbable" ); 8372 } 8373 if ( !hasFocus.length ) { 8374 hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); 8375 } 8376 if ( !hasFocus.length ) { 8377 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); 8378 } 8379 if ( !hasFocus.length ) { 8380 hasFocus = this.uiDialog; 8381 } 8382 hasFocus.eq( 0 ).focus(); 8383 }, 8384 8385 _keepFocus: function( event ) { 8386 function checkFocus() { 8387 var activeElement = this.document[0].activeElement, 8388 isActive = this.uiDialog[0] === activeElement || 8389 $.contains( this.uiDialog[0], activeElement ); 8390 if ( !isActive ) { 8391 this._focusTabbable(); 8392 } 8393 } 8394 event.preventDefault(); 8395 checkFocus.call( this ); 8396 // support: IE 8397 // IE <= 8 doesn't prevent moving focus even with event.preventDefault() 8398 // so we check again later 8399 this._delay( checkFocus ); 8400 }, 8401 8402 _createWrapper: function() { 8403 this.uiDialog = $("<div>") 8404 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + 8405 this.options.dialogClass ) 8406 .hide() 8407 .attr({ 8408 // Setting tabIndex makes the div focusable 8409 tabIndex: -1, 8410 role: "dialog" 8411 }) 8412 .appendTo( this._appendTo() ); 8413 8414 this._on( this.uiDialog, { 8415 keydown: function( event ) { 8416 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 8417 event.keyCode === $.ui.keyCode.ESCAPE ) { 8418 event.preventDefault(); 8419 this.close( event ); 8420 return; 8421 } 8422 8423 // prevent tabbing out of dialogs 8424 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { 8425 return; 8426 } 8427 var tabbables = this.uiDialog.find( ":tabbable" ), 8428 first = tabbables.filter( ":first" ), 8429 last = tabbables.filter( ":last" ); 8430 8431 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { 8432 this._delay(function() { 8433 first.focus(); 8434 }); 8435 event.preventDefault(); 8436 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { 8437 this._delay(function() { 8438 last.focus(); 8439 }); 8440 event.preventDefault(); 8441 } 8442 }, 8443 mousedown: function( event ) { 8444 if ( this._moveToTop( event ) ) { 8445 this._focusTabbable(); 8446 } 8447 } 8448 }); 8449 8450 // We assume that any existing aria-describedby attribute means 8451 // that the dialog content is marked up properly 8452 // otherwise we brute force the content as the description 8453 if ( !this.element.find( "[aria-describedby]" ).length ) { 8454 this.uiDialog.attr({ 8455 "aria-describedby": this.element.uniqueId().attr( "id" ) 8456 }); 8457 } 8458 }, 8459 8460 _createTitlebar: function() { 8461 var uiDialogTitle; 8462 8463 this.uiDialogTitlebar = $( "<div>" ) 8464 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" ) 8465 .prependTo( this.uiDialog ); 8466 this._on( this.uiDialogTitlebar, { 8467 mousedown: function( event ) { 8468 // Don't prevent click on close button (#8838) 8469 // Focusing a dialog that is partially scrolled out of view 8470 // causes the browser to scroll it into view, preventing the click event 8471 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { 8472 // Dialog isn't getting focus when dragging (#8063) 8473 this.uiDialog.focus(); 8474 } 8475 } 8476 }); 8477 8478 // support: IE 8479 // Use type="button" to prevent enter keypresses in textboxes from closing the 8480 // dialog in IE (#9312) 8481 this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) 8482 .button({ 8483 label: this.options.closeText, 8484 icons: { 8485 primary: "ui-icon-closethick" 8486 }, 8487 text: false 8488 }) 8489 .addClass( "ui-dialog-titlebar-close" ) 8490 .appendTo( this.uiDialogTitlebar ); 8491 this._on( this.uiDialogTitlebarClose, { 8492 click: function( event ) { 8493 event.preventDefault(); 8494 this.close( event ); 8495 } 8496 }); 8497 8498 uiDialogTitle = $( "<span>" ) 8499 .uniqueId() 8500 .addClass( "ui-dialog-title" ) 8501 .prependTo( this.uiDialogTitlebar ); 8502 this._title( uiDialogTitle ); 8503 8504 this.uiDialog.attr({ 8505 "aria-labelledby": uiDialogTitle.attr( "id" ) 8506 }); 8507 }, 8508 8509 _title: function( title ) { 8510 if ( !this.options.title ) { 8511 title.html( " " ); 8512 } 8513 title.text( this.options.title ); 8514 }, 8515 8516 _createButtonPane: function() { 8517 this.uiDialogButtonPane = $( "<div>" ) 8518 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); 8519 8520 this.uiButtonSet = $( "<div>" ) 8521 .addClass( "ui-dialog-buttonset" ) 8522 .appendTo( this.uiDialogButtonPane ); 8523 8524 this._createButtons(); 8525 }, 8526 8527 _createButtons: function() { 8528 var that = this, 8529 buttons = this.options.buttons; 8530 8531 // if we already have a button pane, remove it 8532 this.uiDialogButtonPane.remove(); 8533 this.uiButtonSet.empty(); 8534 8535 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { 8536 this.uiDialog.removeClass( "ui-dialog-buttons" ); 8537 return; 8538 } 8539 8540 $.each( buttons, function( name, props ) { 8541 var click, buttonOptions; 8542 props = $.isFunction( props ) ? 8543 { click: props, text: name } : 8544 props; 8545 // Default to a non-submitting button 8546 props = $.extend( { type: "button" }, props ); 8547 // Change the context for the click callback to be the main element 8548 click = props.click; 8549 props.click = function() { 8550 click.apply( that.element[ 0 ], arguments ); 8551 }; 8552 buttonOptions = { 8553 icons: props.icons, 8554 text: props.showText 8555 }; 8556 delete props.icons; 8557 delete props.showText; 8558 $( "<button></button>", props ) 8559 .button( buttonOptions ) 8560 .appendTo( that.uiButtonSet ); 8561 }); 8562 this.uiDialog.addClass( "ui-dialog-buttons" ); 8563 this.uiDialogButtonPane.appendTo( this.uiDialog ); 8564 }, 8565 8566 _makeDraggable: function() { 8567 var that = this, 8568 options = this.options; 8569 8570 function filteredUi( ui ) { 8571 return { 8572 position: ui.position, 8573 offset: ui.offset 8574 }; 8575 } 8576 8577 this.uiDialog.draggable({ 8578 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", 8579 handle: ".ui-dialog-titlebar", 8580 containment: "document", 8581 start: function( event, ui ) { 8582 $( this ).addClass( "ui-dialog-dragging" ); 8583 that._blockFrames(); 8584 that._trigger( "dragStart", event, filteredUi( ui ) ); 8585 }, 8586 drag: function( event, ui ) { 8587 that._trigger( "drag", event, filteredUi( ui ) ); 8588 }, 8589 stop: function( event, ui ) { 8590 var left = ui.offset.left - that.document.scrollLeft(), 8591 top = ui.offset.top - that.document.scrollTop(); 8592 8593 options.position = { 8594 my: "left top", 8595 at: "left" + (left >= 0 ? "+" : "") + left + " " + 8596 "top" + (top >= 0 ? "+" : "") + top, 8597 of: that.window 8598 }; 8599 $( this ).removeClass( "ui-dialog-dragging" ); 8600 that._unblockFrames(); 8601 that._trigger( "dragStop", event, filteredUi( ui ) ); 8602 } 8603 }); 8604 }, 8605 8606 _makeResizable: function() { 8607 var that = this, 8608 options = this.options, 8609 handles = options.resizable, 8610 // .ui-resizable has position: relative defined in the stylesheet 8611 // but dialogs have to use absolute or fixed positioning 8612 position = this.uiDialog.css("position"), 8613 resizeHandles = typeof handles === "string" ? 8614 handles : 8615 "n,e,s,w,se,sw,ne,nw"; 8616 8617 function filteredUi( ui ) { 8618 return { 8619 originalPosition: ui.originalPosition, 8620 originalSize: ui.originalSize, 8621 position: ui.position, 8622 size: ui.size 8623 }; 8624 } 8625 8626 this.uiDialog.resizable({ 8627 cancel: ".ui-dialog-content", 8628 containment: "document", 8629 alsoResize: this.element, 8630 maxWidth: options.maxWidth, 8631 maxHeight: options.maxHeight, 8632 minWidth: options.minWidth, 8633 minHeight: this._minHeight(), 8634 handles: resizeHandles, 8635 start: function( event, ui ) { 8636 $( this ).addClass( "ui-dialog-resizing" ); 8637 that._blockFrames(); 8638 that._trigger( "resizeStart", event, filteredUi( ui ) ); 8639 }, 8640 resize: function( event, ui ) { 8641 that._trigger( "resize", event, filteredUi( ui ) ); 8642 }, 8643 stop: function( event, ui ) { 8644 var offset = that.uiDialog.offset(), 8645 left = offset.left - that.document.scrollLeft(), 8646 top = offset.top - that.document.scrollTop(); 8647 8648 options.height = that.uiDialog.height(); 8649 options.width = that.uiDialog.width(); 8650 options.position = { 8651 my: "left top", 8652 at: "left" + (left >= 0 ? "+" : "") + left + " " + 8653 "top" + (top >= 0 ? "+" : "") + top, 8654 of: that.window 8655 }; 8656 $( this ).removeClass( "ui-dialog-resizing" ); 8657 that._unblockFrames(); 8658 that._trigger( "resizeStop", event, filteredUi( ui ) ); 8659 } 8660 }) 8661 .css( "position", position ); 8662 }, 8663 8664 _trackFocus: function() { 8665 this._on( this.widget(), { 8666 focusin: function( event ) { 8667 this._makeFocusTarget(); 8668 this._focusedElement = $( event.target ); 8669 } 8670 }); 8671 }, 8672 8673 _makeFocusTarget: function() { 8674 this._untrackInstance(); 8675 this._trackingInstances().unshift( this ); 8676 }, 8677 8678 _untrackInstance: function() { 8679 var instances = this._trackingInstances(), 8680 exists = $.inArray( this, instances ); 8681 if ( exists !== -1 ) { 8682 instances.splice( exists, 1 ); 8683 } 8684 }, 8685 8686 _trackingInstances: function() { 8687 var instances = this.document.data( "ui-dialog-instances" ); 8688 if ( !instances ) { 8689 instances = []; 8690 this.document.data( "ui-dialog-instances", instances ); 8691 } 8692 return instances; 8693 }, 8694 8695 _minHeight: function() { 8696 var options = this.options; 8697 8698 return options.height === "auto" ? 8699 options.minHeight : 8700 Math.min( options.minHeight, options.height ); 8701 }, 8702 8703 _position: function() { 8704 // Need to show the dialog to get the actual offset in the position plugin 8705 var isVisible = this.uiDialog.is( ":visible" ); 8706 if ( !isVisible ) { 8707 this.uiDialog.show(); 8708 } 8709 this.uiDialog.position( this.options.position ); 8710 if ( !isVisible ) { 8711 this.uiDialog.hide(); 8712 } 8713 }, 8714 8715 _setOptions: function( options ) { 8716 var that = this, 8717 resize = false, 8718 resizableOptions = {}; 8719 8720 $.each( options, function( key, value ) { 8721 that._setOption( key, value ); 8722 8723 if ( key in that.sizeRelatedOptions ) { 8724 resize = true; 8725 } 8726 if ( key in that.resizableRelatedOptions ) { 8727 resizableOptions[ key ] = value; 8728 } 8729 }); 8730 8731 if ( resize ) { 8732 this._size(); 8733 this._position(); 8734 } 8735 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 8736 this.uiDialog.resizable( "option", resizableOptions ); 8737 } 8738 }, 8739 8740 _setOption: function( key, value ) { 8741 var isDraggable, isResizable, 8742 uiDialog = this.uiDialog; 8743 8744 if ( key === "dialogClass" ) { 8745 uiDialog 8746 .removeClass( this.options.dialogClass ) 8747 .addClass( value ); 8748 } 8749 8750 if ( key === "disabled" ) { 8751 return; 8752 } 8753 8754 this._super( key, value ); 8755 8756 if ( key === "appendTo" ) { 8757 this.uiDialog.appendTo( this._appendTo() ); 8758 } 8759 8760 if ( key === "buttons" ) { 8761 this._createButtons(); 8762 } 8763 8764 if ( key === "closeText" ) { 8765 this.uiDialogTitlebarClose.button({ 8766 // Ensure that we always pass a string 8767 label: "" + value 8768 }); 8769 } 8770 8771 if ( key === "draggable" ) { 8772 isDraggable = uiDialog.is( ":data(ui-draggable)" ); 8773 if ( isDraggable && !value ) { 8774 uiDialog.draggable( "destroy" ); 8775 } 8776 8777 if ( !isDraggable && value ) { 8778 this._makeDraggable(); 8779 } 8780 } 8781 8782 if ( key === "position" ) { 8783 this._position(); 8784 } 8785 8786 if ( key === "resizable" ) { 8787 // currently resizable, becoming non-resizable 8788 isResizable = uiDialog.is( ":data(ui-resizable)" ); 8789 if ( isResizable && !value ) { 8790 uiDialog.resizable( "destroy" ); 8791 } 8792 8793 // currently resizable, changing handles 8794 if ( isResizable && typeof value === "string" ) { 8795 uiDialog.resizable( "option", "handles", value ); 8796 } 8797 8798 // currently non-resizable, becoming resizable 8799 if ( !isResizable && value !== false ) { 8800 this._makeResizable(); 8801 } 8802 } 8803 8804 if ( key === "title" ) { 8805 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); 8806 } 8807 }, 8808 8809 _size: function() { 8810 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 8811 // divs will both have width and height set, so we need to reset them 8812 var nonContentHeight, minContentHeight, maxContentHeight, 8813 options = this.options; 8814 8815 // Reset content sizing 8816 this.element.show().css({ 8817 width: "auto", 8818 minHeight: 0, 8819 maxHeight: "none", 8820 height: 0 8821 }); 8822 8823 if ( options.minWidth > options.width ) { 8824 options.width = options.minWidth; 8825 } 8826 8827 // reset wrapper sizing 8828 // determine the height of all the non-content elements 8829 nonContentHeight = this.uiDialog.css({ 8830 height: "auto", 8831 width: options.width 8832 }) 8833 .outerHeight(); 8834 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 8835 maxContentHeight = typeof options.maxHeight === "number" ? 8836 Math.max( 0, options.maxHeight - nonContentHeight ) : 8837 "none"; 8838 8839 if ( options.height === "auto" ) { 8840 this.element.css({ 8841 minHeight: minContentHeight, 8842 maxHeight: maxContentHeight, 8843 height: "auto" 8844 }); 8845 } else { 8846 this.element.height( Math.max( 0, options.height - nonContentHeight ) ); 8847 } 8848 8849 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 8850 this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); 8851 } 8852 }, 8853 8854 _blockFrames: function() { 8855 this.iframeBlocks = this.document.find( "iframe" ).map(function() { 8856 var iframe = $( this ); 8857 8858 return $( "<div>" ) 8859 .css({ 8860 position: "absolute", 8861 width: iframe.outerWidth(), 8862 height: iframe.outerHeight() 8863 }) 8864 .appendTo( iframe.parent() ) 8865 .offset( iframe.offset() )[0]; 8866 }); 8867 }, 8868 8869 _unblockFrames: function() { 8870 if ( this.iframeBlocks ) { 8871 this.iframeBlocks.remove(); 8872 delete this.iframeBlocks; 8873 } 8874 }, 8875 8876 _allowInteraction: function( event ) { 8877 if ( $( event.target ).closest( ".ui-dialog" ).length ) { 8878 return true; 8879 } 8880 8881 // TODO: Remove hack when datepicker implements 8882 // the .ui-front logic (#8989) 8883 return !!$( event.target ).closest( ".ui-datepicker" ).length; 8884 }, 8885 8886 _createOverlay: function() { 8887 if ( !this.options.modal ) { 8888 return; 8889 } 8890 8891 // We use a delay in case the overlay is created from an 8892 // event that we're going to be cancelling (#2804) 8893 var isOpening = true; 8894 this._delay(function() { 8895 isOpening = false; 8896 }); 8897 8898 if ( !this.document.data( "ui-dialog-overlays" ) ) { 8899 8900 // Prevent use of anchors and inputs 8901 // Using _on() for an event handler shared across many instances is 8902 // safe because the dialogs stack and must be closed in reverse order 8903 this._on( this.document, { 8904 focusin: function( event ) { 8905 if ( isOpening ) { 8906 return; 8907 } 8908 8909 if ( !this._allowInteraction( event ) ) { 8910 event.preventDefault(); 8911 this._trackingInstances()[ 0 ]._focusTabbable(); 8912 } 8913 } 8914 }); 8915 } 8916 8917 this.overlay = $( "<div>" ) 8918 .addClass( "ui-widget-overlay ui-front" ) 8919 .appendTo( this._appendTo() ); 8920 this._on( this.overlay, { 8921 mousedown: "_keepFocus" 8922 }); 8923 this.document.data( "ui-dialog-overlays", 8924 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 ); 8925 }, 8926 8927 _destroyOverlay: function() { 8928 if ( !this.options.modal ) { 8929 return; 8930 } 8931 8932 if ( this.overlay ) { 8933 var overlays = this.document.data( "ui-dialog-overlays" ) - 1; 8934 8935 if ( !overlays ) { 8936 this.document 8937 .unbind( "focusin" ) 8938 .removeData( "ui-dialog-overlays" ); 8939 } else { 8940 this.document.data( "ui-dialog-overlays", overlays ); 8941 } 8942 8943 this.overlay.remove(); 8944 this.overlay = null; 8945 } 8946 } 8947 }); 8948 8949 8950 /*! 8951 * jQuery UI Droppable 1.11.4 8952 * http://jqueryui.com 8953 * 8954 * Copyright jQuery Foundation and other contributors 8955 * Released under the MIT license. 8956 * http://jquery.org/license 8957 * 8958 * http://api.jqueryui.com/droppable/ 8959 */ 8960 8961 8962 $.widget( "ui.droppable", { 8963 version: "1.11.4", 8964 widgetEventPrefix: "drop", 8965 options: { 8966 accept: "*", 8967 activeClass: false, 8968 addClasses: true, 8969 greedy: false, 8970 hoverClass: false, 8971 scope: "default", 8972 tolerance: "intersect", 8973 8974 // callbacks 8975 activate: null, 8976 deactivate: null, 8977 drop: null, 8978 out: null, 8979 over: null 8980 }, 8981 _create: function() { 8982 8983 var proportions, 8984 o = this.options, 8985 accept = o.accept; 8986 8987 this.isover = false; 8988 this.isout = true; 8989 8990 this.accept = $.isFunction( accept ) ? accept : function( d ) { 8991 return d.is( accept ); 8992 }; 8993 8994 this.proportions = function( /* valueToWrite */ ) { 8995 if ( arguments.length ) { 8996 // Store the droppable's proportions 8997 proportions = arguments[ 0 ]; 8998 } else { 8999 // Retrieve or derive the droppable's proportions 9000 return proportions ? 9001 proportions : 9002 proportions = { 9003 width: this.element[ 0 ].offsetWidth, 9004 height: this.element[ 0 ].offsetHeight 9005 }; 9006 } 9007 }; 9008 9009 this._addToManager( o.scope ); 9010 9011 o.addClasses && this.element.addClass( "ui-droppable" ); 9012 9013 }, 9014 9015 _addToManager: function( scope ) { 9016 // Add the reference and positions to the manager 9017 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; 9018 $.ui.ddmanager.droppables[ scope ].push( this ); 9019 }, 9020 9021 _splice: function( drop ) { 9022 var i = 0; 9023 for ( ; i < drop.length; i++ ) { 9024 if ( drop[ i ] === this ) { 9025 drop.splice( i, 1 ); 9026 } 9027 } 9028 }, 9029 9030 _destroy: function() { 9031 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 9032 9033 this._splice( drop ); 9034 9035 this.element.removeClass( "ui-droppable ui-droppable-disabled" ); 9036 }, 9037 9038 _setOption: function( key, value ) { 9039 9040 if ( key === "accept" ) { 9041 this.accept = $.isFunction( value ) ? value : function( d ) { 9042 return d.is( value ); 9043 }; 9044 } else if ( key === "scope" ) { 9045 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 9046 9047 this._splice( drop ); 9048 this._addToManager( value ); 9049 } 9050 9051 this._super( key, value ); 9052 }, 9053 9054 _activate: function( event ) { 9055 var draggable = $.ui.ddmanager.current; 9056 if ( this.options.activeClass ) { 9057 this.element.addClass( this.options.activeClass ); 9058 } 9059 if ( draggable ){ 9060 this._trigger( "activate", event, this.ui( draggable ) ); 9061 } 9062 }, 9063 9064 _deactivate: function( event ) { 9065 var draggable = $.ui.ddmanager.current; 9066 if ( this.options.activeClass ) { 9067 this.element.removeClass( this.options.activeClass ); 9068 } 9069 if ( draggable ){ 9070 this._trigger( "deactivate", event, this.ui( draggable ) ); 9071 } 9072 }, 9073 9074 _over: function( event ) { 9075 9076 var draggable = $.ui.ddmanager.current; 9077 9078 // Bail if draggable and droppable are same element 9079 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { 9080 return; 9081 } 9082 9083 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 9084 if ( this.options.hoverClass ) { 9085 this.element.addClass( this.options.hoverClass ); 9086 } 9087 this._trigger( "over", event, this.ui( draggable ) ); 9088 } 9089 9090 }, 9091 9092 _out: function( event ) { 9093 9094 var draggable = $.ui.ddmanager.current; 9095 9096 // Bail if draggable and droppable are same element 9097 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { 9098 return; 9099 } 9100 9101 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 9102 if ( this.options.hoverClass ) { 9103 this.element.removeClass( this.options.hoverClass ); 9104 } 9105 this._trigger( "out", event, this.ui( draggable ) ); 9106 } 9107 9108 }, 9109 9110 _drop: function( event, custom ) { 9111 9112 var draggable = custom || $.ui.ddmanager.current, 9113 childrenIntersection = false; 9114 9115 // Bail if draggable and droppable are same element 9116 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { 9117 return false; 9118 } 9119 9120 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() { 9121 var inst = $( this ).droppable( "instance" ); 9122 if ( 9123 inst.options.greedy && 9124 !inst.options.disabled && 9125 inst.options.scope === draggable.options.scope && 9126 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) && 9127 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event ) 9128 ) { childrenIntersection = true; return false; } 9129 }); 9130 if ( childrenIntersection ) { 9131 return false; 9132 } 9133 9134 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 9135 if ( this.options.activeClass ) { 9136 this.element.removeClass( this.options.activeClass ); 9137 } 9138 if ( this.options.hoverClass ) { 9139 this.element.removeClass( this.options.hoverClass ); 9140 } 9141 this._trigger( "drop", event, this.ui( draggable ) ); 9142 return this.element; 9143 } 9144 9145 return false; 9146 9147 }, 9148 9149 ui: function( c ) { 9150 return { 9151 draggable: ( c.currentItem || c.element ), 9152 helper: c.helper, 9153 position: c.position, 9154 offset: c.positionAbs 9155 }; 9156 } 9157 9158 }); 9159 9160 $.ui.intersect = (function() { 9161 function isOverAxis( x, reference, size ) { 9162 return ( x >= reference ) && ( x < ( reference + size ) ); 9163 } 9164 9165 return function( draggable, droppable, toleranceMode, event ) { 9166 9167 if ( !droppable.offset ) { 9168 return false; 9169 } 9170 9171 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left, 9172 y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top, 9173 x2 = x1 + draggable.helperProportions.width, 9174 y2 = y1 + draggable.helperProportions.height, 9175 l = droppable.offset.left, 9176 t = droppable.offset.top, 9177 r = l + droppable.proportions().width, 9178 b = t + droppable.proportions().height; 9179 9180 switch ( toleranceMode ) { 9181 case "fit": 9182 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); 9183 case "intersect": 9184 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half 9185 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half 9186 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half 9187 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half 9188 case "pointer": 9189 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width ); 9190 case "touch": 9191 return ( 9192 ( y1 >= t && y1 <= b ) || // Top edge touching 9193 ( y2 >= t && y2 <= b ) || // Bottom edge touching 9194 ( y1 < t && y2 > b ) // Surrounded vertically 9195 ) && ( 9196 ( x1 >= l && x1 <= r ) || // Left edge touching 9197 ( x2 >= l && x2 <= r ) || // Right edge touching 9198 ( x1 < l && x2 > r ) // Surrounded horizontally 9199 ); 9200 default: 9201 return false; 9202 } 9203 }; 9204 })(); 9205 9206 /* 9207 This manager tracks offsets of draggables and droppables 9208 */ 9209 $.ui.ddmanager = { 9210 current: null, 9211 droppables: { "default": [] }, 9212 prepareOffsets: function( t, event ) { 9213 9214 var i, j, 9215 m = $.ui.ddmanager.droppables[ t.options.scope ] || [], 9216 type = event ? event.type : null, // workaround for #2317 9217 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); 9218 9219 droppablesLoop: for ( i = 0; i < m.length; i++ ) { 9220 9221 // No disabled and non-accepted 9222 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { 9223 continue; 9224 } 9225 9226 // Filter out elements in the current dragged item 9227 for ( j = 0; j < list.length; j++ ) { 9228 if ( list[ j ] === m[ i ].element[ 0 ] ) { 9229 m[ i ].proportions().height = 0; 9230 continue droppablesLoop; 9231 } 9232 } 9233 9234 m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; 9235 if ( !m[ i ].visible ) { 9236 continue; 9237 } 9238 9239 // Activate the droppable if used directly from draggables 9240 if ( type === "mousedown" ) { 9241 m[ i ]._activate.call( m[ i ], event ); 9242 } 9243 9244 m[ i ].offset = m[ i ].element.offset(); 9245 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight }); 9246 9247 } 9248 9249 }, 9250 drop: function( draggable, event ) { 9251 9252 var dropped = false; 9253 // Create a copy of the droppables in case the list changes during the drop (#9116) 9254 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { 9255 9256 if ( !this.options ) { 9257 return; 9258 } 9259 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { 9260 dropped = this._drop.call( this, event ) || dropped; 9261 } 9262 9263 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 9264 this.isout = true; 9265 this.isover = false; 9266 this._deactivate.call( this, event ); 9267 } 9268 9269 }); 9270 return dropped; 9271 9272 }, 9273 dragStart: function( draggable, event ) { 9274 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) 9275 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { 9276 if ( !draggable.options.refreshPositions ) { 9277 $.ui.ddmanager.prepareOffsets( draggable, event ); 9278 } 9279 }); 9280 }, 9281 drag: function( draggable, event ) { 9282 9283 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. 9284 if ( draggable.options.refreshPositions ) { 9285 $.ui.ddmanager.prepareOffsets( draggable, event ); 9286 } 9287 9288 // Run through all droppables and check their positions based on specific tolerance options 9289 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { 9290 9291 if ( this.options.disabled || this.greedyChild || !this.visible ) { 9292 return; 9293 } 9294 9295 var parentInstance, scope, parent, 9296 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), 9297 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null ); 9298 if ( !c ) { 9299 return; 9300 } 9301 9302 if ( this.options.greedy ) { 9303 // find droppable parents with same scope 9304 scope = this.options.scope; 9305 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() { 9306 return $( this ).droppable( "instance" ).options.scope === scope; 9307 }); 9308 9309 if ( parent.length ) { 9310 parentInstance = $( parent[ 0 ] ).droppable( "instance" ); 9311 parentInstance.greedyChild = ( c === "isover" ); 9312 } 9313 } 9314 9315 // we just moved into a greedy child 9316 if ( parentInstance && c === "isover" ) { 9317 parentInstance.isover = false; 9318 parentInstance.isout = true; 9319 parentInstance._out.call( parentInstance, event ); 9320 } 9321 9322 this[ c ] = true; 9323 this[c === "isout" ? "isover" : "isout"] = false; 9324 this[c === "isover" ? "_over" : "_out"].call( this, event ); 9325 9326 // we just moved out of a greedy child 9327 if ( parentInstance && c === "isout" ) { 9328 parentInstance.isout = false; 9329 parentInstance.isover = true; 9330 parentInstance._over.call( parentInstance, event ); 9331 } 9332 }); 9333 9334 }, 9335 dragStop: function( draggable, event ) { 9336 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); 9337 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) 9338 if ( !draggable.options.refreshPositions ) { 9339 $.ui.ddmanager.prepareOffsets( draggable, event ); 9340 } 9341 } 9342 }; 9343 9344 var droppable = $.ui.droppable; 9345 9346 9347 /*! 9348 * jQuery UI Effects 1.11.4 9349 * http://jqueryui.com 9350 * 9351 * Copyright jQuery Foundation and other contributors 9352 * Released under the MIT license. 9353 * http://jquery.org/license 9354 * 9355 * http://api.jqueryui.com/category/effects-core/ 9356 */ 9357 9358 9359 var dataSpace = "ui-effects-", 9360 9361 // Create a local jQuery because jQuery Color relies on it and the 9362 // global may not exist with AMD and a custom build (#10199) 9363 jQuery = $; 9364 9365 $.effects = { 9366 effect: {} 9367 }; 9368 9369 /*! 9370 * jQuery Color Animations v2.1.2 9371 * https://github.com/jquery/jquery-color 9372 * 9373 * Copyright 2014 jQuery Foundation and other contributors 9374 * Released under the MIT license. 9375 * http://jquery.org/license 9376 * 9377 * Date: Wed Jan 16 08:47:09 2013 -0600 9378 */ 9379 (function( jQuery, undefined ) { 9380 9381 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", 9382 9383 // plusequals test for += 100 -= 100 9384 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, 9385 // a set of RE's that can match strings and generate color tuples. 9386 stringParsers = [ { 9387 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 9388 parse: function( execResult ) { 9389 return [ 9390 execResult[ 1 ], 9391 execResult[ 2 ], 9392 execResult[ 3 ], 9393 execResult[ 4 ] 9394 ]; 9395 } 9396 }, { 9397 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 9398 parse: function( execResult ) { 9399 return [ 9400 execResult[ 1 ] * 2.55, 9401 execResult[ 2 ] * 2.55, 9402 execResult[ 3 ] * 2.55, 9403 execResult[ 4 ] 9404 ]; 9405 } 9406 }, { 9407 // this regex ignores A-F because it's compared against an already lowercased string 9408 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, 9409 parse: function( execResult ) { 9410 return [ 9411 parseInt( execResult[ 1 ], 16 ), 9412 parseInt( execResult[ 2 ], 16 ), 9413 parseInt( execResult[ 3 ], 16 ) 9414 ]; 9415 } 9416 }, { 9417 // this regex ignores A-F because it's compared against an already lowercased string 9418 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, 9419 parse: function( execResult ) { 9420 return [ 9421 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 9422 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 9423 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) 9424 ]; 9425 } 9426 }, { 9427 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 9428 space: "hsla", 9429 parse: function( execResult ) { 9430 return [ 9431 execResult[ 1 ], 9432 execResult[ 2 ] / 100, 9433 execResult[ 3 ] / 100, 9434 execResult[ 4 ] 9435 ]; 9436 } 9437 } ], 9438 9439 // jQuery.Color( ) 9440 color = jQuery.Color = function( color, green, blue, alpha ) { 9441 return new jQuery.Color.fn.parse( color, green, blue, alpha ); 9442 }, 9443 spaces = { 9444 rgba: { 9445 props: { 9446 red: { 9447 idx: 0, 9448 type: "byte" 9449 }, 9450 green: { 9451 idx: 1, 9452 type: "byte" 9453 }, 9454 blue: { 9455 idx: 2, 9456 type: "byte" 9457 } 9458 } 9459 }, 9460 9461 hsla: { 9462 props: { 9463 hue: { 9464 idx: 0, 9465 type: "degrees" 9466 }, 9467 saturation: { 9468 idx: 1, 9469 type: "percent" 9470 }, 9471 lightness: { 9472 idx: 2, 9473 type: "percent" 9474 } 9475 } 9476 } 9477 }, 9478 propTypes = { 9479 "byte": { 9480 floor: true, 9481 max: 255 9482 }, 9483 "percent": { 9484 max: 1 9485 }, 9486 "degrees": { 9487 mod: 360, 9488 floor: true 9489 } 9490 }, 9491 support = color.support = {}, 9492 9493 // element for support tests 9494 supportElem = jQuery( "<p>" )[ 0 ], 9495 9496 // colors = jQuery.Color.names 9497 colors, 9498 9499 // local aliases of functions called often 9500 each = jQuery.each; 9501 9502 // determine rgba support immediately 9503 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; 9504 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; 9505 9506 // define cache name and alpha properties 9507 // for rgba and hsla spaces 9508 each( spaces, function( spaceName, space ) { 9509 space.cache = "_" + spaceName; 9510 space.props.alpha = { 9511 idx: 3, 9512 type: "percent", 9513 def: 1 9514 }; 9515 }); 9516 9517 function clamp( value, prop, allowEmpty ) { 9518 var type = propTypes[ prop.type ] || {}; 9519 9520 if ( value == null ) { 9521 return (allowEmpty || !prop.def) ? null : prop.def; 9522 } 9523 9524 // ~~ is an short way of doing floor for positive numbers 9525 value = type.floor ? ~~value : parseFloat( value ); 9526 9527 // IE will pass in empty strings as value for alpha, 9528 // which will hit this case 9529 if ( isNaN( value ) ) { 9530 return prop.def; 9531 } 9532 9533 if ( type.mod ) { 9534 // we add mod before modding to make sure that negatives values 9535 // get converted properly: -10 -> 350 9536 return (value + type.mod) % type.mod; 9537 } 9538 9539 // for now all property types without mod have min and max 9540 return 0 > value ? 0 : type.max < value ? type.max : value; 9541 } 9542 9543 function stringParse( string ) { 9544 var inst = color(), 9545 rgba = inst._rgba = []; 9546 9547 string = string.toLowerCase(); 9548 9549 each( stringParsers, function( i, parser ) { 9550 var parsed, 9551 match = parser.re.exec( string ), 9552 values = match && parser.parse( match ), 9553 spaceName = parser.space || "rgba"; 9554 9555 if ( values ) { 9556 parsed = inst[ spaceName ]( values ); 9557 9558 // if this was an rgba parse the assignment might happen twice 9559 // oh well.... 9560 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; 9561 rgba = inst._rgba = parsed._rgba; 9562 9563 // exit each( stringParsers ) here because we matched 9564 return false; 9565 } 9566 }); 9567 9568 // Found a stringParser that handled it 9569 if ( rgba.length ) { 9570 9571 // if this came from a parsed string, force "transparent" when alpha is 0 9572 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) 9573 if ( rgba.join() === "0,0,0,0" ) { 9574 jQuery.extend( rgba, colors.transparent ); 9575 } 9576 return inst; 9577 } 9578 9579 // named colors 9580 return colors[ string ]; 9581 } 9582 9583 color.fn = jQuery.extend( color.prototype, { 9584 parse: function( red, green, blue, alpha ) { 9585 if ( red === undefined ) { 9586 this._rgba = [ null, null, null, null ]; 9587 return this; 9588 } 9589 if ( red.jquery || red.nodeType ) { 9590 red = jQuery( red ).css( green ); 9591 green = undefined; 9592 } 9593 9594 var inst = this, 9595 type = jQuery.type( red ), 9596 rgba = this._rgba = []; 9597 9598 // more than 1 argument specified - assume ( red, green, blue, alpha ) 9599 if ( green !== undefined ) { 9600 red = [ red, green, blue, alpha ]; 9601 type = "array"; 9602 } 9603 9604 if ( type === "string" ) { 9605 return this.parse( stringParse( red ) || colors._default ); 9606 } 9607 9608 if ( type === "array" ) { 9609 each( spaces.rgba.props, function( key, prop ) { 9610 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); 9611 }); 9612 return this; 9613 } 9614 9615 if ( type === "object" ) { 9616 if ( red instanceof color ) { 9617 each( spaces, function( spaceName, space ) { 9618 if ( red[ space.cache ] ) { 9619 inst[ space.cache ] = red[ space.cache ].slice(); 9620 } 9621 }); 9622 } else { 9623 each( spaces, function( spaceName, space ) { 9624 var cache = space.cache; 9625 each( space.props, function( key, prop ) { 9626 9627 // if the cache doesn't exist, and we know how to convert 9628 if ( !inst[ cache ] && space.to ) { 9629 9630 // if the value was null, we don't need to copy it 9631 // if the key was alpha, we don't need to copy it either 9632 if ( key === "alpha" || red[ key ] == null ) { 9633 return; 9634 } 9635 inst[ cache ] = space.to( inst._rgba ); 9636 } 9637 9638 // this is the only case where we allow nulls for ALL properties. 9639 // call clamp with alwaysAllowEmpty 9640 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); 9641 }); 9642 9643 // everything defined but alpha? 9644 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { 9645 // use the default of 1 9646 inst[ cache ][ 3 ] = 1; 9647 if ( space.from ) { 9648 inst._rgba = space.from( inst[ cache ] ); 9649 } 9650 } 9651 }); 9652 } 9653 return this; 9654 } 9655 }, 9656 is: function( compare ) { 9657 var is = color( compare ), 9658 same = true, 9659 inst = this; 9660 9661 each( spaces, function( _, space ) { 9662 var localCache, 9663 isCache = is[ space.cache ]; 9664 if (isCache) { 9665 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; 9666 each( space.props, function( _, prop ) { 9667 if ( isCache[ prop.idx ] != null ) { 9668 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); 9669 return same; 9670 } 9671 }); 9672 } 9673 return same; 9674 }); 9675 return same; 9676 }, 9677 _space: function() { 9678 var used = [], 9679 inst = this; 9680 each( spaces, function( spaceName, space ) { 9681 if ( inst[ space.cache ] ) { 9682 used.push( spaceName ); 9683 } 9684 }); 9685 return used.pop(); 9686 }, 9687 transition: function( other, distance ) { 9688 var end = color( other ), 9689 spaceName = end._space(), 9690 space = spaces[ spaceName ], 9691 startColor = this.alpha() === 0 ? color( "transparent" ) : this, 9692 start = startColor[ space.cache ] || space.to( startColor._rgba ), 9693 result = start.slice(); 9694 9695 end = end[ space.cache ]; 9696 each( space.props, function( key, prop ) { 9697 var index = prop.idx, 9698 startValue = start[ index ], 9699 endValue = end[ index ], 9700 type = propTypes[ prop.type ] || {}; 9701 9702 // if null, don't override start value 9703 if ( endValue === null ) { 9704 return; 9705 } 9706 // if null - use end 9707 if ( startValue === null ) { 9708 result[ index ] = endValue; 9709 } else { 9710 if ( type.mod ) { 9711 if ( endValue - startValue > type.mod / 2 ) { 9712 startValue += type.mod; 9713 } else if ( startValue - endValue > type.mod / 2 ) { 9714 startValue -= type.mod; 9715 } 9716 } 9717 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); 9718 } 9719 }); 9720 return this[ spaceName ]( result ); 9721 }, 9722 blend: function( opaque ) { 9723 // if we are already opaque - return ourself 9724 if ( this._rgba[ 3 ] === 1 ) { 9725 return this; 9726 } 9727 9728 var rgb = this._rgba.slice(), 9729 a = rgb.pop(), 9730 blend = color( opaque )._rgba; 9731 9732 return color( jQuery.map( rgb, function( v, i ) { 9733 return ( 1 - a ) * blend[ i ] + a * v; 9734 })); 9735 }, 9736 toRgbaString: function() { 9737 var prefix = "rgba(", 9738 rgba = jQuery.map( this._rgba, function( v, i ) { 9739 return v == null ? ( i > 2 ? 1 : 0 ) : v; 9740 }); 9741 9742 if ( rgba[ 3 ] === 1 ) { 9743 rgba.pop(); 9744 prefix = "rgb("; 9745 } 9746 9747 return prefix + rgba.join() + ")"; 9748 }, 9749 toHslaString: function() { 9750 var prefix = "hsla(", 9751 hsla = jQuery.map( this.hsla(), function( v, i ) { 9752 if ( v == null ) { 9753 v = i > 2 ? 1 : 0; 9754 } 9755 9756 // catch 1 and 2 9757 if ( i && i < 3 ) { 9758 v = Math.round( v * 100 ) + "%"; 9759 } 9760 return v; 9761 }); 9762 9763 if ( hsla[ 3 ] === 1 ) { 9764 hsla.pop(); 9765 prefix = "hsl("; 9766 } 9767 return prefix + hsla.join() + ")"; 9768 }, 9769 toHexString: function( includeAlpha ) { 9770 var rgba = this._rgba.slice(), 9771 alpha = rgba.pop(); 9772 9773 if ( includeAlpha ) { 9774 rgba.push( ~~( alpha * 255 ) ); 9775 } 9776 9777 return "#" + jQuery.map( rgba, function( v ) { 9778 9779 // default to 0 when nulls exist 9780 v = ( v || 0 ).toString( 16 ); 9781 return v.length === 1 ? "0" + v : v; 9782 }).join(""); 9783 }, 9784 toString: function() { 9785 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); 9786 } 9787 }); 9788 color.fn.parse.prototype = color.fn; 9789 9790 // hsla conversions adapted from: 9791 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 9792 9793 function hue2rgb( p, q, h ) { 9794 h = ( h + 1 ) % 1; 9795 if ( h * 6 < 1 ) { 9796 return p + ( q - p ) * h * 6; 9797 } 9798 if ( h * 2 < 1) { 9799 return q; 9800 } 9801 if ( h * 3 < 2 ) { 9802 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; 9803 } 9804 return p; 9805 } 9806 9807 spaces.hsla.to = function( rgba ) { 9808 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { 9809 return [ null, null, null, rgba[ 3 ] ]; 9810 } 9811 var r = rgba[ 0 ] / 255, 9812 g = rgba[ 1 ] / 255, 9813 b = rgba[ 2 ] / 255, 9814 a = rgba[ 3 ], 9815 max = Math.max( r, g, b ), 9816 min = Math.min( r, g, b ), 9817 diff = max - min, 9818 add = max + min, 9819 l = add * 0.5, 9820 h, s; 9821 9822 if ( min === max ) { 9823 h = 0; 9824 } else if ( r === max ) { 9825 h = ( 60 * ( g - b ) / diff ) + 360; 9826 } else if ( g === max ) { 9827 h = ( 60 * ( b - r ) / diff ) + 120; 9828 } else { 9829 h = ( 60 * ( r - g ) / diff ) + 240; 9830 } 9831 9832 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% 9833 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) 9834 if ( diff === 0 ) { 9835 s = 0; 9836 } else if ( l <= 0.5 ) { 9837 s = diff / add; 9838 } else { 9839 s = diff / ( 2 - add ); 9840 } 9841 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; 9842 }; 9843 9844 spaces.hsla.from = function( hsla ) { 9845 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { 9846 return [ null, null, null, hsla[ 3 ] ]; 9847 } 9848 var h = hsla[ 0 ] / 360, 9849 s = hsla[ 1 ], 9850 l = hsla[ 2 ], 9851 a = hsla[ 3 ], 9852 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, 9853 p = 2 * l - q; 9854 9855 return [ 9856 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), 9857 Math.round( hue2rgb( p, q, h ) * 255 ), 9858 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), 9859 a 9860 ]; 9861 }; 9862 9863 each( spaces, function( spaceName, space ) { 9864 var props = space.props, 9865 cache = space.cache, 9866 to = space.to, 9867 from = space.from; 9868 9869 // makes rgba() and hsla() 9870 color.fn[ spaceName ] = function( value ) { 9871 9872 // generate a cache for this space if it doesn't exist 9873 if ( to && !this[ cache ] ) { 9874 this[ cache ] = to( this._rgba ); 9875 } 9876 if ( value === undefined ) { 9877 return this[ cache ].slice(); 9878 } 9879 9880 var ret, 9881 type = jQuery.type( value ), 9882 arr = ( type === "array" || type === "object" ) ? value : arguments, 9883 local = this[ cache ].slice(); 9884 9885 each( props, function( key, prop ) { 9886 var val = arr[ type === "object" ? key : prop.idx ]; 9887 if ( val == null ) { 9888 val = local[ prop.idx ]; 9889 } 9890 local[ prop.idx ] = clamp( val, prop ); 9891 }); 9892 9893 if ( from ) { 9894 ret = color( from( local ) ); 9895 ret[ cache ] = local; 9896 return ret; 9897 } else { 9898 return color( local ); 9899 } 9900 }; 9901 9902 // makes red() green() blue() alpha() hue() saturation() lightness() 9903 each( props, function( key, prop ) { 9904 // alpha is included in more than one space 9905 if ( color.fn[ key ] ) { 9906 return; 9907 } 9908 color.fn[ key ] = function( value ) { 9909 var vtype = jQuery.type( value ), 9910 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), 9911 local = this[ fn ](), 9912 cur = local[ prop.idx ], 9913 match; 9914 9915 if ( vtype === "undefined" ) { 9916 return cur; 9917 } 9918 9919 if ( vtype === "function" ) { 9920 value = value.call( this, cur ); 9921 vtype = jQuery.type( value ); 9922 } 9923 if ( value == null && prop.empty ) { 9924 return this; 9925 } 9926 if ( vtype === "string" ) { 9927 match = rplusequals.exec( value ); 9928 if ( match ) { 9929 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); 9930 } 9931 } 9932 local[ prop.idx ] = value; 9933 return this[ fn ]( local ); 9934 }; 9935 }); 9936 }); 9937 9938 // add cssHook and .fx.step function for each named hook. 9939 // accept a space separated string of properties 9940 color.hook = function( hook ) { 9941 var hooks = hook.split( " " ); 9942 each( hooks, function( i, hook ) { 9943 jQuery.cssHooks[ hook ] = { 9944 set: function( elem, value ) { 9945 var parsed, curElem, 9946 backgroundColor = ""; 9947 9948 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { 9949 value = color( parsed || value ); 9950 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { 9951 curElem = hook === "backgroundColor" ? elem.parentNode : elem; 9952 while ( 9953 (backgroundColor === "" || backgroundColor === "transparent") && 9954 curElem && curElem.style 9955 ) { 9956 try { 9957 backgroundColor = jQuery.css( curElem, "backgroundColor" ); 9958 curElem = curElem.parentNode; 9959 } catch ( e ) { 9960 } 9961 } 9962 9963 value = value.blend( backgroundColor && backgroundColor !== "transparent" ? 9964 backgroundColor : 9965 "_default" ); 9966 } 9967 9968 value = value.toRgbaString(); 9969 } 9970 try { 9971 elem.style[ hook ] = value; 9972 } catch ( e ) { 9973 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' 9974 } 9975 } 9976 }; 9977 jQuery.fx.step[ hook ] = function( fx ) { 9978 if ( !fx.colorInit ) { 9979 fx.start = color( fx.elem, hook ); 9980 fx.end = color( fx.end ); 9981 fx.colorInit = true; 9982 } 9983 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); 9984 }; 9985 }); 9986 9987 }; 9988 9989 color.hook( stepHooks ); 9990 9991 jQuery.cssHooks.borderColor = { 9992 expand: function( value ) { 9993 var expanded = {}; 9994 9995 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { 9996 expanded[ "border" + part + "Color" ] = value; 9997 }); 9998 return expanded; 9999 } 10000 }; 10001 10002 // Basic color names only. 10003 // Usage of any of the other color names requires adding yourself or including 10004 // jquery.color.svg-names.js. 10005 colors = jQuery.Color.names = { 10006 // 4.1. Basic color keywords 10007 aqua: "#00ffff", 10008 black: "#000000", 10009 blue: "#0000ff", 10010 fuchsia: "#ff00ff", 10011 gray: "#808080", 10012 green: "#008000", 10013 lime: "#00ff00", 10014 maroon: "#800000", 10015 navy: "#000080", 10016 olive: "#808000", 10017 purple: "#800080", 10018 red: "#ff0000", 10019 silver: "#c0c0c0", 10020 teal: "#008080", 10021 white: "#ffffff", 10022 yellow: "#ffff00", 10023 10024 // 4.2.3. "transparent" color keyword 10025 transparent: [ null, null, null, 0 ], 10026 10027 _default: "#ffffff" 10028 }; 10029 10030 })( jQuery ); 10031 10032 /******************************************************************************/ 10033 /****************************** CLASS ANIMATIONS ******************************/ 10034 /******************************************************************************/ 10035 (function() { 10036 10037 var classAnimationActions = [ "add", "remove", "toggle" ], 10038 shorthandStyles = { 10039 border: 1, 10040 borderBottom: 1, 10041 borderColor: 1, 10042 borderLeft: 1, 10043 borderRight: 1, 10044 borderTop: 1, 10045 borderWidth: 1, 10046 margin: 1, 10047 padding: 1 10048 }; 10049 10050 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { 10051 $.fx.step[ prop ] = function( fx ) { 10052 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { 10053 jQuery.style( fx.elem, prop, fx.end ); 10054 fx.setAttr = true; 10055 } 10056 }; 10057 }); 10058 10059 function getElementStyles( elem ) { 10060 var key, len, 10061 style = elem.ownerDocument.defaultView ? 10062 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : 10063 elem.currentStyle, 10064 styles = {}; 10065 10066 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { 10067 len = style.length; 10068 while ( len-- ) { 10069 key = style[ len ]; 10070 if ( typeof style[ key ] === "string" ) { 10071 styles[ $.camelCase( key ) ] = style[ key ]; 10072 } 10073 } 10074 // support: Opera, IE <9 10075 } else { 10076 for ( key in style ) { 10077 if ( typeof style[ key ] === "string" ) { 10078 styles[ key ] = style[ key ]; 10079 } 10080 } 10081 } 10082 10083 return styles; 10084 } 10085 10086 function styleDifference( oldStyle, newStyle ) { 10087 var diff = {}, 10088 name, value; 10089 10090 for ( name in newStyle ) { 10091 value = newStyle[ name ]; 10092 if ( oldStyle[ name ] !== value ) { 10093 if ( !shorthandStyles[ name ] ) { 10094 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { 10095 diff[ name ] = value; 10096 } 10097 } 10098 } 10099 } 10100 10101 return diff; 10102 } 10103 10104 // support: jQuery <1.8 10105 if ( !$.fn.addBack ) { 10106 $.fn.addBack = function( selector ) { 10107 return this.add( selector == null ? 10108 this.prevObject : this.prevObject.filter( selector ) 10109 ); 10110 }; 10111 } 10112 10113 $.effects.animateClass = function( value, duration, easing, callback ) { 10114 var o = $.speed( duration, easing, callback ); 10115 10116 return this.queue( function() { 10117 var animated = $( this ), 10118 baseClass = animated.attr( "class" ) || "", 10119 applyClassChange, 10120 allAnimations = o.children ? animated.find( "*" ).addBack() : animated; 10121 10122 // map the animated objects to store the original styles. 10123 allAnimations = allAnimations.map(function() { 10124 var el = $( this ); 10125 return { 10126 el: el, 10127 start: getElementStyles( this ) 10128 }; 10129 }); 10130 10131 // apply class change 10132 applyClassChange = function() { 10133 $.each( classAnimationActions, function(i, action) { 10134 if ( value[ action ] ) { 10135 animated[ action + "Class" ]( value[ action ] ); 10136 } 10137 }); 10138 }; 10139 applyClassChange(); 10140 10141 // map all animated objects again - calculate new styles and diff 10142 allAnimations = allAnimations.map(function() { 10143 this.end = getElementStyles( this.el[ 0 ] ); 10144 this.diff = styleDifference( this.start, this.end ); 10145 return this; 10146 }); 10147 10148 // apply original class 10149 animated.attr( "class", baseClass ); 10150 10151 // map all animated objects again - this time collecting a promise 10152 allAnimations = allAnimations.map(function() { 10153 var styleInfo = this, 10154 dfd = $.Deferred(), 10155 opts = $.extend({}, o, { 10156 queue: false, 10157 complete: function() { 10158 dfd.resolve( styleInfo ); 10159 } 10160 }); 10161 10162 this.el.animate( this.diff, opts ); 10163 return dfd.promise(); 10164 }); 10165 10166 // once all animations have completed: 10167 $.when.apply( $, allAnimations.get() ).done(function() { 10168 10169 // set the final class 10170 applyClassChange(); 10171 10172 // for each animated element, 10173 // clear all css properties that were animated 10174 $.each( arguments, function() { 10175 var el = this.el; 10176 $.each( this.diff, function(key) { 10177 el.css( key, "" ); 10178 }); 10179 }); 10180 10181 // this is guarnteed to be there if you use jQuery.speed() 10182 // it also handles dequeuing the next anim... 10183 o.complete.call( animated[ 0 ] ); 10184 }); 10185 }); 10186 }; 10187 10188 $.fn.extend({ 10189 addClass: (function( orig ) { 10190 return function( classNames, speed, easing, callback ) { 10191 return speed ? 10192 $.effects.animateClass.call( this, 10193 { add: classNames }, speed, easing, callback ) : 10194 orig.apply( this, arguments ); 10195 }; 10196 })( $.fn.addClass ), 10197 10198 removeClass: (function( orig ) { 10199 return function( classNames, speed, easing, callback ) { 10200 return arguments.length > 1 ? 10201 $.effects.animateClass.call( this, 10202 { remove: classNames }, speed, easing, callback ) : 10203 orig.apply( this, arguments ); 10204 }; 10205 })( $.fn.removeClass ), 10206 10207 toggleClass: (function( orig ) { 10208 return function( classNames, force, speed, easing, callback ) { 10209 if ( typeof force === "boolean" || force === undefined ) { 10210 if ( !speed ) { 10211 // without speed parameter 10212 return orig.apply( this, arguments ); 10213 } else { 10214 return $.effects.animateClass.call( this, 10215 (force ? { add: classNames } : { remove: classNames }), 10216 speed, easing, callback ); 10217 } 10218 } else { 10219 // without force parameter 10220 return $.effects.animateClass.call( this, 10221 { toggle: classNames }, force, speed, easing ); 10222 } 10223 }; 10224 })( $.fn.toggleClass ), 10225 10226 switchClass: function( remove, add, speed, easing, callback) { 10227 return $.effects.animateClass.call( this, { 10228 add: add, 10229 remove: remove 10230 }, speed, easing, callback ); 10231 } 10232 }); 10233 10234 })(); 10235 10236 /******************************************************************************/ 10237 /*********************************** EFFECTS **********************************/ 10238 /******************************************************************************/ 10239 10240 (function() { 10241 10242 $.extend( $.effects, { 10243 version: "1.11.4", 10244 10245 // Saves a set of properties in a data storage 10246 save: function( element, set ) { 10247 for ( var i = 0; i < set.length; i++ ) { 10248 if ( set[ i ] !== null ) { 10249 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); 10250 } 10251 } 10252 }, 10253 10254 // Restores a set of previously saved properties from a data storage 10255 restore: function( element, set ) { 10256 var val, i; 10257 for ( i = 0; i < set.length; i++ ) { 10258 if ( set[ i ] !== null ) { 10259 val = element.data( dataSpace + set[ i ] ); 10260 // support: jQuery 1.6.2 10261 // http://bugs.jquery.com/ticket/9917 10262 // jQuery 1.6.2 incorrectly returns undefined for any falsy value. 10263 // We can't differentiate between "" and 0 here, so we just assume 10264 // empty string since it's likely to be a more common value... 10265 if ( val === undefined ) { 10266 val = ""; 10267 } 10268 element.css( set[ i ], val ); 10269 } 10270 } 10271 }, 10272 10273 setMode: function( el, mode ) { 10274 if (mode === "toggle") { 10275 mode = el.is( ":hidden" ) ? "show" : "hide"; 10276 } 10277 return mode; 10278 }, 10279 10280 // Translates a [top,left] array into a baseline value 10281 // this should be a little more flexible in the future to handle a string & hash 10282 getBaseline: function( origin, original ) { 10283 var y, x; 10284 switch ( origin[ 0 ] ) { 10285 case "top": y = 0; break; 10286 case "middle": y = 0.5; break; 10287 case "bottom": y = 1; break; 10288 default: y = origin[ 0 ] / original.height; 10289 } 10290 switch ( origin[ 1 ] ) { 10291 case "left": x = 0; break; 10292 case "center": x = 0.5; break; 10293 case "right": x = 1; break; 10294 default: x = origin[ 1 ] / original.width; 10295 } 10296 return { 10297 x: x, 10298 y: y 10299 }; 10300 }, 10301 10302 // Wraps the element around a wrapper that copies position properties 10303 createWrapper: function( element ) { 10304 10305 // if the element is already wrapped, return it 10306 if ( element.parent().is( ".ui-effects-wrapper" )) { 10307 return element.parent(); 10308 } 10309 10310 // wrap the element 10311 var props = { 10312 width: element.outerWidth(true), 10313 height: element.outerHeight(true), 10314 "float": element.css( "float" ) 10315 }, 10316 wrapper = $( "<div></div>" ) 10317 .addClass( "ui-effects-wrapper" ) 10318 .css({ 10319 fontSize: "100%", 10320 background: "transparent", 10321 border: "none", 10322 margin: 0, 10323 padding: 0 10324 }), 10325 // Store the size in case width/height are defined in % - Fixes #5245 10326 size = { 10327 width: element.width(), 10328 height: element.height() 10329 }, 10330 active = document.activeElement; 10331 10332 // support: Firefox 10333 // Firefox incorrectly exposes anonymous content 10334 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 10335 try { 10336 active.id; 10337 } catch ( e ) { 10338 active = document.body; 10339 } 10340 10341 element.wrap( wrapper ); 10342 10343 // Fixes #7595 - Elements lose focus when wrapped. 10344 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 10345 $( active ).focus(); 10346 } 10347 10348 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element 10349 10350 // transfer positioning properties to the wrapper 10351 if ( element.css( "position" ) === "static" ) { 10352 wrapper.css({ position: "relative" }); 10353 element.css({ position: "relative" }); 10354 } else { 10355 $.extend( props, { 10356 position: element.css( "position" ), 10357 zIndex: element.css( "z-index" ) 10358 }); 10359 $.each([ "top", "left", "bottom", "right" ], function(i, pos) { 10360 props[ pos ] = element.css( pos ); 10361 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { 10362 props[ pos ] = "auto"; 10363 } 10364 }); 10365 element.css({ 10366 position: "relative", 10367 top: 0, 10368 left: 0, 10369 right: "auto", 10370 bottom: "auto" 10371 }); 10372 } 10373 element.css(size); 10374 10375 return wrapper.css( props ).show(); 10376 }, 10377 10378 removeWrapper: function( element ) { 10379 var active = document.activeElement; 10380 10381 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 10382 element.parent().replaceWith( element ); 10383 10384 // Fixes #7595 - Elements lose focus when wrapped. 10385 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 10386 $( active ).focus(); 10387 } 10388 } 10389 10390 return element; 10391 }, 10392 10393 setTransition: function( element, list, factor, value ) { 10394 value = value || {}; 10395 $.each( list, function( i, x ) { 10396 var unit = element.cssUnit( x ); 10397 if ( unit[ 0 ] > 0 ) { 10398 value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; 10399 } 10400 }); 10401 return value; 10402 } 10403 }); 10404 10405 // return an effect options object for the given parameters: 10406 function _normalizeArguments( effect, options, speed, callback ) { 10407 10408 // allow passing all options as the first parameter 10409 if ( $.isPlainObject( effect ) ) { 10410 options = effect; 10411 effect = effect.effect; 10412 } 10413 10414 // convert to an object 10415 effect = { effect: effect }; 10416 10417 // catch (effect, null, ...) 10418 if ( options == null ) { 10419 options = {}; 10420 } 10421 10422 // catch (effect, callback) 10423 if ( $.isFunction( options ) ) { 10424 callback = options; 10425 speed = null; 10426 options = {}; 10427 } 10428 10429 // catch (effect, speed, ?) 10430 if ( typeof options === "number" || $.fx.speeds[ options ] ) { 10431 callback = speed; 10432 speed = options; 10433 options = {}; 10434 } 10435 10436 // catch (effect, options, callback) 10437 if ( $.isFunction( speed ) ) { 10438 callback = speed; 10439 speed = null; 10440 } 10441 10442 // add options to effect 10443 if ( options ) { 10444 $.extend( effect, options ); 10445 } 10446 10447 speed = speed || options.duration; 10448 effect.duration = $.fx.off ? 0 : 10449 typeof speed === "number" ? speed : 10450 speed in $.fx.speeds ? $.fx.speeds[ speed ] : 10451 $.fx.speeds._default; 10452 10453 effect.complete = callback || options.complete; 10454 10455 return effect; 10456 } 10457 10458 function standardAnimationOption( option ) { 10459 // Valid standard speeds (nothing, number, named speed) 10460 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { 10461 return true; 10462 } 10463 10464 // Invalid strings - treat as "normal" speed 10465 if ( typeof option === "string" && !$.effects.effect[ option ] ) { 10466 return true; 10467 } 10468 10469 // Complete callback 10470 if ( $.isFunction( option ) ) { 10471 return true; 10472 } 10473 10474 // Options hash (but not naming an effect) 10475 if ( typeof option === "object" && !option.effect ) { 10476 return true; 10477 } 10478 10479 // Didn't match any standard API 10480 return false; 10481 } 10482 10483 $.fn.extend({ 10484 effect: function( /* effect, options, speed, callback */ ) { 10485 var args = _normalizeArguments.apply( this, arguments ), 10486 mode = args.mode, 10487 queue = args.queue, 10488 effectMethod = $.effects.effect[ args.effect ]; 10489 10490 if ( $.fx.off || !effectMethod ) { 10491 // delegate to the original method (e.g., .show()) if possible 10492 if ( mode ) { 10493 return this[ mode ]( args.duration, args.complete ); 10494 } else { 10495 return this.each( function() { 10496 if ( args.complete ) { 10497 args.complete.call( this ); 10498 } 10499 }); 10500 } 10501 } 10502 10503 function run( next ) { 10504 var elem = $( this ), 10505 complete = args.complete, 10506 mode = args.mode; 10507 10508 function done() { 10509 if ( $.isFunction( complete ) ) { 10510 complete.call( elem[0] ); 10511 } 10512 if ( $.isFunction( next ) ) { 10513 next(); 10514 } 10515 } 10516 10517 // If the element already has the correct final state, delegate to 10518 // the core methods so the internal tracking of "olddisplay" works. 10519 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { 10520 elem[ mode ](); 10521 done(); 10522 } else { 10523 effectMethod.call( elem[0], args, done ); 10524 } 10525 } 10526 10527 return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); 10528 }, 10529 10530 show: (function( orig ) { 10531 return function( option ) { 10532 if ( standardAnimationOption( option ) ) { 10533 return orig.apply( this, arguments ); 10534 } else { 10535 var args = _normalizeArguments.apply( this, arguments ); 10536 args.mode = "show"; 10537 return this.effect.call( this, args ); 10538 } 10539 }; 10540 })( $.fn.show ), 10541 10542 hide: (function( orig ) { 10543 return function( option ) { 10544 if ( standardAnimationOption( option ) ) { 10545 return orig.apply( this, arguments ); 10546 } else { 10547 var args = _normalizeArguments.apply( this, arguments ); 10548 args.mode = "hide"; 10549 return this.effect.call( this, args ); 10550 } 10551 }; 10552 })( $.fn.hide ), 10553 10554 toggle: (function( orig ) { 10555 return function( option ) { 10556 if ( standardAnimationOption( option ) || typeof option === "boolean" ) { 10557 return orig.apply( this, arguments ); 10558 } else { 10559 var args = _normalizeArguments.apply( this, arguments ); 10560 args.mode = "toggle"; 10561 return this.effect.call( this, args ); 10562 } 10563 }; 10564 })( $.fn.toggle ), 10565 10566 // helper functions 10567 cssUnit: function(key) { 10568 var style = this.css( key ), 10569 val = []; 10570 10571 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { 10572 if ( style.indexOf( unit ) > 0 ) { 10573 val = [ parseFloat( style ), unit ]; 10574 } 10575 }); 10576 return val; 10577 } 10578 }); 10579 10580 })(); 10581 10582 /******************************************************************************/ 10583 /*********************************** EASING ***********************************/ 10584 /******************************************************************************/ 10585 10586 (function() { 10587 10588 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing) 10589 10590 var baseEasings = {}; 10591 10592 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { 10593 baseEasings[ name ] = function( p ) { 10594 return Math.pow( p, i + 2 ); 10595 }; 10596 }); 10597 10598 $.extend( baseEasings, { 10599 Sine: function( p ) { 10600 return 1 - Math.cos( p * Math.PI / 2 ); 10601 }, 10602 Circ: function( p ) { 10603 return 1 - Math.sqrt( 1 - p * p ); 10604 }, 10605 Elastic: function( p ) { 10606 return p === 0 || p === 1 ? p : 10607 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); 10608 }, 10609 Back: function( p ) { 10610 return p * p * ( 3 * p - 2 ); 10611 }, 10612 Bounce: function( p ) { 10613 var pow2, 10614 bounce = 4; 10615 10616 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} 10617 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); 10618 } 10619 }); 10620 10621 $.each( baseEasings, function( name, easeIn ) { 10622 $.easing[ "easeIn" + name ] = easeIn; 10623 $.easing[ "easeOut" + name ] = function( p ) { 10624 return 1 - easeIn( 1 - p ); 10625 }; 10626 $.easing[ "easeInOut" + name ] = function( p ) { 10627 return p < 0.5 ? 10628 easeIn( p * 2 ) / 2 : 10629 1 - easeIn( p * -2 + 2 ) / 2; 10630 }; 10631 }); 10632 10633 })(); 10634 10635 var effect = $.effects; 10636 10637 10638 /*! 10639 * jQuery UI Effects Blind 1.11.4 10640 * http://jqueryui.com 10641 * 10642 * Copyright jQuery Foundation and other contributors 10643 * Released under the MIT license. 10644 * http://jquery.org/license 10645 * 10646 * http://api.jqueryui.com/blind-effect/ 10647 */ 10648 10649 10650 var effectBlind = $.effects.effect.blind = function( o, done ) { 10651 // Create element 10652 var el = $( this ), 10653 rvertical = /up|down|vertical/, 10654 rpositivemotion = /up|left|vertical|horizontal/, 10655 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10656 mode = $.effects.setMode( el, o.mode || "hide" ), 10657 direction = o.direction || "up", 10658 vertical = rvertical.test( direction ), 10659 ref = vertical ? "height" : "width", 10660 ref2 = vertical ? "top" : "left", 10661 motion = rpositivemotion.test( direction ), 10662 animation = {}, 10663 show = mode === "show", 10664 wrapper, distance, margin; 10665 10666 // if already wrapped, the wrapper's properties are my property. #6245 10667 if ( el.parent().is( ".ui-effects-wrapper" ) ) { 10668 $.effects.save( el.parent(), props ); 10669 } else { 10670 $.effects.save( el, props ); 10671 } 10672 el.show(); 10673 wrapper = $.effects.createWrapper( el ).css({ 10674 overflow: "hidden" 10675 }); 10676 10677 distance = wrapper[ ref ](); 10678 margin = parseFloat( wrapper.css( ref2 ) ) || 0; 10679 10680 animation[ ref ] = show ? distance : 0; 10681 if ( !motion ) { 10682 el 10683 .css( vertical ? "bottom" : "right", 0 ) 10684 .css( vertical ? "top" : "left", "auto" ) 10685 .css({ position: "absolute" }); 10686 10687 animation[ ref2 ] = show ? margin : distance + margin; 10688 } 10689 10690 // start at 0 if we are showing 10691 if ( show ) { 10692 wrapper.css( ref, 0 ); 10693 if ( !motion ) { 10694 wrapper.css( ref2, margin + distance ); 10695 } 10696 } 10697 10698 // Animate 10699 wrapper.animate( animation, { 10700 duration: o.duration, 10701 easing: o.easing, 10702 queue: false, 10703 complete: function() { 10704 if ( mode === "hide" ) { 10705 el.hide(); 10706 } 10707 $.effects.restore( el, props ); 10708 $.effects.removeWrapper( el ); 10709 done(); 10710 } 10711 }); 10712 }; 10713 10714 10715 /*! 10716 * jQuery UI Effects Bounce 1.11.4 10717 * http://jqueryui.com 10718 * 10719 * Copyright jQuery Foundation and other contributors 10720 * Released under the MIT license. 10721 * http://jquery.org/license 10722 * 10723 * http://api.jqueryui.com/bounce-effect/ 10724 */ 10725 10726 10727 var effectBounce = $.effects.effect.bounce = function( o, done ) { 10728 var el = $( this ), 10729 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10730 10731 // defaults: 10732 mode = $.effects.setMode( el, o.mode || "effect" ), 10733 hide = mode === "hide", 10734 show = mode === "show", 10735 direction = o.direction || "up", 10736 distance = o.distance, 10737 times = o.times || 5, 10738 10739 // number of internal animations 10740 anims = times * 2 + ( show || hide ? 1 : 0 ), 10741 speed = o.duration / anims, 10742 easing = o.easing, 10743 10744 // utility: 10745 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 10746 motion = ( direction === "up" || direction === "left" ), 10747 i, 10748 upAnim, 10749 downAnim, 10750 10751 // we will need to re-assemble the queue to stack our animations in place 10752 queue = el.queue(), 10753 queuelen = queue.length; 10754 10755 // Avoid touching opacity to prevent clearType and PNG issues in IE 10756 if ( show || hide ) { 10757 props.push( "opacity" ); 10758 } 10759 10760 $.effects.save( el, props ); 10761 el.show(); 10762 $.effects.createWrapper( el ); // Create Wrapper 10763 10764 // default distance for the BIGGEST bounce is the outer Distance / 3 10765 if ( !distance ) { 10766 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; 10767 } 10768 10769 if ( show ) { 10770 downAnim = { opacity: 1 }; 10771 downAnim[ ref ] = 0; 10772 10773 // if we are showing, force opacity 0 and set the initial position 10774 // then do the "first" animation 10775 el.css( "opacity", 0 ) 10776 .css( ref, motion ? -distance * 2 : distance * 2 ) 10777 .animate( downAnim, speed, easing ); 10778 } 10779 10780 // start at the smallest distance if we are hiding 10781 if ( hide ) { 10782 distance = distance / Math.pow( 2, times - 1 ); 10783 } 10784 10785 downAnim = {}; 10786 downAnim[ ref ] = 0; 10787 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here 10788 for ( i = 0; i < times; i++ ) { 10789 upAnim = {}; 10790 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 10791 10792 el.animate( upAnim, speed, easing ) 10793 .animate( downAnim, speed, easing ); 10794 10795 distance = hide ? distance * 2 : distance / 2; 10796 } 10797 10798 // Last Bounce when Hiding 10799 if ( hide ) { 10800 upAnim = { opacity: 0 }; 10801 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 10802 10803 el.animate( upAnim, speed, easing ); 10804 } 10805 10806 el.queue(function() { 10807 if ( hide ) { 10808 el.hide(); 10809 } 10810 $.effects.restore( el, props ); 10811 $.effects.removeWrapper( el ); 10812 done(); 10813 }); 10814 10815 // inject all the animations we just queued to be first in line (after "inprogress") 10816 if ( queuelen > 1) { 10817 queue.splice.apply( queue, 10818 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); 10819 } 10820 el.dequeue(); 10821 10822 }; 10823 10824 10825 /*! 10826 * jQuery UI Effects Clip 1.11.4 10827 * http://jqueryui.com 10828 * 10829 * Copyright jQuery Foundation and other contributors 10830 * Released under the MIT license. 10831 * http://jquery.org/license 10832 * 10833 * http://api.jqueryui.com/clip-effect/ 10834 */ 10835 10836 10837 var effectClip = $.effects.effect.clip = function( o, done ) { 10838 // Create element 10839 var el = $( this ), 10840 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10841 mode = $.effects.setMode( el, o.mode || "hide" ), 10842 show = mode === "show", 10843 direction = o.direction || "vertical", 10844 vert = direction === "vertical", 10845 size = vert ? "height" : "width", 10846 position = vert ? "top" : "left", 10847 animation = {}, 10848 wrapper, animate, distance; 10849 10850 // Save & Show 10851 $.effects.save( el, props ); 10852 el.show(); 10853 10854 // Create Wrapper 10855 wrapper = $.effects.createWrapper( el ).css({ 10856 overflow: "hidden" 10857 }); 10858 animate = ( el[0].tagName === "IMG" ) ? wrapper : el; 10859 distance = animate[ size ](); 10860 10861 // Shift 10862 if ( show ) { 10863 animate.css( size, 0 ); 10864 animate.css( position, distance / 2 ); 10865 } 10866 10867 // Create Animation Object: 10868 animation[ size ] = show ? distance : 0; 10869 animation[ position ] = show ? 0 : distance / 2; 10870 10871 // Animate 10872 animate.animate( animation, { 10873 queue: false, 10874 duration: o.duration, 10875 easing: o.easing, 10876 complete: function() { 10877 if ( !show ) { 10878 el.hide(); 10879 } 10880 $.effects.restore( el, props ); 10881 $.effects.removeWrapper( el ); 10882 done(); 10883 } 10884 }); 10885 10886 }; 10887 10888 10889 /*! 10890 * jQuery UI Effects Drop 1.11.4 10891 * http://jqueryui.com 10892 * 10893 * Copyright jQuery Foundation and other contributors 10894 * Released under the MIT license. 10895 * http://jquery.org/license 10896 * 10897 * http://api.jqueryui.com/drop-effect/ 10898 */ 10899 10900 10901 var effectDrop = $.effects.effect.drop = function( o, done ) { 10902 10903 var el = $( this ), 10904 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], 10905 mode = $.effects.setMode( el, o.mode || "hide" ), 10906 show = mode === "show", 10907 direction = o.direction || "left", 10908 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 10909 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", 10910 animation = { 10911 opacity: show ? 1 : 0 10912 }, 10913 distance; 10914 10915 // Adjust 10916 $.effects.save( el, props ); 10917 el.show(); 10918 $.effects.createWrapper( el ); 10919 10920 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; 10921 10922 if ( show ) { 10923 el 10924 .css( "opacity", 0 ) 10925 .css( ref, motion === "pos" ? -distance : distance ); 10926 } 10927 10928 // Animation 10929 animation[ ref ] = ( show ? 10930 ( motion === "pos" ? "+=" : "-=" ) : 10931 ( motion === "pos" ? "-=" : "+=" ) ) + 10932 distance; 10933 10934 // Animate 10935 el.animate( animation, { 10936 queue: false, 10937 duration: o.duration, 10938 easing: o.easing, 10939 complete: function() { 10940 if ( mode === "hide" ) { 10941 el.hide(); 10942 } 10943 $.effects.restore( el, props ); 10944 $.effects.removeWrapper( el ); 10945 done(); 10946 } 10947 }); 10948 }; 10949 10950 10951 /*! 10952 * jQuery UI Effects Explode 1.11.4 10953 * http://jqueryui.com 10954 * 10955 * Copyright jQuery Foundation and other contributors 10956 * Released under the MIT license. 10957 * http://jquery.org/license 10958 * 10959 * http://api.jqueryui.com/explode-effect/ 10960 */ 10961 10962 10963 var effectExplode = $.effects.effect.explode = function( o, done ) { 10964 10965 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, 10966 cells = rows, 10967 el = $( this ), 10968 mode = $.effects.setMode( el, o.mode || "hide" ), 10969 show = mode === "show", 10970 10971 // show and then visibility:hidden the element before calculating offset 10972 offset = el.show().css( "visibility", "hidden" ).offset(), 10973 10974 // width and height of a piece 10975 width = Math.ceil( el.outerWidth() / cells ), 10976 height = Math.ceil( el.outerHeight() / rows ), 10977 pieces = [], 10978 10979 // loop 10980 i, j, left, top, mx, my; 10981 10982 // children animate complete: 10983 function childComplete() { 10984 pieces.push( this ); 10985 if ( pieces.length === rows * cells ) { 10986 animComplete(); 10987 } 10988 } 10989 10990 // clone the element for each row and cell. 10991 for ( i = 0; i < rows ; i++ ) { // ===> 10992 top = offset.top + i * height; 10993 my = i - ( rows - 1 ) / 2 ; 10994 10995 for ( j = 0; j < cells ; j++ ) { // ||| 10996 left = offset.left + j * width; 10997 mx = j - ( cells - 1 ) / 2 ; 10998 10999 // Create a clone of the now hidden main element that will be absolute positioned 11000 // within a wrapper div off the -left and -top equal to size of our pieces 11001 el 11002 .clone() 11003 .appendTo( "body" ) 11004 .wrap( "<div></div>" ) 11005 .css({ 11006 position: "absolute", 11007 visibility: "visible", 11008 left: -j * width, 11009 top: -i * height 11010 }) 11011 11012 // select the wrapper - make it overflow: hidden and absolute positioned based on 11013 // where the original was located +left and +top equal to the size of pieces 11014 .parent() 11015 .addClass( "ui-effects-explode" ) 11016 .css({ 11017 position: "absolute", 11018 overflow: "hidden", 11019 width: width, 11020 height: height, 11021 left: left + ( show ? mx * width : 0 ), 11022 top: top + ( show ? my * height : 0 ), 11023 opacity: show ? 0 : 1 11024 }).animate({ 11025 left: left + ( show ? 0 : mx * width ), 11026 top: top + ( show ? 0 : my * height ), 11027 opacity: show ? 1 : 0 11028 }, o.duration || 500, o.easing, childComplete ); 11029 } 11030 } 11031 11032 function animComplete() { 11033 el.css({ 11034 visibility: "visible" 11035 }); 11036 $( pieces ).remove(); 11037 if ( !show ) { 11038 el.hide(); 11039 } 11040 done(); 11041 } 11042 }; 11043 11044 11045 /*! 11046 * jQuery UI Effects Fade 1.11.4 11047 * http://jqueryui.com 11048 * 11049 * Copyright jQuery Foundation and other contributors 11050 * Released under the MIT license. 11051 * http://jquery.org/license 11052 * 11053 * http://api.jqueryui.com/fade-effect/ 11054 */ 11055 11056 11057 var effectFade = $.effects.effect.fade = function( o, done ) { 11058 var el = $( this ), 11059 mode = $.effects.setMode( el, o.mode || "toggle" ); 11060 11061 el.animate({ 11062 opacity: mode 11063 }, { 11064 queue: false, 11065 duration: o.duration, 11066 easing: o.easing, 11067 complete: done 11068 }); 11069 }; 11070 11071 11072 /*! 11073 * jQuery UI Effects Fold 1.11.4 11074 * http://jqueryui.com 11075 * 11076 * Copyright jQuery Foundation and other contributors 11077 * Released under the MIT license. 11078 * http://jquery.org/license 11079 * 11080 * http://api.jqueryui.com/fold-effect/ 11081 */ 11082 11083 11084 var effectFold = $.effects.effect.fold = function( o, done ) { 11085 11086 // Create element 11087 var el = $( this ), 11088 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 11089 mode = $.effects.setMode( el, o.mode || "hide" ), 11090 show = mode === "show", 11091 hide = mode === "hide", 11092 size = o.size || 15, 11093 percent = /([0-9]+)%/.exec( size ), 11094 horizFirst = !!o.horizFirst, 11095 widthFirst = show !== horizFirst, 11096 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], 11097 duration = o.duration / 2, 11098 wrapper, distance, 11099 animation1 = {}, 11100 animation2 = {}; 11101 11102 $.effects.save( el, props ); 11103 el.show(); 11104 11105 // Create Wrapper 11106 wrapper = $.effects.createWrapper( el ).css({ 11107 overflow: "hidden" 11108 }); 11109 distance = widthFirst ? 11110 [ wrapper.width(), wrapper.height() ] : 11111 [ wrapper.height(), wrapper.width() ]; 11112 11113 if ( percent ) { 11114 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; 11115 } 11116 if ( show ) { 11117 wrapper.css( horizFirst ? { 11118 height: 0, 11119 width: size 11120 } : { 11121 height: size, 11122 width: 0 11123 }); 11124 } 11125 11126 // Animation 11127 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; 11128 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; 11129 11130 // Animate 11131 wrapper 11132 .animate( animation1, duration, o.easing ) 11133 .animate( animation2, duration, o.easing, function() { 11134 if ( hide ) { 11135 el.hide(); 11136 } 11137 $.effects.restore( el, props ); 11138 $.effects.removeWrapper( el ); 11139 done(); 11140 }); 11141 11142 }; 11143 11144 11145 /*! 11146 * jQuery UI Effects Highlight 1.11.4 11147 * http://jqueryui.com 11148 * 11149 * Copyright jQuery Foundation and other contributors 11150 * Released under the MIT license. 11151 * http://jquery.org/license 11152 * 11153 * http://api.jqueryui.com/highlight-effect/ 11154 */ 11155 11156 11157 var effectHighlight = $.effects.effect.highlight = function( o, done ) { 11158 var elem = $( this ), 11159 props = [ "backgroundImage", "backgroundColor", "opacity" ], 11160 mode = $.effects.setMode( elem, o.mode || "show" ), 11161 animation = { 11162 backgroundColor: elem.css( "backgroundColor" ) 11163 }; 11164 11165 if (mode === "hide") { 11166 animation.opacity = 0; 11167 } 11168 11169 $.effects.save( elem, props ); 11170 11171 elem 11172 .show() 11173 .css({ 11174 backgroundImage: "none", 11175 backgroundColor: o.color || "#ffff99" 11176 }) 11177 .animate( animation, { 11178 queue: false, 11179 duration: o.duration, 11180 easing: o.easing, 11181 complete: function() { 11182 if ( mode === "hide" ) { 11183 elem.hide(); 11184 } 11185 $.effects.restore( elem, props ); 11186 done(); 11187 } 11188 }); 11189 }; 11190 11191 11192 /*! 11193 * jQuery UI Effects Size 1.11.4 11194 * http://jqueryui.com 11195 * 11196 * Copyright jQuery Foundation and other contributors 11197 * Released under the MIT license. 11198 * http://jquery.org/license 11199 * 11200 * http://api.jqueryui.com/size-effect/ 11201 */ 11202 11203 11204 var effectSize = $.effects.effect.size = function( o, done ) { 11205 11206 // Create element 11207 var original, baseline, factor, 11208 el = $( this ), 11209 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], 11210 11211 // Always restore 11212 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], 11213 11214 // Copy for children 11215 props2 = [ "width", "height", "overflow" ], 11216 cProps = [ "fontSize" ], 11217 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], 11218 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], 11219 11220 // Set options 11221 mode = $.effects.setMode( el, o.mode || "effect" ), 11222 restore = o.restore || mode !== "effect", 11223 scale = o.scale || "both", 11224 origin = o.origin || [ "middle", "center" ], 11225 position = el.css( "position" ), 11226 props = restore ? props0 : props1, 11227 zero = { 11228 height: 0, 11229 width: 0, 11230 outerHeight: 0, 11231 outerWidth: 0 11232 }; 11233 11234 if ( mode === "show" ) { 11235 el.show(); 11236 } 11237 original = { 11238 height: el.height(), 11239 width: el.width(), 11240 outerHeight: el.outerHeight(), 11241 outerWidth: el.outerWidth() 11242 }; 11243 11244 if ( o.mode === "toggle" && mode === "show" ) { 11245 el.from = o.to || zero; 11246 el.to = o.from || original; 11247 } else { 11248 el.from = o.from || ( mode === "show" ? zero : original ); 11249 el.to = o.to || ( mode === "hide" ? zero : original ); 11250 } 11251 11252 // Set scaling factor 11253 factor = { 11254 from: { 11255 y: el.from.height / original.height, 11256 x: el.from.width / original.width 11257 }, 11258 to: { 11259 y: el.to.height / original.height, 11260 x: el.to.width / original.width 11261 } 11262 }; 11263 11264 // Scale the css box 11265 if ( scale === "box" || scale === "both" ) { 11266 11267 // Vertical props scaling 11268 if ( factor.from.y !== factor.to.y ) { 11269 props = props.concat( vProps ); 11270 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); 11271 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); 11272 } 11273 11274 // Horizontal props scaling 11275 if ( factor.from.x !== factor.to.x ) { 11276 props = props.concat( hProps ); 11277 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); 11278 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); 11279 } 11280 } 11281 11282 // Scale the content 11283 if ( scale === "content" || scale === "both" ) { 11284 11285 // Vertical props scaling 11286 if ( factor.from.y !== factor.to.y ) { 11287 props = props.concat( cProps ).concat( props2 ); 11288 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); 11289 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); 11290 } 11291 } 11292 11293 $.effects.save( el, props ); 11294 el.show(); 11295 $.effects.createWrapper( el ); 11296 el.css( "overflow", "hidden" ).css( el.from ); 11297 11298 // Adjust 11299 if (origin) { // Calculate baseline shifts 11300 baseline = $.effects.getBaseline( origin, original ); 11301 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; 11302 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; 11303 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; 11304 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; 11305 } 11306 el.css( el.from ); // set top & left 11307 11308 // Animate 11309 if ( scale === "content" || scale === "both" ) { // Scale the children 11310 11311 // Add margins/font-size 11312 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); 11313 hProps = hProps.concat([ "marginLeft", "marginRight" ]); 11314 props2 = props0.concat(vProps).concat(hProps); 11315 11316 el.find( "*[width]" ).each( function() { 11317 var child = $( this ), 11318 c_original = { 11319 height: child.height(), 11320 width: child.width(), 11321 outerHeight: child.outerHeight(), 11322 outerWidth: child.outerWidth() 11323 }; 11324 if (restore) { 11325 $.effects.save(child, props2); 11326 } 11327 11328 child.from = { 11329 height: c_original.height * factor.from.y, 11330 width: c_original.width * factor.from.x, 11331 outerHeight: c_original.outerHeight * factor.from.y, 11332 outerWidth: c_original.outerWidth * factor.from.x 11333 }; 11334 child.to = { 11335 height: c_original.height * factor.to.y, 11336 width: c_original.width * factor.to.x, 11337 outerHeight: c_original.height * factor.to.y, 11338 outerWidth: c_original.width * factor.to.x 11339 }; 11340 11341 // Vertical props scaling 11342 if ( factor.from.y !== factor.to.y ) { 11343 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); 11344 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); 11345 } 11346 11347 // Horizontal props scaling 11348 if ( factor.from.x !== factor.to.x ) { 11349 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); 11350 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); 11351 } 11352 11353 // Animate children 11354 child.css( child.from ); 11355 child.animate( child.to, o.duration, o.easing, function() { 11356 11357 // Restore children 11358 if ( restore ) { 11359 $.effects.restore( child, props2 ); 11360 } 11361 }); 11362 }); 11363 } 11364 11365 // Animate 11366 el.animate( el.to, { 11367 queue: false, 11368 duration: o.duration, 11369 easing: o.easing, 11370 complete: function() { 11371 if ( el.to.opacity === 0 ) { 11372 el.css( "opacity", el.from.opacity ); 11373 } 11374 if ( mode === "hide" ) { 11375 el.hide(); 11376 } 11377 $.effects.restore( el, props ); 11378 if ( !restore ) { 11379 11380 // we need to calculate our new positioning based on the scaling 11381 if ( position === "static" ) { 11382 el.css({ 11383 position: "relative", 11384 top: el.to.top, 11385 left: el.to.left 11386 }); 11387 } else { 11388 $.each([ "top", "left" ], function( idx, pos ) { 11389 el.css( pos, function( _, str ) { 11390 var val = parseInt( str, 10 ), 11391 toRef = idx ? el.to.left : el.to.top; 11392 11393 // if original was "auto", recalculate the new value from wrapper 11394 if ( str === "auto" ) { 11395 return toRef + "px"; 11396 } 11397 11398 return val + toRef + "px"; 11399 }); 11400 }); 11401 } 11402 } 11403 11404 $.effects.removeWrapper( el ); 11405 done(); 11406 } 11407 }); 11408 11409 }; 11410 11411 11412 /*! 11413 * jQuery UI Effects Scale 1.11.4 11414 * http://jqueryui.com 11415 * 11416 * Copyright jQuery Foundation and other contributors 11417 * Released under the MIT license. 11418 * http://jquery.org/license 11419 * 11420 * http://api.jqueryui.com/scale-effect/ 11421 */ 11422 11423 11424 var effectScale = $.effects.effect.scale = function( o, done ) { 11425 11426 // Create element 11427 var el = $( this ), 11428 options = $.extend( true, {}, o ), 11429 mode = $.effects.setMode( el, o.mode || "effect" ), 11430 percent = parseInt( o.percent, 10 ) || 11431 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), 11432 direction = o.direction || "both", 11433 origin = o.origin, 11434 original = { 11435 height: el.height(), 11436 width: el.width(), 11437 outerHeight: el.outerHeight(), 11438 outerWidth: el.outerWidth() 11439 }, 11440 factor = { 11441 y: direction !== "horizontal" ? (percent / 100) : 1, 11442 x: direction !== "vertical" ? (percent / 100) : 1 11443 }; 11444 11445 // We are going to pass this effect to the size effect: 11446 options.effect = "size"; 11447 options.queue = false; 11448 options.complete = done; 11449 11450 // Set default origin and restore for show/hide 11451 if ( mode !== "effect" ) { 11452 options.origin = origin || [ "middle", "center" ]; 11453 options.restore = true; 11454 } 11455 11456 options.from = o.from || ( mode === "show" ? { 11457 height: 0, 11458 width: 0, 11459 outerHeight: 0, 11460 outerWidth: 0 11461 } : original ); 11462 options.to = { 11463 height: original.height * factor.y, 11464 width: original.width * factor.x, 11465 outerHeight: original.outerHeight * factor.y, 11466 outerWidth: original.outerWidth * factor.x 11467 }; 11468 11469 // Fade option to support puff 11470 if ( options.fade ) { 11471 if ( mode === "show" ) { 11472 options.from.opacity = 0; 11473 options.to.opacity = 1; 11474 } 11475 if ( mode === "hide" ) { 11476 options.from.opacity = 1; 11477 options.to.opacity = 0; 11478 } 11479 } 11480 11481 // Animate 11482 el.effect( options ); 11483 11484 }; 11485 11486 11487 /*! 11488 * jQuery UI Effects Puff 1.11.4 11489 * http://jqueryui.com 11490 * 11491 * Copyright jQuery Foundation and other contributors 11492 * Released under the MIT license. 11493 * http://jquery.org/license 11494 * 11495 * http://api.jqueryui.com/puff-effect/ 11496 */ 11497 11498 11499 var effectPuff = $.effects.effect.puff = function( o, done ) { 11500 var elem = $( this ), 11501 mode = $.effects.setMode( elem, o.mode || "hide" ), 11502 hide = mode === "hide", 11503 percent = parseInt( o.percent, 10 ) || 150, 11504 factor = percent / 100, 11505 original = { 11506 height: elem.height(), 11507 width: elem.width(), 11508 outerHeight: elem.outerHeight(), 11509 outerWidth: elem.outerWidth() 11510 }; 11511 11512 $.extend( o, { 11513 effect: "scale", 11514 queue: false, 11515 fade: true, 11516 mode: mode, 11517 complete: done, 11518 percent: hide ? percent : 100, 11519 from: hide ? 11520 original : 11521 { 11522 height: original.height * factor, 11523 width: original.width * factor, 11524 outerHeight: original.outerHeight * factor, 11525 outerWidth: original.outerWidth * factor 11526 } 11527 }); 11528 11529 elem.effect( o ); 11530 }; 11531 11532 11533 /*! 11534 * jQuery UI Effects Pulsate 1.11.4 11535 * http://jqueryui.com 11536 * 11537 * Copyright jQuery Foundation and other contributors 11538 * Released under the MIT license. 11539 * http://jquery.org/license 11540 * 11541 * http://api.jqueryui.com/pulsate-effect/ 11542 */ 11543 11544 11545 var effectPulsate = $.effects.effect.pulsate = function( o, done ) { 11546 var elem = $( this ), 11547 mode = $.effects.setMode( elem, o.mode || "show" ), 11548 show = mode === "show", 11549 hide = mode === "hide", 11550 showhide = ( show || mode === "hide" ), 11551 11552 // showing or hiding leaves of the "last" animation 11553 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), 11554 duration = o.duration / anims, 11555 animateTo = 0, 11556 queue = elem.queue(), 11557 queuelen = queue.length, 11558 i; 11559 11560 if ( show || !elem.is(":visible")) { 11561 elem.css( "opacity", 0 ).show(); 11562 animateTo = 1; 11563 } 11564 11565 // anims - 1 opacity "toggles" 11566 for ( i = 1; i < anims; i++ ) { 11567 elem.animate({ 11568 opacity: animateTo 11569 }, duration, o.easing ); 11570 animateTo = 1 - animateTo; 11571 } 11572 11573 elem.animate({ 11574 opacity: animateTo 11575 }, duration, o.easing); 11576 11577 elem.queue(function() { 11578 if ( hide ) { 11579 elem.hide(); 11580 } 11581 done(); 11582 }); 11583 11584 // We just queued up "anims" animations, we need to put them next in the queue 11585 if ( queuelen > 1 ) { 11586 queue.splice.apply( queue, 11587 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); 11588 } 11589 elem.dequeue(); 11590 }; 11591 11592 11593 /*! 11594 * jQuery UI Effects Shake 1.11.4 11595 * http://jqueryui.com 11596 * 11597 * Copyright jQuery Foundation and other contributors 11598 * Released under the MIT license. 11599 * http://jquery.org/license 11600 * 11601 * http://api.jqueryui.com/shake-effect/ 11602 */ 11603 11604 11605 var effectShake = $.effects.effect.shake = function( o, done ) { 11606 11607 var el = $( this ), 11608 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 11609 mode = $.effects.setMode( el, o.mode || "effect" ), 11610 direction = o.direction || "left", 11611 distance = o.distance || 20, 11612 times = o.times || 3, 11613 anims = times * 2 + 1, 11614 speed = Math.round( o.duration / anims ), 11615 ref = (direction === "up" || direction === "down") ? "top" : "left", 11616 positiveMotion = (direction === "up" || direction === "left"), 11617 animation = {}, 11618 animation1 = {}, 11619 animation2 = {}, 11620 i, 11621 11622 // we will need to re-assemble the queue to stack our animations in place 11623 queue = el.queue(), 11624 queuelen = queue.length; 11625 11626 $.effects.save( el, props ); 11627 el.show(); 11628 $.effects.createWrapper( el ); 11629 11630 // Animation 11631 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; 11632 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; 11633 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; 11634 11635 // Animate 11636 el.animate( animation, speed, o.easing ); 11637 11638 // Shakes 11639 for ( i = 1; i < times; i++ ) { 11640 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); 11641 } 11642 el 11643 .animate( animation1, speed, o.easing ) 11644 .animate( animation, speed / 2, o.easing ) 11645 .queue(function() { 11646 if ( mode === "hide" ) { 11647 el.hide(); 11648 } 11649 $.effects.restore( el, props ); 11650 $.effects.removeWrapper( el ); 11651 done(); 11652 }); 11653 11654 // inject all the animations we just queued to be first in line (after "inprogress") 11655 if ( queuelen > 1) { 11656 queue.splice.apply( queue, 11657 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); 11658 } 11659 el.dequeue(); 11660 11661 }; 11662 11663 11664 /*! 11665 * jQuery UI Effects Slide 1.11.4 11666 * http://jqueryui.com 11667 * 11668 * Copyright jQuery Foundation and other contributors 11669 * Released under the MIT license. 11670 * http://jquery.org/license 11671 * 11672 * http://api.jqueryui.com/slide-effect/ 11673 */ 11674 11675 11676 var effectSlide = $.effects.effect.slide = function( o, done ) { 11677 11678 // Create element 11679 var el = $( this ), 11680 props = [ "position", "top", "bottom", "left", "right", "width", "height" ], 11681 mode = $.effects.setMode( el, o.mode || "show" ), 11682 show = mode === "show", 11683 direction = o.direction || "left", 11684 ref = (direction === "up" || direction === "down") ? "top" : "left", 11685 positiveMotion = (direction === "up" || direction === "left"), 11686 distance, 11687 animation = {}; 11688 11689 // Adjust 11690 $.effects.save( el, props ); 11691 el.show(); 11692 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); 11693 11694 $.effects.createWrapper( el ).css({ 11695 overflow: "hidden" 11696 }); 11697 11698 if ( show ) { 11699 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); 11700 } 11701 11702 // Animation 11703 animation[ ref ] = ( show ? 11704 ( positiveMotion ? "+=" : "-=") : 11705 ( positiveMotion ? "-=" : "+=")) + 11706 distance; 11707 11708 // Animate 11709 el.animate( animation, { 11710 queue: false, 11711 duration: o.duration, 11712 easing: o.easing, 11713 complete: function() { 11714 if ( mode === "hide" ) { 11715 el.hide(); 11716 } 11717 $.effects.restore( el, props ); 11718 $.effects.removeWrapper( el ); 11719 done(); 11720 } 11721 }); 11722 }; 11723 11724 11725 /*! 11726 * jQuery UI Effects Transfer 1.11.4 11727 * http://jqueryui.com 11728 * 11729 * Copyright jQuery Foundation and other contributors 11730 * Released under the MIT license. 11731 * http://jquery.org/license 11732 * 11733 * http://api.jqueryui.com/transfer-effect/ 11734 */ 11735 11736 11737 var effectTransfer = $.effects.effect.transfer = function( o, done ) { 11738 var elem = $( this ), 11739 target = $( o.to ), 11740 targetFixed = target.css( "position" ) === "fixed", 11741 body = $("body"), 11742 fixTop = targetFixed ? body.scrollTop() : 0, 11743 fixLeft = targetFixed ? body.scrollLeft() : 0, 11744 endPosition = target.offset(), 11745 animation = { 11746 top: endPosition.top - fixTop, 11747 left: endPosition.left - fixLeft, 11748 height: target.innerHeight(), 11749 width: target.innerWidth() 11750 }, 11751 startPosition = elem.offset(), 11752 transfer = $( "<div class='ui-effects-transfer'></div>" ) 11753 .appendTo( document.body ) 11754 .addClass( o.className ) 11755 .css({ 11756 top: startPosition.top - fixTop, 11757 left: startPosition.left - fixLeft, 11758 height: elem.innerHeight(), 11759 width: elem.innerWidth(), 11760 position: targetFixed ? "fixed" : "absolute" 11761 }) 11762 .animate( animation, o.duration, o.easing, function() { 11763 transfer.remove(); 11764 done(); 11765 }); 11766 }; 11767 11768 11769 /*! 11770 * jQuery UI Progressbar 1.11.4 11771 * http://jqueryui.com 11772 * 11773 * Copyright jQuery Foundation and other contributors 11774 * Released under the MIT license. 11775 * http://jquery.org/license 11776 * 11777 * http://api.jqueryui.com/progressbar/ 11778 */ 11779 11780 11781 var progressbar = $.widget( "ui.progressbar", { 11782 version: "1.11.4", 11783 options: { 11784 max: 100, 11785 value: 0, 11786 11787 change: null, 11788 complete: null 11789 }, 11790 11791 min: 0, 11792 11793 _create: function() { 11794 // Constrain initial value 11795 this.oldValue = this.options.value = this._constrainedValue(); 11796 11797 this.element 11798 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) 11799 .attr({ 11800 // Only set static values, aria-valuenow and aria-valuemax are 11801 // set inside _refreshValue() 11802 role: "progressbar", 11803 "aria-valuemin": this.min 11804 }); 11805 11806 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) 11807 .appendTo( this.element ); 11808 11809 this._refreshValue(); 11810 }, 11811 11812 _destroy: function() { 11813 this.element 11814 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) 11815 .removeAttr( "role" ) 11816 .removeAttr( "aria-valuemin" ) 11817 .removeAttr( "aria-valuemax" ) 11818 .removeAttr( "aria-valuenow" ); 11819 11820 this.valueDiv.remove(); 11821 }, 11822 11823 value: function( newValue ) { 11824 if ( newValue === undefined ) { 11825 return this.options.value; 11826 } 11827 11828 this.options.value = this._constrainedValue( newValue ); 11829 this._refreshValue(); 11830 }, 11831 11832 _constrainedValue: function( newValue ) { 11833 if ( newValue === undefined ) { 11834 newValue = this.options.value; 11835 } 11836 11837 this.indeterminate = newValue === false; 11838 11839 // sanitize value 11840 if ( typeof newValue !== "number" ) { 11841 newValue = 0; 11842 } 11843 11844 return this.indeterminate ? false : 11845 Math.min( this.options.max, Math.max( this.min, newValue ) ); 11846 }, 11847 11848 _setOptions: function( options ) { 11849 // Ensure "value" option is set after other values (like max) 11850 var value = options.value; 11851 delete options.value; 11852 11853 this._super( options ); 11854 11855 this.options.value = this._constrainedValue( value ); 11856 this._refreshValue(); 11857 }, 11858 11859 _setOption: function( key, value ) { 11860 if ( key === "max" ) { 11861 // Don't allow a max less than min 11862 value = Math.max( this.min, value ); 11863 } 11864 if ( key === "disabled" ) { 11865 this.element 11866 .toggleClass( "ui-state-disabled", !!value ) 11867 .attr( "aria-disabled", value ); 11868 } 11869 this._super( key, value ); 11870 }, 11871 11872 _percentage: function() { 11873 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); 11874 }, 11875 11876 _refreshValue: function() { 11877 var value = this.options.value, 11878 percentage = this._percentage(); 11879 11880 this.valueDiv 11881 .toggle( this.indeterminate || value > this.min ) 11882 .toggleClass( "ui-corner-right", value === this.options.max ) 11883 .width( percentage.toFixed(0) + "%" ); 11884 11885 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); 11886 11887 if ( this.indeterminate ) { 11888 this.element.removeAttr( "aria-valuenow" ); 11889 if ( !this.overlayDiv ) { 11890 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv ); 11891 } 11892 } else { 11893 this.element.attr({ 11894 "aria-valuemax": this.options.max, 11895 "aria-valuenow": value 11896 }); 11897 if ( this.overlayDiv ) { 11898 this.overlayDiv.remove(); 11899 this.overlayDiv = null; 11900 } 11901 } 11902 11903 if ( this.oldValue !== value ) { 11904 this.oldValue = value; 11905 this._trigger( "change" ); 11906 } 11907 if ( value === this.options.max ) { 11908 this._trigger( "complete" ); 11909 } 11910 } 11911 }); 11912 11913 11914 /*! 11915 * jQuery UI Selectable 1.11.4 11916 * http://jqueryui.com 11917 * 11918 * Copyright jQuery Foundation and other contributors 11919 * Released under the MIT license. 11920 * http://jquery.org/license 11921 * 11922 * http://api.jqueryui.com/selectable/ 11923 */ 11924 11925 11926 var selectable = $.widget("ui.selectable", $.ui.mouse, { 11927 version: "1.11.4", 11928 options: { 11929 appendTo: "body", 11930 autoRefresh: true, 11931 distance: 0, 11932 filter: "*", 11933 tolerance: "touch", 11934 11935 // callbacks 11936 selected: null, 11937 selecting: null, 11938 start: null, 11939 stop: null, 11940 unselected: null, 11941 unselecting: null 11942 }, 11943 _create: function() { 11944 var selectees, 11945 that = this; 11946 11947 this.element.addClass("ui-selectable"); 11948 11949 this.dragged = false; 11950 11951 // cache selectee children based on filter 11952 this.refresh = function() { 11953 selectees = $(that.options.filter, that.element[0]); 11954 selectees.addClass("ui-selectee"); 11955 selectees.each(function() { 11956 var $this = $(this), 11957 pos = $this.offset(); 11958 $.data(this, "selectable-item", { 11959 element: this, 11960 $element: $this, 11961 left: pos.left, 11962 top: pos.top, 11963 right: pos.left + $this.outerWidth(), 11964 bottom: pos.top + $this.outerHeight(), 11965 startselected: false, 11966 selected: $this.hasClass("ui-selected"), 11967 selecting: $this.hasClass("ui-selecting"), 11968 unselecting: $this.hasClass("ui-unselecting") 11969 }); 11970 }); 11971 }; 11972 this.refresh(); 11973 11974 this.selectees = selectees.addClass("ui-selectee"); 11975 11976 this._mouseInit(); 11977 11978 this.helper = $("<div class='ui-selectable-helper'></div>"); 11979 }, 11980 11981 _destroy: function() { 11982 this.selectees 11983 .removeClass("ui-selectee") 11984 .removeData("selectable-item"); 11985 this.element 11986 .removeClass("ui-selectable ui-selectable-disabled"); 11987 this._mouseDestroy(); 11988 }, 11989 11990 _mouseStart: function(event) { 11991 var that = this, 11992 options = this.options; 11993 11994 this.opos = [ event.pageX, event.pageY ]; 11995 11996 if (this.options.disabled) { 11997 return; 11998 } 11999 12000 this.selectees = $(options.filter, this.element[0]); 12001 12002 this._trigger("start", event); 12003 12004 $(options.appendTo).append(this.helper); 12005 // position helper (lasso) 12006 this.helper.css({ 12007 "left": event.pageX, 12008 "top": event.pageY, 12009 "width": 0, 12010 "height": 0 12011 }); 12012 12013 if (options.autoRefresh) { 12014 this.refresh(); 12015 } 12016 12017 this.selectees.filter(".ui-selected").each(function() { 12018 var selectee = $.data(this, "selectable-item"); 12019 selectee.startselected = true; 12020 if (!event.metaKey && !event.ctrlKey) { 12021 selectee.$element.removeClass("ui-selected"); 12022 selectee.selected = false; 12023 selectee.$element.addClass("ui-unselecting"); 12024 selectee.unselecting = true; 12025 // selectable UNSELECTING callback 12026 that._trigger("unselecting", event, { 12027 unselecting: selectee.element 12028 }); 12029 } 12030 }); 12031 12032 $(event.target).parents().addBack().each(function() { 12033 var doSelect, 12034 selectee = $.data(this, "selectable-item"); 12035 if (selectee) { 12036 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); 12037 selectee.$element 12038 .removeClass(doSelect ? "ui-unselecting" : "ui-selected") 12039 .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); 12040 selectee.unselecting = !doSelect; 12041 selectee.selecting = doSelect; 12042 selectee.selected = doSelect; 12043 // selectable (UN)SELECTING callback 12044 if (doSelect) { 12045 that._trigger("selecting", event, { 12046 selecting: selectee.element 12047 }); 12048 } else { 12049 that._trigger("unselecting", event, { 12050 unselecting: selectee.element 12051 }); 12052 } 12053 return false; 12054 } 12055 }); 12056 12057 }, 12058 12059 _mouseDrag: function(event) { 12060 12061 this.dragged = true; 12062 12063 if (this.options.disabled) { 12064 return; 12065 } 12066 12067 var tmp, 12068 that = this, 12069 options = this.options, 12070 x1 = this.opos[0], 12071 y1 = this.opos[1], 12072 x2 = event.pageX, 12073 y2 = event.pageY; 12074 12075 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } 12076 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } 12077 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 }); 12078 12079 this.selectees.each(function() { 12080 var selectee = $.data(this, "selectable-item"), 12081 hit = false; 12082 12083 //prevent helper from being selected if appendTo: selectable 12084 if (!selectee || selectee.element === that.element[0]) { 12085 return; 12086 } 12087 12088 if (options.tolerance === "touch") { 12089 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); 12090 } else if (options.tolerance === "fit") { 12091 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); 12092 } 12093 12094 if (hit) { 12095 // SELECT 12096 if (selectee.selected) { 12097 selectee.$element.removeClass("ui-selected"); 12098 selectee.selected = false; 12099 } 12100 if (selectee.unselecting) { 12101 selectee.$element.removeClass("ui-unselecting"); 12102 selectee.unselecting = false; 12103 } 12104 if (!selectee.selecting) { 12105 selectee.$element.addClass("ui-selecting"); 12106 selectee.selecting = true; 12107 // selectable SELECTING callback 12108 that._trigger("selecting", event, { 12109 selecting: selectee.element 12110 }); 12111 } 12112 } else { 12113 // UNSELECT 12114 if (selectee.selecting) { 12115 if ((event.metaKey || event.ctrlKey) && selectee.startselected) { 12116 selectee.$element.removeClass("ui-selecting"); 12117 selectee.selecting = false; 12118 selectee.$element.addClass("ui-selected"); 12119 selectee.selected = true; 12120 } else { 12121 selectee.$element.removeClass("ui-selecting"); 12122 selectee.selecting = false; 12123 if (selectee.startselected) { 12124 selectee.$element.addClass("ui-unselecting"); 12125 selectee.unselecting = true; 12126 } 12127 // selectable UNSELECTING callback 12128 that._trigger("unselecting", event, { 12129 unselecting: selectee.element 12130 }); 12131 } 12132 } 12133 if (selectee.selected) { 12134 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { 12135 selectee.$element.removeClass("ui-selected"); 12136 selectee.selected = false; 12137 12138 selectee.$element.addClass("ui-unselecting"); 12139 selectee.unselecting = true; 12140 // selectable UNSELECTING callback 12141 that._trigger("unselecting", event, { 12142 unselecting: selectee.element 12143 }); 12144 } 12145 } 12146 } 12147 }); 12148 12149 return false; 12150 }, 12151 12152 _mouseStop: function(event) { 12153 var that = this; 12154 12155 this.dragged = false; 12156 12157 $(".ui-unselecting", this.element[0]).each(function() { 12158 var selectee = $.data(this, "selectable-item"); 12159 selectee.$element.removeClass("ui-unselecting"); 12160 selectee.unselecting = false; 12161 selectee.startselected = false; 12162 that._trigger("unselected", event, { 12163 unselected: selectee.element 12164 }); 12165 }); 12166 $(".ui-selecting", this.element[0]).each(function() { 12167 var selectee = $.data(this, "selectable-item"); 12168 selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); 12169 selectee.selecting = false; 12170 selectee.selected = true; 12171 selectee.startselected = true; 12172 that._trigger("selected", event, { 12173 selected: selectee.element 12174 }); 12175 }); 12176 this._trigger("stop", event); 12177 12178 this.helper.remove(); 12179 12180 return false; 12181 } 12182 12183 }); 12184 12185 12186 /*! 12187 * jQuery UI Selectmenu 1.11.4 12188 * http://jqueryui.com 12189 * 12190 * Copyright jQuery Foundation and other contributors 12191 * Released under the MIT license. 12192 * http://jquery.org/license 12193 * 12194 * http://api.jqueryui.com/selectmenu 12195 */ 12196 12197 12198 var selectmenu = $.widget( "ui.selectmenu", { 12199 version: "1.11.4", 12200 defaultElement: "<select>", 12201 options: { 12202 appendTo: null, 12203 disabled: null, 12204 icons: { 12205 button: "ui-icon-triangle-1-s" 12206 }, 12207 position: { 12208 my: "left top", 12209 at: "left bottom", 12210 collision: "none" 12211 }, 12212 width: null, 12213 12214 // callbacks 12215 change: null, 12216 close: null, 12217 focus: null, 12218 open: null, 12219 select: null 12220 }, 12221 12222 _create: function() { 12223 var selectmenuId = this.element.uniqueId().attr( "id" ); 12224 this.ids = { 12225 element: selectmenuId, 12226 button: selectmenuId + "-button", 12227 menu: selectmenuId + "-menu" 12228 }; 12229 12230 this._drawButton(); 12231 this._drawMenu(); 12232 12233 if ( this.options.disabled ) { 12234 this.disable(); 12235 } 12236 }, 12237 12238 _drawButton: function() { 12239 var that = this; 12240 12241 // Associate existing label with the new button 12242 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button ); 12243 this._on( this.label, { 12244 click: function( event ) { 12245 this.button.focus(); 12246 event.preventDefault(); 12247 } 12248 }); 12249 12250 // Hide original select element 12251 this.element.hide(); 12252 12253 // Create button 12254 this.button = $( "<span>", { 12255 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all", 12256 tabindex: this.options.disabled ? -1 : 0, 12257 id: this.ids.button, 12258 role: "combobox", 12259 "aria-expanded": "false", 12260 "aria-autocomplete": "list", 12261 "aria-owns": this.ids.menu, 12262 "aria-haspopup": "true" 12263 }) 12264 .insertAfter( this.element ); 12265 12266 $( "<span>", { 12267 "class": "ui-icon " + this.options.icons.button 12268 }) 12269 .prependTo( this.button ); 12270 12271 this.buttonText = $( "<span>", { 12272 "class": "ui-selectmenu-text" 12273 }) 12274 .appendTo( this.button ); 12275 12276 this._setText( this.buttonText, this.element.find( "option:selected" ).text() ); 12277 this._resizeButton(); 12278 12279 this._on( this.button, this._buttonEvents ); 12280 this.button.one( "focusin", function() { 12281 12282 // Delay rendering the menu items until the button receives focus. 12283 // The menu may have already been rendered via a programmatic open. 12284 if ( !that.menuItems ) { 12285 that._refreshMenu(); 12286 } 12287 }); 12288 this._hoverable( this.button ); 12289 this._focusable( this.button ); 12290 }, 12291 12292 _drawMenu: function() { 12293 var that = this; 12294 12295 // Create menu 12296 this.menu = $( "<ul>", { 12297 "aria-hidden": "true", 12298 "aria-labelledby": this.ids.button, 12299 id: this.ids.menu 12300 }); 12301 12302 // Wrap menu 12303 this.menuWrap = $( "<div>", { 12304 "class": "ui-selectmenu-menu ui-front" 12305 }) 12306 .append( this.menu ) 12307 .appendTo( this._appendTo() ); 12308 12309 // Initialize menu widget 12310 this.menuInstance = this.menu 12311 .menu({ 12312 role: "listbox", 12313 select: function( event, ui ) { 12314 event.preventDefault(); 12315 12316 // support: IE8 12317 // If the item was selected via a click, the text selection 12318 // will be destroyed in IE 12319 that._setSelection(); 12320 12321 that._select( ui.item.data( "ui-selectmenu-item" ), event ); 12322 }, 12323 focus: function( event, ui ) { 12324 var item = ui.item.data( "ui-selectmenu-item" ); 12325 12326 // Prevent inital focus from firing and check if its a newly focused item 12327 if ( that.focusIndex != null && item.index !== that.focusIndex ) { 12328 that._trigger( "focus", event, { item: item } ); 12329 if ( !that.isOpen ) { 12330 that._select( item, event ); 12331 } 12332 } 12333 that.focusIndex = item.index; 12334 12335 that.button.attr( "aria-activedescendant", 12336 that.menuItems.eq( item.index ).attr( "id" ) ); 12337 } 12338 }) 12339 .menu( "instance" ); 12340 12341 // Adjust menu styles to dropdown 12342 this.menu 12343 .addClass( "ui-corner-bottom" ) 12344 .removeClass( "ui-corner-all" ); 12345 12346 // Don't close the menu on mouseleave 12347 this.menuInstance._off( this.menu, "mouseleave" ); 12348 12349 // Cancel the menu's collapseAll on document click 12350 this.menuInstance._closeOnDocumentClick = function() { 12351 return false; 12352 }; 12353 12354 // Selects often contain empty items, but never contain dividers 12355 this.menuInstance._isDivider = function() { 12356 return false; 12357 }; 12358 }, 12359 12360 refresh: function() { 12361 this._refreshMenu(); 12362 this._setText( this.buttonText, this._getSelectedItem().text() ); 12363 if ( !this.options.width ) { 12364 this._resizeButton(); 12365 } 12366 }, 12367 12368 _refreshMenu: function() { 12369 this.menu.empty(); 12370 12371 var item, 12372 options = this.element.find( "option" ); 12373 12374 if ( !options.length ) { 12375 return; 12376 } 12377 12378 this._parseOptions( options ); 12379 this._renderMenu( this.menu, this.items ); 12380 12381 this.menuInstance.refresh(); 12382 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" ); 12383 12384 item = this._getSelectedItem(); 12385 12386 // Update the menu to have the correct item focused 12387 this.menuInstance.focus( null, item ); 12388 this._setAria( item.data( "ui-selectmenu-item" ) ); 12389 12390 // Set disabled state 12391 this._setOption( "disabled", this.element.prop( "disabled" ) ); 12392 }, 12393 12394 open: function( event ) { 12395 if ( this.options.disabled ) { 12396 return; 12397 } 12398 12399 // If this is the first time the menu is being opened, render the items 12400 if ( !this.menuItems ) { 12401 this._refreshMenu(); 12402 } else { 12403 12404 // Menu clears focus on close, reset focus to selected item 12405 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" ); 12406 this.menuInstance.focus( null, this._getSelectedItem() ); 12407 } 12408 12409 this.isOpen = true; 12410 this._toggleAttr(); 12411 this._resizeMenu(); 12412 this._position(); 12413 12414 this._on( this.document, this._documentClick ); 12415 12416 this._trigger( "open", event ); 12417 }, 12418 12419 _position: function() { 12420 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); 12421 }, 12422 12423 close: function( event ) { 12424 if ( !this.isOpen ) { 12425 return; 12426 } 12427 12428 this.isOpen = false; 12429 this._toggleAttr(); 12430 12431 this.range = null; 12432 this._off( this.document ); 12433 12434 this._trigger( "close", event ); 12435 }, 12436 12437 widget: function() { 12438 return this.button; 12439 }, 12440 12441 menuWidget: function() { 12442 return this.menu; 12443 }, 12444 12445 _renderMenu: function( ul, items ) { 12446 var that = this, 12447 currentOptgroup = ""; 12448 12449 $.each( items, function( index, item ) { 12450 if ( item.optgroup !== currentOptgroup ) { 12451 $( "<li>", { 12452 "class": "ui-selectmenu-optgroup ui-menu-divider" + 12453 ( item.element.parent( "optgroup" ).prop( "disabled" ) ? 12454 " ui-state-disabled" : 12455 "" ), 12456 text: item.optgroup 12457 }) 12458 .appendTo( ul ); 12459 12460 currentOptgroup = item.optgroup; 12461 } 12462 12463 that._renderItemData( ul, item ); 12464 }); 12465 }, 12466 12467 _renderItemData: function( ul, item ) { 12468 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); 12469 }, 12470 12471 _renderItem: function( ul, item ) { 12472 var li = $( "<li>" ); 12473 12474 if ( item.disabled ) { 12475 li.addClass( "ui-state-disabled" ); 12476 } 12477 this._setText( li, item.label ); 12478 12479 return li.appendTo( ul ); 12480 }, 12481 12482 _setText: function( element, value ) { 12483 if ( value ) { 12484 element.text( value ); 12485 } else { 12486 element.html( " " ); 12487 } 12488 }, 12489 12490 _move: function( direction, event ) { 12491 var item, next, 12492 filter = ".ui-menu-item"; 12493 12494 if ( this.isOpen ) { 12495 item = this.menuItems.eq( this.focusIndex ); 12496 } else { 12497 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ); 12498 filter += ":not(.ui-state-disabled)"; 12499 } 12500 12501 if ( direction === "first" || direction === "last" ) { 12502 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); 12503 } else { 12504 next = item[ direction + "All" ]( filter ).eq( 0 ); 12505 } 12506 12507 if ( next.length ) { 12508 this.menuInstance.focus( event, next ); 12509 } 12510 }, 12511 12512 _getSelectedItem: function() { 12513 return this.menuItems.eq( this.element[ 0 ].selectedIndex ); 12514 }, 12515 12516 _toggle: function( event ) { 12517 this[ this.isOpen ? "close" : "open" ]( event ); 12518 }, 12519 12520 _setSelection: function() { 12521 var selection; 12522 12523 if ( !this.range ) { 12524 return; 12525 } 12526 12527 if ( window.getSelection ) { 12528 selection = window.getSelection(); 12529 selection.removeAllRanges(); 12530 selection.addRange( this.range ); 12531 12532 // support: IE8 12533 } else { 12534 this.range.select(); 12535 } 12536 12537 // support: IE 12538 // Setting the text selection kills the button focus in IE, but 12539 // restoring the focus doesn't kill the selection. 12540 this.button.focus(); 12541 }, 12542 12543 _documentClick: { 12544 mousedown: function( event ) { 12545 if ( !this.isOpen ) { 12546 return; 12547 } 12548 12549 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) { 12550 this.close( event ); 12551 } 12552 } 12553 }, 12554 12555 _buttonEvents: { 12556 12557 // Prevent text selection from being reset when interacting with the selectmenu (#10144) 12558 mousedown: function() { 12559 var selection; 12560 12561 if ( window.getSelection ) { 12562 selection = window.getSelection(); 12563 if ( selection.rangeCount ) { 12564 this.range = selection.getRangeAt( 0 ); 12565 } 12566 12567 // support: IE8 12568 } else { 12569 this.range = document.selection.createRange(); 12570 } 12571 }, 12572 12573 click: function( event ) { 12574 this._setSelection(); 12575 this._toggle( event ); 12576 }, 12577 12578 keydown: function( event ) { 12579 var preventDefault = true; 12580 switch ( event.keyCode ) { 12581 case $.ui.keyCode.TAB: 12582 case $.ui.keyCode.ESCAPE: 12583 this.close( event ); 12584 preventDefault = false; 12585 break; 12586 case $.ui.keyCode.ENTER: 12587 if ( this.isOpen ) { 12588 this._selectFocusedItem( event ); 12589 } 12590 break; 12591 case $.ui.keyCode.UP: 12592 if ( event.altKey ) { 12593 this._toggle( event ); 12594 } else { 12595 this._move( "prev", event ); 12596 } 12597 break; 12598 case $.ui.keyCode.DOWN: 12599 if ( event.altKey ) { 12600 this._toggle( event ); 12601 } else { 12602 this._move( "next", event ); 12603 } 12604 break; 12605 case $.ui.keyCode.SPACE: 12606 if ( this.isOpen ) { 12607 this._selectFocusedItem( event ); 12608 } else { 12609 this._toggle( event ); 12610 } 12611 break; 12612 case $.ui.keyCode.LEFT: 12613 this._move( "prev", event ); 12614 break; 12615 case $.ui.keyCode.RIGHT: 12616 this._move( "next", event ); 12617 break; 12618 case $.ui.keyCode.HOME: 12619 case $.ui.keyCode.PAGE_UP: 12620 this._move( "first", event ); 12621 break; 12622 case $.ui.keyCode.END: 12623 case $.ui.keyCode.PAGE_DOWN: 12624 this._move( "last", event ); 12625 break; 12626 default: 12627 this.menu.trigger( event ); 12628 preventDefault = false; 12629 } 12630 12631 if ( preventDefault ) { 12632 event.preventDefault(); 12633 } 12634 } 12635 }, 12636 12637 _selectFocusedItem: function( event ) { 12638 var item = this.menuItems.eq( this.focusIndex ); 12639 if ( !item.hasClass( "ui-state-disabled" ) ) { 12640 this._select( item.data( "ui-selectmenu-item" ), event ); 12641 } 12642 }, 12643 12644 _select: function( item, event ) { 12645 var oldIndex = this.element[ 0 ].selectedIndex; 12646 12647 // Change native select element 12648 this.element[ 0 ].selectedIndex = item.index; 12649 this._setText( this.buttonText, item.label ); 12650 this._setAria( item ); 12651 this._trigger( "select", event, { item: item } ); 12652 12653 if ( item.index !== oldIndex ) { 12654 this._trigger( "change", event, { item: item } ); 12655 } 12656 12657 this.close( event ); 12658 }, 12659 12660 _setAria: function( item ) { 12661 var id = this.menuItems.eq( item.index ).attr( "id" ); 12662 12663 this.button.attr({ 12664 "aria-labelledby": id, 12665 "aria-activedescendant": id 12666 }); 12667 this.menu.attr( "aria-activedescendant", id ); 12668 }, 12669 12670 _setOption: function( key, value ) { 12671 if ( key === "icons" ) { 12672 this.button.find( "span.ui-icon" ) 12673 .removeClass( this.options.icons.button ) 12674 .addClass( value.button ); 12675 } 12676 12677 this._super( key, value ); 12678 12679 if ( key === "appendTo" ) { 12680 this.menuWrap.appendTo( this._appendTo() ); 12681 } 12682 12683 if ( key === "disabled" ) { 12684 this.menuInstance.option( "disabled", value ); 12685 this.button 12686 .toggleClass( "ui-state-disabled", value ) 12687 .attr( "aria-disabled", value ); 12688 12689 this.element.prop( "disabled", value ); 12690 if ( value ) { 12691 this.button.attr( "tabindex", -1 ); 12692 this.close(); 12693 } else { 12694 this.button.attr( "tabindex", 0 ); 12695 } 12696 } 12697 12698 if ( key === "width" ) { 12699 this._resizeButton(); 12700 } 12701 }, 12702 12703 _appendTo: function() { 12704 var element = this.options.appendTo; 12705 12706 if ( element ) { 12707 element = element.jquery || element.nodeType ? 12708 $( element ) : 12709 this.document.find( element ).eq( 0 ); 12710 } 12711 12712 if ( !element || !element[ 0 ] ) { 12713 element = this.element.closest( ".ui-front" ); 12714 } 12715 12716 if ( !element.length ) { 12717 element = this.document[ 0 ].body; 12718 } 12719 12720 return element; 12721 }, 12722 12723 _toggleAttr: function() { 12724 this.button 12725 .toggleClass( "ui-corner-top", this.isOpen ) 12726 .toggleClass( "ui-corner-all", !this.isOpen ) 12727 .attr( "aria-expanded", this.isOpen ); 12728 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen ); 12729 this.menu.attr( "aria-hidden", !this.isOpen ); 12730 }, 12731 12732 _resizeButton: function() { 12733 var width = this.options.width; 12734 12735 if ( !width ) { 12736 width = this.element.show().outerWidth(); 12737 this.element.hide(); 12738 } 12739 12740 this.button.outerWidth( width ); 12741 }, 12742 12743 _resizeMenu: function() { 12744 this.menu.outerWidth( Math.max( 12745 this.button.outerWidth(), 12746 12747 // support: IE10 12748 // IE10 wraps long text (possibly a rounding bug) 12749 // so we add 1px to avoid the wrapping 12750 this.menu.width( "" ).outerWidth() + 1 12751 ) ); 12752 }, 12753 12754 _getCreateOptions: function() { 12755 return { disabled: this.element.prop( "disabled" ) }; 12756 }, 12757 12758 _parseOptions: function( options ) { 12759 var data = []; 12760 options.each(function( index, item ) { 12761 var option = $( item ), 12762 optgroup = option.parent( "optgroup" ); 12763 data.push({ 12764 element: option, 12765 index: index, 12766 value: option.val(), 12767 label: option.text(), 12768 optgroup: optgroup.attr( "label" ) || "", 12769 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) 12770 }); 12771 }); 12772 this.items = data; 12773 }, 12774 12775 _destroy: function() { 12776 this.menuWrap.remove(); 12777 this.button.remove(); 12778 this.element.show(); 12779 this.element.removeUniqueId(); 12780 this.label.attr( "for", this.ids.element ); 12781 } 12782 }); 12783 12784 12785 /*! 12786 * jQuery UI Slider 1.11.4 12787 * http://jqueryui.com 12788 * 12789 * Copyright jQuery Foundation and other contributors 12790 * Released under the MIT license. 12791 * http://jquery.org/license 12792 * 12793 * http://api.jqueryui.com/slider/ 12794 */ 12795 12796 12797 var slider = $.widget( "ui.slider", $.ui.mouse, { 12798 version: "1.11.4", 12799 widgetEventPrefix: "slide", 12800 12801 options: { 12802 animate: false, 12803 distance: 0, 12804 max: 100, 12805 min: 0, 12806 orientation: "horizontal", 12807 range: false, 12808 step: 1, 12809 value: 0, 12810 values: null, 12811 12812 // callbacks 12813 change: null, 12814 slide: null, 12815 start: null, 12816 stop: null 12817 }, 12818 12819 // number of pages in a slider 12820 // (how many times can you page up/down to go through the whole range) 12821 numPages: 5, 12822 12823 _create: function() { 12824 this._keySliding = false; 12825 this._mouseSliding = false; 12826 this._animateOff = true; 12827 this._handleIndex = null; 12828 this._detectOrientation(); 12829 this._mouseInit(); 12830 this._calculateNewMax(); 12831 12832 this.element 12833 .addClass( "ui-slider" + 12834 " ui-slider-" + this.orientation + 12835 " ui-widget" + 12836 " ui-widget-content" + 12837 " ui-corner-all"); 12838 12839 this._refresh(); 12840 this._setOption( "disabled", this.options.disabled ); 12841 12842 this._animateOff = false; 12843 }, 12844 12845 _refresh: function() { 12846 this._createRange(); 12847 this._createHandles(); 12848 this._setupEvents(); 12849 this._refreshValue(); 12850 }, 12851 12852 _createHandles: function() { 12853 var i, handleCount, 12854 options = this.options, 12855 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), 12856 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>", 12857 handles = []; 12858 12859 handleCount = ( options.values && options.values.length ) || 1; 12860 12861 if ( existingHandles.length > handleCount ) { 12862 existingHandles.slice( handleCount ).remove(); 12863 existingHandles = existingHandles.slice( 0, handleCount ); 12864 } 12865 12866 for ( i = existingHandles.length; i < handleCount; i++ ) { 12867 handles.push( handle ); 12868 } 12869 12870 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 12871 12872 this.handle = this.handles.eq( 0 ); 12873 12874 this.handles.each(function( i ) { 12875 $( this ).data( "ui-slider-handle-index", i ); 12876 }); 12877 }, 12878 12879 _createRange: function() { 12880 var options = this.options, 12881 classes = ""; 12882 12883 if ( options.range ) { 12884 if ( options.range === true ) { 12885 if ( !options.values ) { 12886 options.values = [ this._valueMin(), this._valueMin() ]; 12887 } else if ( options.values.length && options.values.length !== 2 ) { 12888 options.values = [ options.values[0], options.values[0] ]; 12889 } else if ( $.isArray( options.values ) ) { 12890 options.values = options.values.slice(0); 12891 } 12892 } 12893 12894 if ( !this.range || !this.range.length ) { 12895 this.range = $( "<div></div>" ) 12896 .appendTo( this.element ); 12897 12898 classes = "ui-slider-range" + 12899 // note: this isn't the most fittingly semantic framework class for this element, 12900 // but worked best visually with a variety of themes 12901 " ui-widget-header ui-corner-all"; 12902 } else { 12903 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) 12904 // Handle range switching from true to min/max 12905 .css({ 12906 "left": "", 12907 "bottom": "" 12908 }); 12909 } 12910 12911 this.range.addClass( classes + 12912 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); 12913 } else { 12914 if ( this.range ) { 12915 this.range.remove(); 12916 } 12917 this.range = null; 12918 } 12919 }, 12920 12921 _setupEvents: function() { 12922 this._off( this.handles ); 12923 this._on( this.handles, this._handleEvents ); 12924 this._hoverable( this.handles ); 12925 this._focusable( this.handles ); 12926 }, 12927 12928 _destroy: function() { 12929 this.handles.remove(); 12930 if ( this.range ) { 12931 this.range.remove(); 12932 } 12933 12934 this.element 12935 .removeClass( "ui-slider" + 12936 " ui-slider-horizontal" + 12937 " ui-slider-vertical" + 12938 " ui-widget" + 12939 " ui-widget-content" + 12940 " ui-corner-all" ); 12941 12942 this._mouseDestroy(); 12943 }, 12944 12945 _mouseCapture: function( event ) { 12946 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 12947 that = this, 12948 o = this.options; 12949 12950 if ( o.disabled ) { 12951 return false; 12952 } 12953 12954 this.elementSize = { 12955 width: this.element.outerWidth(), 12956 height: this.element.outerHeight() 12957 }; 12958 this.elementOffset = this.element.offset(); 12959 12960 position = { x: event.pageX, y: event.pageY }; 12961 normValue = this._normValueFromMouse( position ); 12962 distance = this._valueMax() - this._valueMin() + 1; 12963 this.handles.each(function( i ) { 12964 var thisDistance = Math.abs( normValue - that.values(i) ); 12965 if (( distance > thisDistance ) || 12966 ( distance === thisDistance && 12967 (i === that._lastChangedValue || that.values(i) === o.min ))) { 12968 distance = thisDistance; 12969 closestHandle = $( this ); 12970 index = i; 12971 } 12972 }); 12973 12974 allowed = this._start( event, index ); 12975 if ( allowed === false ) { 12976 return false; 12977 } 12978 this._mouseSliding = true; 12979 12980 this._handleIndex = index; 12981 12982 closestHandle 12983 .addClass( "ui-state-active" ) 12984 .focus(); 12985 12986 offset = closestHandle.offset(); 12987 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 12988 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 12989 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 12990 top: event.pageY - offset.top - 12991 ( closestHandle.height() / 2 ) - 12992 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - 12993 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + 12994 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) 12995 }; 12996 12997 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 12998 this._slide( event, index, normValue ); 12999 } 13000 this._animateOff = true; 13001 return true; 13002 }, 13003 13004 _mouseStart: function() { 13005 return true; 13006 }, 13007 13008 _mouseDrag: function( event ) { 13009 var position = { x: event.pageX, y: event.pageY }, 13010 normValue = this._normValueFromMouse( position ); 13011 13012 this._slide( event, this._handleIndex, normValue ); 13013 13014 return false; 13015 }, 13016 13017 _mouseStop: function( event ) { 13018 this.handles.removeClass( "ui-state-active" ); 13019 this._mouseSliding = false; 13020 13021 this._stop( event, this._handleIndex ); 13022 this._change( event, this._handleIndex ); 13023 13024 this._handleIndex = null; 13025 this._clickOffset = null; 13026 this._animateOff = false; 13027 13028 return false; 13029 }, 13030 13031 _detectOrientation: function() { 13032 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 13033 }, 13034 13035 _normValueFromMouse: function( position ) { 13036 var pixelTotal, 13037 pixelMouse, 13038 percentMouse, 13039 valueTotal, 13040 valueMouse; 13041 13042 if ( this.orientation === "horizontal" ) { 13043 pixelTotal = this.elementSize.width; 13044 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); 13045 } else { 13046 pixelTotal = this.elementSize.height; 13047 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); 13048 } 13049 13050 percentMouse = ( pixelMouse / pixelTotal ); 13051 if ( percentMouse > 1 ) { 13052 percentMouse = 1; 13053 } 13054 if ( percentMouse < 0 ) { 13055 percentMouse = 0; 13056 } 13057 if ( this.orientation === "vertical" ) { 13058 percentMouse = 1 - percentMouse; 13059 } 13060 13061 valueTotal = this._valueMax() - this._valueMin(); 13062 valueMouse = this._valueMin() + percentMouse * valueTotal; 13063 13064 return this._trimAlignValue( valueMouse ); 13065 }, 13066 13067 _start: function( event, index ) { 13068 var uiHash = { 13069 handle: this.handles[ index ], 13070 value: this.value() 13071 }; 13072 if ( this.options.values && this.options.values.length ) { 13073 uiHash.value = this.values( index ); 13074 uiHash.values = this.values(); 13075 } 13076 return this._trigger( "start", event, uiHash ); 13077 }, 13078 13079 _slide: function( event, index, newVal ) { 13080 var otherVal, 13081 newValues, 13082 allowed; 13083 13084 if ( this.options.values && this.options.values.length ) { 13085 otherVal = this.values( index ? 0 : 1 ); 13086 13087 if ( ( this.options.values.length === 2 && this.options.range === true ) && 13088 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) 13089 ) { 13090 newVal = otherVal; 13091 } 13092 13093 if ( newVal !== this.values( index ) ) { 13094 newValues = this.values(); 13095 newValues[ index ] = newVal; 13096 // A slide can be canceled by returning false from the slide callback 13097 allowed = this._trigger( "slide", event, { 13098 handle: this.handles[ index ], 13099 value: newVal, 13100 values: newValues 13101 } ); 13102 otherVal = this.values( index ? 0 : 1 ); 13103 if ( allowed !== false ) { 13104 this.values( index, newVal ); 13105 } 13106 } 13107 } else { 13108 if ( newVal !== this.value() ) { 13109 // A slide can be canceled by returning false from the slide callback 13110 allowed = this._trigger( "slide", event, { 13111 handle: this.handles[ index ], 13112 value: newVal 13113 } ); 13114 if ( allowed !== false ) { 13115 this.value( newVal ); 13116 } 13117 } 13118 } 13119 }, 13120 13121 _stop: function( event, index ) { 13122 var uiHash = { 13123 handle: this.handles[ index ], 13124 value: this.value() 13125 }; 13126 if ( this.options.values && this.options.values.length ) { 13127 uiHash.value = this.values( index ); 13128 uiHash.values = this.values(); 13129 } 13130 13131 this._trigger( "stop", event, uiHash ); 13132 }, 13133 13134 _change: function( event, index ) { 13135 if ( !this._keySliding && !this._mouseSliding ) { 13136 var uiHash = { 13137 handle: this.handles[ index ], 13138 value: this.value() 13139 }; 13140 if ( this.options.values && this.options.values.length ) { 13141 uiHash.value = this.values( index ); 13142 uiHash.values = this.values(); 13143 } 13144 13145 //store the last changed value index for reference when handles overlap 13146 this._lastChangedValue = index; 13147 13148 this._trigger( "change", event, uiHash ); 13149 } 13150 }, 13151 13152 value: function( newValue ) { 13153 if ( arguments.length ) { 13154 this.options.value = this._trimAlignValue( newValue ); 13155 this._refreshValue(); 13156 this._change( null, 0 ); 13157 return; 13158 } 13159 13160 return this._value(); 13161 }, 13162 13163 values: function( index, newValue ) { 13164 var vals, 13165 newValues, 13166 i; 13167 13168 if ( arguments.length > 1 ) { 13169 this.options.values[ index ] = this._trimAlignValue( newValue ); 13170 this._refreshValue(); 13171 this._change( null, index ); 13172 return; 13173 } 13174 13175 if ( arguments.length ) { 13176 if ( $.isArray( arguments[ 0 ] ) ) { 13177 vals = this.options.values; 13178 newValues = arguments[ 0 ]; 13179 for ( i = 0; i < vals.length; i += 1 ) { 13180 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 13181 this._change( null, i ); 13182 } 13183 this._refreshValue(); 13184 } else { 13185 if ( this.options.values && this.options.values.length ) { 13186 return this._values( index ); 13187 } else { 13188 return this.value(); 13189 } 13190 } 13191 } else { 13192 return this._values(); 13193 } 13194 }, 13195 13196 _setOption: function( key, value ) { 13197 var i, 13198 valsLength = 0; 13199 13200 if ( key === "range" && this.options.range === true ) { 13201 if ( value === "min" ) { 13202 this.options.value = this._values( 0 ); 13203 this.options.values = null; 13204 } else if ( value === "max" ) { 13205 this.options.value = this._values( this.options.values.length - 1 ); 13206 this.options.values = null; 13207 } 13208 } 13209 13210 if ( $.isArray( this.options.values ) ) { 13211 valsLength = this.options.values.length; 13212 } 13213 13214 if ( key === "disabled" ) { 13215 this.element.toggleClass( "ui-state-disabled", !!value ); 13216 } 13217 13218 this._super( key, value ); 13219 13220 switch ( key ) { 13221 case "orientation": 13222 this._detectOrientation(); 13223 this.element 13224 .removeClass( "ui-slider-horizontal ui-slider-vertical" ) 13225 .addClass( "ui-slider-" + this.orientation ); 13226 this._refreshValue(); 13227 13228 // Reset positioning from previous orientation 13229 this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); 13230 break; 13231 case "value": 13232 this._animateOff = true; 13233 this._refreshValue(); 13234 this._change( null, 0 ); 13235 this._animateOff = false; 13236 break; 13237 case "values": 13238 this._animateOff = true; 13239 this._refreshValue(); 13240 for ( i = 0; i < valsLength; i += 1 ) { 13241 this._change( null, i ); 13242 } 13243 this._animateOff = false; 13244 break; 13245 case "step": 13246 case "min": 13247 case "max": 13248 this._animateOff = true; 13249 this._calculateNewMax(); 13250 this._refreshValue(); 13251 this._animateOff = false; 13252 break; 13253 case "range": 13254 this._animateOff = true; 13255 this._refresh(); 13256 this._animateOff = false; 13257 break; 13258 } 13259 }, 13260 13261 //internal value getter 13262 // _value() returns value trimmed by min and max, aligned by step 13263 _value: function() { 13264 var val = this.options.value; 13265 val = this._trimAlignValue( val ); 13266 13267 return val; 13268 }, 13269 13270 //internal values getter 13271 // _values() returns array of values trimmed by min and max, aligned by step 13272 // _values( index ) returns single value trimmed by min and max, aligned by step 13273 _values: function( index ) { 13274 var val, 13275 vals, 13276 i; 13277 13278 if ( arguments.length ) { 13279 val = this.options.values[ index ]; 13280 val = this._trimAlignValue( val ); 13281 13282 return val; 13283 } else if ( this.options.values && this.options.values.length ) { 13284 // .slice() creates a copy of the array 13285 // this copy gets trimmed by min and max and then returned 13286 vals = this.options.values.slice(); 13287 for ( i = 0; i < vals.length; i += 1) { 13288 vals[ i ] = this._trimAlignValue( vals[ i ] ); 13289 } 13290 13291 return vals; 13292 } else { 13293 return []; 13294 } 13295 }, 13296 13297 // returns the step-aligned value that val is closest to, between (inclusive) min and max 13298 _trimAlignValue: function( val ) { 13299 if ( val <= this._valueMin() ) { 13300 return this._valueMin(); 13301 } 13302 if ( val >= this._valueMax() ) { 13303 return this._valueMax(); 13304 } 13305 var step = ( this.options.step > 0 ) ? this.options.step : 1, 13306 valModStep = (val - this._valueMin()) % step, 13307 alignValue = val - valModStep; 13308 13309 if ( Math.abs(valModStep) * 2 >= step ) { 13310 alignValue += ( valModStep > 0 ) ? step : ( -step ); 13311 } 13312 13313 // Since JavaScript has problems with large floats, round 13314 // the final value to 5 digits after the decimal point (see #4124) 13315 return parseFloat( alignValue.toFixed(5) ); 13316 }, 13317 13318 _calculateNewMax: function() { 13319 var max = this.options.max, 13320 min = this._valueMin(), 13321 step = this.options.step, 13322 aboveMin = Math.floor( ( +( max - min ).toFixed( this._precision() ) ) / step ) * step; 13323 max = aboveMin + min; 13324 this.max = parseFloat( max.toFixed( this._precision() ) ); 13325 }, 13326 13327 _precision: function() { 13328 var precision = this._precisionOf( this.options.step ); 13329 if ( this.options.min !== null ) { 13330 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 13331 } 13332 return precision; 13333 }, 13334 13335 _precisionOf: function( num ) { 13336 var str = num.toString(), 13337 decimal = str.indexOf( "." ); 13338 return decimal === -1 ? 0 : str.length - decimal - 1; 13339 }, 13340 13341 _valueMin: function() { 13342 return this.options.min; 13343 }, 13344 13345 _valueMax: function() { 13346 return this.max; 13347 }, 13348 13349 _refreshValue: function() { 13350 var lastValPercent, valPercent, value, valueMin, valueMax, 13351 oRange = this.options.range, 13352 o = this.options, 13353 that = this, 13354 animate = ( !this._animateOff ) ? o.animate : false, 13355 _set = {}; 13356 13357 if ( this.options.values && this.options.values.length ) { 13358 this.handles.each(function( i ) { 13359 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; 13360 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 13361 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 13362 if ( that.options.range === true ) { 13363 if ( that.orientation === "horizontal" ) { 13364 if ( i === 0 ) { 13365 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); 13366 } 13367 if ( i === 1 ) { 13368 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 13369 } 13370 } else { 13371 if ( i === 0 ) { 13372 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); 13373 } 13374 if ( i === 1 ) { 13375 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 13376 } 13377 } 13378 } 13379 lastValPercent = valPercent; 13380 }); 13381 } else { 13382 value = this.value(); 13383 valueMin = this._valueMin(); 13384 valueMax = this._valueMax(); 13385 valPercent = ( valueMax !== valueMin ) ? 13386 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 13387 0; 13388 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 13389 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 13390 13391 if ( oRange === "min" && this.orientation === "horizontal" ) { 13392 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); 13393 } 13394 if ( oRange === "max" && this.orientation === "horizontal" ) { 13395 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 13396 } 13397 if ( oRange === "min" && this.orientation === "vertical" ) { 13398 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); 13399 } 13400 if ( oRange === "max" && this.orientation === "vertical" ) { 13401 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 13402 } 13403 } 13404 }, 13405 13406 _handleEvents: { 13407 keydown: function( event ) { 13408 var allowed, curVal, newVal, step, 13409 index = $( event.target ).data( "ui-slider-handle-index" ); 13410 13411 switch ( event.keyCode ) { 13412 case $.ui.keyCode.HOME: 13413 case $.ui.keyCode.END: 13414 case $.ui.keyCode.PAGE_UP: 13415 case $.ui.keyCode.PAGE_DOWN: 13416 case $.ui.keyCode.UP: 13417 case $.ui.keyCode.RIGHT: 13418 case $.ui.keyCode.DOWN: 13419 case $.ui.keyCode.LEFT: 13420 event.preventDefault(); 13421 if ( !this._keySliding ) { 13422 this._keySliding = true; 13423 $( event.target ).addClass( "ui-state-active" ); 13424 allowed = this._start( event, index ); 13425 if ( allowed === false ) { 13426 return; 13427 } 13428 } 13429 break; 13430 } 13431 13432 step = this.options.step; 13433 if ( this.options.values && this.options.values.length ) { 13434 curVal = newVal = this.values( index ); 13435 } else { 13436 curVal = newVal = this.value(); 13437 } 13438 13439 switch ( event.keyCode ) { 13440 case $.ui.keyCode.HOME: 13441 newVal = this._valueMin(); 13442 break; 13443 case $.ui.keyCode.END: 13444 newVal = this._valueMax(); 13445 break; 13446 case $.ui.keyCode.PAGE_UP: 13447 newVal = this._trimAlignValue( 13448 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) 13449 ); 13450 break; 13451 case $.ui.keyCode.PAGE_DOWN: 13452 newVal = this._trimAlignValue( 13453 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) ); 13454 break; 13455 case $.ui.keyCode.UP: 13456 case $.ui.keyCode.RIGHT: 13457 if ( curVal === this._valueMax() ) { 13458 return; 13459 } 13460 newVal = this._trimAlignValue( curVal + step ); 13461 break; 13462 case $.ui.keyCode.DOWN: 13463 case $.ui.keyCode.LEFT: 13464 if ( curVal === this._valueMin() ) { 13465 return; 13466 } 13467 newVal = this._trimAlignValue( curVal - step ); 13468 break; 13469 } 13470 13471 this._slide( event, index, newVal ); 13472 }, 13473 keyup: function( event ) { 13474 var index = $( event.target ).data( "ui-slider-handle-index" ); 13475 13476 if ( this._keySliding ) { 13477 this._keySliding = false; 13478 this._stop( event, index ); 13479 this._change( event, index ); 13480 $( event.target ).removeClass( "ui-state-active" ); 13481 } 13482 } 13483 } 13484 }); 13485 13486 13487 /*! 13488 * jQuery UI Sortable 1.11.4 13489 * http://jqueryui.com 13490 * 13491 * Copyright jQuery Foundation and other contributors 13492 * Released under the MIT license. 13493 * http://jquery.org/license 13494 * 13495 * http://api.jqueryui.com/sortable/ 13496 */ 13497 13498 13499 var sortable = $.widget("ui.sortable", $.ui.mouse, { 13500 version: "1.11.4", 13501 widgetEventPrefix: "sort", 13502 ready: false, 13503 options: { 13504 appendTo: "parent", 13505 axis: false, 13506 connectWith: false, 13507 containment: false, 13508 cursor: "auto", 13509 cursorAt: false, 13510 dropOnEmpty: true, 13511 forcePlaceholderSize: false, 13512 forceHelperSize: false, 13513 grid: false, 13514 handle: false, 13515 helper: "original", 13516 items: "> *", 13517 opacity: false, 13518 placeholder: false, 13519 revert: false, 13520 scroll: true, 13521 scrollSensitivity: 20, 13522 scrollSpeed: 20, 13523 scope: "default", 13524 tolerance: "intersect", 13525 zIndex: 1000, 13526 13527 // callbacks 13528 activate: null, 13529 beforeStop: null, 13530 change: null, 13531 deactivate: null, 13532 out: null, 13533 over: null, 13534 receive: null, 13535 remove: null, 13536 sort: null, 13537 start: null, 13538 stop: null, 13539 update: null 13540 }, 13541 13542 _isOverAxis: function( x, reference, size ) { 13543 return ( x >= reference ) && ( x < ( reference + size ) ); 13544 }, 13545 13546 _isFloating: function( item ) { 13547 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); 13548 }, 13549 13550 _create: function() { 13551 this.containerCache = {}; 13552 this.element.addClass("ui-sortable"); 13553 13554 //Get the items 13555 this.refresh(); 13556 13557 //Let's determine the parent's offset 13558 this.offset = this.element.offset(); 13559 13560 //Initialize mouse events for interaction 13561 this._mouseInit(); 13562 13563 this._setHandleClassName(); 13564 13565 //We're ready to go 13566 this.ready = true; 13567 13568 }, 13569 13570 _setOption: function( key, value ) { 13571 this._super( key, value ); 13572 13573 if ( key === "handle" ) { 13574 this._setHandleClassName(); 13575 } 13576 }, 13577 13578 _setHandleClassName: function() { 13579 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" ); 13580 $.each( this.items, function() { 13581 ( this.instance.options.handle ? 13582 this.item.find( this.instance.options.handle ) : this.item ) 13583 .addClass( "ui-sortable-handle" ); 13584 }); 13585 }, 13586 13587 _destroy: function() { 13588 this.element 13589 .removeClass( "ui-sortable ui-sortable-disabled" ) 13590 .find( ".ui-sortable-handle" ) 13591 .removeClass( "ui-sortable-handle" ); 13592 this._mouseDestroy(); 13593 13594 for ( var i = this.items.length - 1; i >= 0; i-- ) { 13595 this.items[i].item.removeData(this.widgetName + "-item"); 13596 } 13597 13598 return this; 13599 }, 13600 13601 _mouseCapture: function(event, overrideHandle) { 13602 var currentItem = null, 13603 validHandle = false, 13604 that = this; 13605 13606 if (this.reverting) { 13607 return false; 13608 } 13609 13610 if(this.options.disabled || this.options.type === "static") { 13611 return false; 13612 } 13613 13614 //We have to refresh the items data once first 13615 this._refreshItems(event); 13616 13617 //Find out if the clicked node (or one of its parents) is a actual item in this.items 13618 $(event.target).parents().each(function() { 13619 if($.data(this, that.widgetName + "-item") === that) { 13620 currentItem = $(this); 13621 return false; 13622 } 13623 }); 13624 if($.data(event.target, that.widgetName + "-item") === that) { 13625 currentItem = $(event.target); 13626 } 13627 13628 if(!currentItem) { 13629 return false; 13630 } 13631 if(this.options.handle && !overrideHandle) { 13632 $(this.options.handle, currentItem).find("*").addBack().each(function() { 13633 if(this === event.target) { 13634 validHandle = true; 13635 } 13636 }); 13637 if(!validHandle) { 13638 return false; 13639 } 13640 } 13641 13642 this.currentItem = currentItem; 13643 this._removeCurrentsFromItems(); 13644 return true; 13645 13646 }, 13647 13648 _mouseStart: function(event, overrideHandle, noActivation) { 13649 13650 var i, body, 13651 o = this.options; 13652 13653 this.currentContainer = this; 13654 13655 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture 13656 this.refreshPositions(); 13657 13658 //Create and append the visible helper 13659 this.helper = this._createHelper(event); 13660 13661 //Cache the helper size 13662 this._cacheHelperProportions(); 13663 13664 /* 13665 * - Position generation - 13666 * This block generates everything position related - it's the core of draggables. 13667 */ 13668 13669 //Cache the margins of the original element 13670 this._cacheMargins(); 13671 13672 //Get the next scrolling parent 13673 this.scrollParent = this.helper.scrollParent(); 13674 13675 //The element's absolute position on the page minus margins 13676 this.offset = this.currentItem.offset(); 13677 this.offset = { 13678 top: this.offset.top - this.margins.top, 13679 left: this.offset.left - this.margins.left 13680 }; 13681 13682 $.extend(this.offset, { 13683 click: { //Where the click happened, relative to the element 13684 left: event.pageX - this.offset.left, 13685 top: event.pageY - this.offset.top 13686 }, 13687 parent: this._getParentOffset(), 13688 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper 13689 }); 13690 13691 // Only after we got the offset, we can change the helper's position to absolute 13692 // TODO: Still need to figure out a way to make relative sorting possible 13693 this.helper.css("position", "absolute"); 13694 this.cssPosition = this.helper.css("position"); 13695 13696 //Generate the original position 13697 this.originalPosition = this._generatePosition(event); 13698 this.originalPageX = event.pageX; 13699 this.originalPageY = event.pageY; 13700 13701 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 13702 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); 13703 13704 //Cache the former DOM position 13705 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; 13706 13707 //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way 13708 if(this.helper[0] !== this.currentItem[0]) { 13709 this.currentItem.hide(); 13710 } 13711 13712 //Create the placeholder 13713 this._createPlaceholder(); 13714 13715 //Set a containment if given in the options 13716 if(o.containment) { 13717 this._setContainment(); 13718 } 13719 13720 if( o.cursor && o.cursor !== "auto" ) { // cursor option 13721 body = this.document.find( "body" ); 13722 13723 // support: IE 13724 this.storedCursor = body.css( "cursor" ); 13725 body.css( "cursor", o.cursor ); 13726 13727 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); 13728 } 13729 13730 if(o.opacity) { // opacity option 13731 if (this.helper.css("opacity")) { 13732 this._storedOpacity = this.helper.css("opacity"); 13733 } 13734 this.helper.css("opacity", o.opacity); 13735 } 13736 13737 if(o.zIndex) { // zIndex option 13738 if (this.helper.css("zIndex")) { 13739 this._storedZIndex = this.helper.css("zIndex"); 13740 } 13741 this.helper.css("zIndex", o.zIndex); 13742 } 13743 13744 //Prepare scrolling 13745 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { 13746 this.overflowOffset = this.scrollParent.offset(); 13747 } 13748 13749 //Call callbacks 13750 this._trigger("start", event, this._uiHash()); 13751 13752 //Recache the helper size 13753 if(!this._preserveHelperProportions) { 13754 this._cacheHelperProportions(); 13755 } 13756 13757 13758 //Post "activate" events to possible containers 13759 if( !noActivation ) { 13760 for ( i = this.containers.length - 1; i >= 0; i-- ) { 13761 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 13762 } 13763 } 13764 13765 //Prepare possible droppables 13766 if($.ui.ddmanager) { 13767 $.ui.ddmanager.current = this; 13768 } 13769 13770 if ($.ui.ddmanager && !o.dropBehaviour) { 13771 $.ui.ddmanager.prepareOffsets(this, event); 13772 } 13773 13774 this.dragging = true; 13775 13776 this.helper.addClass("ui-sortable-helper"); 13777 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position 13778 return true; 13779 13780 }, 13781 13782 _mouseDrag: function(event) { 13783 var i, item, itemElement, intersection, 13784 o = this.options, 13785 scrolled = false; 13786 13787 //Compute the helpers position 13788 this.position = this._generatePosition(event); 13789 this.positionAbs = this._convertPositionTo("absolute"); 13790 13791 if (!this.lastPositionAbs) { 13792 this.lastPositionAbs = this.positionAbs; 13793 } 13794 13795 //Do scrolling 13796 if(this.options.scroll) { 13797 if(this.scrollParent[0] !== this.document[0] && this.scrollParent[0].tagName !== "HTML") { 13798 13799 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { 13800 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; 13801 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { 13802 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; 13803 } 13804 13805 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { 13806 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; 13807 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { 13808 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; 13809 } 13810 13811 } else { 13812 13813 if(event.pageY - this.document.scrollTop() < o.scrollSensitivity) { 13814 scrolled = this.document.scrollTop(this.document.scrollTop() - o.scrollSpeed); 13815 } else if(this.window.height() - (event.pageY - this.document.scrollTop()) < o.scrollSensitivity) { 13816 scrolled = this.document.scrollTop(this.document.scrollTop() + o.scrollSpeed); 13817 } 13818 13819 if(event.pageX - this.document.scrollLeft() < o.scrollSensitivity) { 13820 scrolled = this.document.scrollLeft(this.document.scrollLeft() - o.scrollSpeed); 13821 } else if(this.window.width() - (event.pageX - this.document.scrollLeft()) < o.scrollSensitivity) { 13822 scrolled = this.document.scrollLeft(this.document.scrollLeft() + o.scrollSpeed); 13823 } 13824 13825 } 13826 13827 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { 13828 $.ui.ddmanager.prepareOffsets(this, event); 13829 } 13830 } 13831 13832 //Regenerate the absolute position used for position checks 13833 this.positionAbs = this._convertPositionTo("absolute"); 13834 13835 //Set the helper position 13836 if(!this.options.axis || this.options.axis !== "y") { 13837 this.helper[0].style.left = this.position.left+"px"; 13838 } 13839 if(!this.options.axis || this.options.axis !== "x") { 13840 this.helper[0].style.top = this.position.top+"px"; 13841 } 13842 13843 //Rearrange 13844 for (i = this.items.length - 1; i >= 0; i--) { 13845 13846 //Cache variables and intersection, continue if no intersection 13847 item = this.items[i]; 13848 itemElement = item.item[0]; 13849 intersection = this._intersectsWithPointer(item); 13850 if (!intersection) { 13851 continue; 13852 } 13853 13854 // Only put the placeholder inside the current Container, skip all 13855 // items from other containers. This works because when moving 13856 // an item from one container to another the 13857 // currentContainer is switched before the placeholder is moved. 13858 // 13859 // Without this, moving items in "sub-sortables" can cause 13860 // the placeholder to jitter between the outer and inner container. 13861 if (item.instance !== this.currentContainer) { 13862 continue; 13863 } 13864 13865 // cannot intersect with itself 13866 // no useless actions that have been done before 13867 // no action if the item moved is the parent of the item checked 13868 if (itemElement !== this.currentItem[0] && 13869 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && 13870 !$.contains(this.placeholder[0], itemElement) && 13871 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) 13872 ) { 13873 13874 this.direction = intersection === 1 ? "down" : "up"; 13875 13876 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { 13877 this._rearrange(event, item); 13878 } else { 13879 break; 13880 } 13881 13882 this._trigger("change", event, this._uiHash()); 13883 break; 13884 } 13885 } 13886 13887 //Post events to containers 13888 this._contactContainers(event); 13889 13890 //Interconnect with droppables 13891 if($.ui.ddmanager) { 13892 $.ui.ddmanager.drag(this, event); 13893 } 13894 13895 //Call callbacks 13896 this._trigger("sort", event, this._uiHash()); 13897 13898 this.lastPositionAbs = this.positionAbs; 13899 return false; 13900 13901 }, 13902 13903 _mouseStop: function(event, noPropagation) { 13904 13905 if(!event) { 13906 return; 13907 } 13908 13909 //If we are using droppables, inform the manager about the drop 13910 if ($.ui.ddmanager && !this.options.dropBehaviour) { 13911 $.ui.ddmanager.drop(this, event); 13912 } 13913 13914 if(this.options.revert) { 13915 var that = this, 13916 cur = this.placeholder.offset(), 13917 axis = this.options.axis, 13918 animation = {}; 13919 13920 if ( !axis || axis === "x" ) { 13921 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollLeft); 13922 } 13923 if ( !axis || axis === "y" ) { 13924 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === this.document[0].body ? 0 : this.offsetParent[0].scrollTop); 13925 } 13926 this.reverting = true; 13927 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { 13928 that._clear(event); 13929 }); 13930 } else { 13931 this._clear(event, noPropagation); 13932 } 13933 13934 return false; 13935 13936 }, 13937 13938 cancel: function() { 13939 13940 if(this.dragging) { 13941 13942 this._mouseUp({ target: null }); 13943 13944 if(this.options.helper === "original") { 13945 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); 13946 } else { 13947 this.currentItem.show(); 13948 } 13949 13950 //Post deactivating events to containers 13951 for (var i = this.containers.length - 1; i >= 0; i--){ 13952 this.containers[i]._trigger("deactivate", null, this._uiHash(this)); 13953 if(this.containers[i].containerCache.over) { 13954 this.containers[i]._trigger("out", null, this._uiHash(this)); 13955 this.containers[i].containerCache.over = 0; 13956 } 13957 } 13958 13959 } 13960 13961 if (this.placeholder) { 13962 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! 13963 if(this.placeholder[0].parentNode) { 13964 this.placeholder[0].parentNode.removeChild(this.placeholder[0]); 13965 } 13966 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { 13967 this.helper.remove(); 13968 } 13969 13970 $.extend(this, { 13971 helper: null, 13972 dragging: false, 13973 reverting: false, 13974 _noFinalSort: null 13975 }); 13976 13977 if(this.domPosition.prev) { 13978 $(this.domPosition.prev).after(this.currentItem); 13979 } else { 13980 $(this.domPosition.parent).prepend(this.currentItem); 13981 } 13982 } 13983 13984 return this; 13985 13986 }, 13987 13988 serialize: function(o) { 13989 13990 var items = this._getItemsAsjQuery(o && o.connected), 13991 str = []; 13992 o = o || {}; 13993 13994 $(items).each(function() { 13995 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); 13996 if (res) { 13997 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); 13998 } 13999 }); 14000 14001 if(!str.length && o.key) { 14002 str.push(o.key + "="); 14003 } 14004 14005 return str.join("&"); 14006 14007 }, 14008 14009 toArray: function(o) { 14010 14011 var items = this._getItemsAsjQuery(o && o.connected), 14012 ret = []; 14013 14014 o = o || {}; 14015 14016 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); 14017 return ret; 14018 14019 }, 14020 14021 /* Be careful with the following core functions */ 14022 _intersectsWith: function(item) { 14023 14024 var x1 = this.positionAbs.left, 14025 x2 = x1 + this.helperProportions.width, 14026 y1 = this.positionAbs.top, 14027 y2 = y1 + this.helperProportions.height, 14028 l = item.left, 14029 r = l + item.width, 14030 t = item.top, 14031 b = t + item.height, 14032 dyClick = this.offset.click.top, 14033 dxClick = this.offset.click.left, 14034 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), 14035 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), 14036 isOverElement = isOverElementHeight && isOverElementWidth; 14037 14038 if ( this.options.tolerance === "pointer" || 14039 this.options.forcePointerForContainers || 14040 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) 14041 ) { 14042 return isOverElement; 14043 } else { 14044 14045 return (l < x1 + (this.helperProportions.width / 2) && // Right Half 14046 x2 - (this.helperProportions.width / 2) < r && // Left Half 14047 t < y1 + (this.helperProportions.height / 2) && // Bottom Half 14048 y2 - (this.helperProportions.height / 2) < b ); // Top Half 14049 14050 } 14051 }, 14052 14053 _intersectsWithPointer: function(item) { 14054 14055 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), 14056 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), 14057 isOverElement = isOverElementHeight && isOverElementWidth, 14058 verticalDirection = this._getDragVerticalDirection(), 14059 horizontalDirection = this._getDragHorizontalDirection(); 14060 14061 if (!isOverElement) { 14062 return false; 14063 } 14064 14065 return this.floating ? 14066 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) 14067 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); 14068 14069 }, 14070 14071 _intersectsWithSides: function(item) { 14072 14073 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), 14074 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), 14075 verticalDirection = this._getDragVerticalDirection(), 14076 horizontalDirection = this._getDragHorizontalDirection(); 14077 14078 if (this.floating && horizontalDirection) { 14079 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); 14080 } else { 14081 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); 14082 } 14083 14084 }, 14085 14086 _getDragVerticalDirection: function() { 14087 var delta = this.positionAbs.top - this.lastPositionAbs.top; 14088 return delta !== 0 && (delta > 0 ? "down" : "up"); 14089 }, 14090 14091 _getDragHorizontalDirection: function() { 14092 var delta = this.positionAbs.left - this.lastPositionAbs.left; 14093 return delta !== 0 && (delta > 0 ? "right" : "left"); 14094 }, 14095 14096 refresh: function(event) { 14097 this._refreshItems(event); 14098 this._setHandleClassName(); 14099 this.refreshPositions(); 14100 return this; 14101 }, 14102 14103 _connectWith: function() { 14104 var options = this.options; 14105 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; 14106 }, 14107 14108 _getItemsAsjQuery: function(connected) { 14109 14110 var i, j, cur, inst, 14111 items = [], 14112 queries = [], 14113 connectWith = this._connectWith(); 14114 14115 if(connectWith && connected) { 14116 for (i = connectWith.length - 1; i >= 0; i--){ 14117 cur = $(connectWith[i], this.document[0]); 14118 for ( j = cur.length - 1; j >= 0; j--){ 14119 inst = $.data(cur[j], this.widgetFullName); 14120 if(inst && inst !== this && !inst.options.disabled) { 14121 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); 14122 } 14123 } 14124 } 14125 } 14126 14127 queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); 14128 14129 function addItems() { 14130 items.push( this ); 14131 } 14132 for (i = queries.length - 1; i >= 0; i--){ 14133 queries[i][0].each( addItems ); 14134 } 14135 14136 return $(items); 14137 14138 }, 14139 14140 _removeCurrentsFromItems: function() { 14141 14142 var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); 14143 14144 this.items = $.grep(this.items, function (item) { 14145 for (var j=0; j < list.length; j++) { 14146 if(list[j] === item.item[0]) { 14147 return false; 14148 } 14149 } 14150 return true; 14151 }); 14152 14153 }, 14154 14155 _refreshItems: function(event) { 14156 14157 this.items = []; 14158 this.containers = [this]; 14159 14160 var i, j, cur, inst, targetData, _queries, item, queriesLength, 14161 items = this.items, 14162 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], 14163 connectWith = this._connectWith(); 14164 14165 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down 14166 for (i = connectWith.length - 1; i >= 0; i--){ 14167 cur = $(connectWith[i], this.document[0]); 14168 for (j = cur.length - 1; j >= 0; j--){ 14169 inst = $.data(cur[j], this.widgetFullName); 14170 if(inst && inst !== this && !inst.options.disabled) { 14171 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); 14172 this.containers.push(inst); 14173 } 14174 } 14175 } 14176 } 14177 14178 for (i = queries.length - 1; i >= 0; i--) { 14179 targetData = queries[i][1]; 14180 _queries = queries[i][0]; 14181 14182 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { 14183 item = $(_queries[j]); 14184 14185 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) 14186 14187 items.push({ 14188 item: item, 14189 instance: targetData, 14190 width: 0, height: 0, 14191 left: 0, top: 0 14192 }); 14193 } 14194 } 14195 14196 }, 14197 14198 refreshPositions: function(fast) { 14199 14200 // Determine whether items are being displayed horizontally 14201 this.floating = this.items.length ? 14202 this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) : 14203 false; 14204 14205 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change 14206 if(this.offsetParent && this.helper) { 14207 this.offset.parent = this._getParentOffset(); 14208 } 14209 14210 var i, item, t, p; 14211 14212 for (i = this.items.length - 1; i >= 0; i--){ 14213 item = this.items[i]; 14214 14215 //We ignore calculating positions of all connected containers when we're not over them 14216 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { 14217 continue; 14218 } 14219 14220 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; 14221 14222 if (!fast) { 14223 item.width = t.outerWidth(); 14224 item.height = t.outerHeight(); 14225 } 14226 14227 p = t.offset(); 14228 item.left = p.left; 14229 item.top = p.top; 14230 } 14231 14232 if(this.options.custom && this.options.custom.refreshContainers) { 14233 this.options.custom.refreshContainers.call(this); 14234 } else { 14235 for (i = this.containers.length - 1; i >= 0; i--){ 14236 p = this.containers[i].element.offset(); 14237 this.containers[i].containerCache.left = p.left; 14238 this.containers[i].containerCache.top = p.top; 14239 this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); 14240 this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); 14241 } 14242 } 14243 14244 return this; 14245 }, 14246 14247 _createPlaceholder: function(that) { 14248 that = that || this; 14249 var className, 14250 o = that.options; 14251 14252 if(!o.placeholder || o.placeholder.constructor === String) { 14253 className = o.placeholder; 14254 o.placeholder = { 14255 element: function() { 14256 14257 var nodeName = that.currentItem[0].nodeName.toLowerCase(), 14258 element = $( "<" + nodeName + ">", that.document[0] ) 14259 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") 14260 .removeClass("ui-sortable-helper"); 14261 14262 if ( nodeName === "tbody" ) { 14263 that._createTrPlaceholder( 14264 that.currentItem.find( "tr" ).eq( 0 ), 14265 $( "<tr>", that.document[ 0 ] ).appendTo( element ) 14266 ); 14267 } else if ( nodeName === "tr" ) { 14268 that._createTrPlaceholder( that.currentItem, element ); 14269 } else if ( nodeName === "img" ) { 14270 element.attr( "src", that.currentItem.attr( "src" ) ); 14271 } 14272 14273 if ( !className ) { 14274 element.css( "visibility", "hidden" ); 14275 } 14276 14277 return element; 14278 }, 14279 update: function(container, p) { 14280 14281 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that 14282 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified 14283 if(className && !o.forcePlaceholderSize) { 14284 return; 14285 } 14286 14287 //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item 14288 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } 14289 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } 14290 } 14291 }; 14292 } 14293 14294 //Create the placeholder 14295 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); 14296 14297 //Append it after the actual current item 14298 that.currentItem.after(that.placeholder); 14299 14300 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 14301 o.placeholder.update(that, that.placeholder); 14302 14303 }, 14304 14305 _createTrPlaceholder: function( sourceTr, targetTr ) { 14306 var that = this; 14307 14308 sourceTr.children().each(function() { 14309 $( "<td> </td>", that.document[ 0 ] ) 14310 .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 14311 .appendTo( targetTr ); 14312 }); 14313 }, 14314 14315 _contactContainers: function(event) { 14316 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis, 14317 innermostContainer = null, 14318 innermostIndex = null; 14319 14320 // get innermost container that intersects with item 14321 for (i = this.containers.length - 1; i >= 0; i--) { 14322 14323 // never consider a container that's located within the item itself 14324 if($.contains(this.currentItem[0], this.containers[i].element[0])) { 14325 continue; 14326 } 14327 14328 if(this._intersectsWith(this.containers[i].containerCache)) { 14329 14330 // if we've already found a container and it's more "inner" than this, then continue 14331 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { 14332 continue; 14333 } 14334 14335 innermostContainer = this.containers[i]; 14336 innermostIndex = i; 14337 14338 } else { 14339 // container doesn't intersect. trigger "out" event if necessary 14340 if(this.containers[i].containerCache.over) { 14341 this.containers[i]._trigger("out", event, this._uiHash(this)); 14342 this.containers[i].containerCache.over = 0; 14343 } 14344 } 14345 14346 } 14347 14348 // if no intersecting containers found, return 14349 if(!innermostContainer) { 14350 return; 14351 } 14352 14353 // move the item into the container if it's not there already 14354 if(this.containers.length === 1) { 14355 if (!this.containers[innermostIndex].containerCache.over) { 14356 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 14357 this.containers[innermostIndex].containerCache.over = 1; 14358 } 14359 } else { 14360 14361 //When entering a new container, we will find the item with the least distance and append our item near it 14362 dist = 10000; 14363 itemWithLeastDistance = null; 14364 floating = innermostContainer.floating || this._isFloating(this.currentItem); 14365 posProperty = floating ? "left" : "top"; 14366 sizeProperty = floating ? "width" : "height"; 14367 axis = floating ? "clientX" : "clientY"; 14368 14369 for (j = this.items.length - 1; j >= 0; j--) { 14370 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { 14371 continue; 14372 } 14373 if(this.items[j].item[0] === this.currentItem[0]) { 14374 continue; 14375 } 14376 14377 cur = this.items[j].item.offset()[posProperty]; 14378 nearBottom = false; 14379 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 14380 nearBottom = true; 14381 } 14382 14383 if ( Math.abs( event[ axis ] - cur ) < dist ) { 14384 dist = Math.abs( event[ axis ] - cur ); 14385 itemWithLeastDistance = this.items[ j ]; 14386 this.direction = nearBottom ? "up": "down"; 14387 } 14388 } 14389 14390 //Check if dropOnEmpty is enabled 14391 if(!itemWithLeastDistance && !this.options.dropOnEmpty) { 14392 return; 14393 } 14394 14395 if(this.currentContainer === this.containers[innermostIndex]) { 14396 if ( !this.currentContainer.containerCache.over ) { 14397 this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() ); 14398 this.currentContainer.containerCache.over = 1; 14399 } 14400 return; 14401 } 14402 14403 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); 14404 this._trigger("change", event, this._uiHash()); 14405 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); 14406 this.currentContainer = this.containers[innermostIndex]; 14407 14408 //Update the placeholder 14409 this.options.placeholder.update(this.currentContainer, this.placeholder); 14410 14411 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 14412 this.containers[innermostIndex].containerCache.over = 1; 14413 } 14414 14415 14416 }, 14417 14418 _createHelper: function(event) { 14419 14420 var o = this.options, 14421 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); 14422 14423 //Add the helper to the DOM if that didn't happen already 14424 if(!helper.parents("body").length) { 14425 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); 14426 } 14427 14428 if(helper[0] === this.currentItem[0]) { 14429 this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; 14430 } 14431 14432 if(!helper[0].style.width || o.forceHelperSize) { 14433 helper.width(this.currentItem.width()); 14434 } 14435 if(!helper[0].style.height || o.forceHelperSize) { 14436 helper.height(this.currentItem.height()); 14437 } 14438 14439 return helper; 14440 14441 }, 14442 14443 _adjustOffsetFromHelper: function(obj) { 14444 if (typeof obj === "string") { 14445 obj = obj.split(" "); 14446 } 14447 if ($.isArray(obj)) { 14448 obj = {left: +obj[0], top: +obj[1] || 0}; 14449 } 14450 if ("left" in obj) { 14451 this.offset.click.left = obj.left + this.margins.left; 14452 } 14453 if ("right" in obj) { 14454 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 14455 } 14456 if ("top" in obj) { 14457 this.offset.click.top = obj.top + this.margins.top; 14458 } 14459 if ("bottom" in obj) { 14460 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 14461 } 14462 }, 14463 14464 _getParentOffset: function() { 14465 14466 14467 //Get the offsetParent and cache its position 14468 this.offsetParent = this.helper.offsetParent(); 14469 var po = this.offsetParent.offset(); 14470 14471 // This is a special case where we need to modify a offset calculated on start, since the following happened: 14472 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent 14473 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that 14474 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag 14475 if(this.cssPosition === "absolute" && this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) { 14476 po.left += this.scrollParent.scrollLeft(); 14477 po.top += this.scrollParent.scrollTop(); 14478 } 14479 14480 // This needs to be actually done for all browsers, since pageX/pageY includes this information 14481 // with an ugly IE fix 14482 if( this.offsetParent[0] === this.document[0].body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { 14483 po = { top: 0, left: 0 }; 14484 } 14485 14486 return { 14487 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), 14488 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) 14489 }; 14490 14491 }, 14492 14493 _getRelativeOffset: function() { 14494 14495 if(this.cssPosition === "relative") { 14496 var p = this.currentItem.position(); 14497 return { 14498 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), 14499 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() 14500 }; 14501 } else { 14502 return { top: 0, left: 0 }; 14503 } 14504 14505 }, 14506 14507 _cacheMargins: function() { 14508 this.margins = { 14509 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), 14510 top: (parseInt(this.currentItem.css("marginTop"),10) || 0) 14511 }; 14512 }, 14513 14514 _cacheHelperProportions: function() { 14515 this.helperProportions = { 14516 width: this.helper.outerWidth(), 14517 height: this.helper.outerHeight() 14518 }; 14519 }, 14520 14521 _setContainment: function() { 14522 14523 var ce, co, over, 14524 o = this.options; 14525 if(o.containment === "parent") { 14526 o.containment = this.helper[0].parentNode; 14527 } 14528 if(o.containment === "document" || o.containment === "window") { 14529 this.containment = [ 14530 0 - this.offset.relative.left - this.offset.parent.left, 14531 0 - this.offset.relative.top - this.offset.parent.top, 14532 o.containment === "document" ? this.document.width() : this.window.width() - this.helperProportions.width - this.margins.left, 14533 (o.containment === "document" ? this.document.width() : this.window.height() || this.document[0].body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top 14534 ]; 14535 } 14536 14537 if(!(/^(document|window|parent)$/).test(o.containment)) { 14538 ce = $(o.containment)[0]; 14539 co = $(o.containment).offset(); 14540 over = ($(ce).css("overflow") !== "hidden"); 14541 14542 this.containment = [ 14543 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, 14544 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, 14545 co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, 14546 co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top 14547 ]; 14548 } 14549 14550 }, 14551 14552 _convertPositionTo: function(d, pos) { 14553 14554 if(!pos) { 14555 pos = this.position; 14556 } 14557 var mod = d === "absolute" ? 1 : -1, 14558 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, 14559 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 14560 14561 return { 14562 top: ( 14563 pos.top + // The absolute mouse position 14564 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 14565 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) 14566 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) 14567 ), 14568 left: ( 14569 pos.left + // The absolute mouse position 14570 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 14571 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) 14572 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) 14573 ) 14574 }; 14575 14576 }, 14577 14578 _generatePosition: function(event) { 14579 14580 var top, left, 14581 o = this.options, 14582 pageX = event.pageX, 14583 pageY = event.pageY, 14584 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== this.document[0] && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 14585 14586 // This is another very weird special case that only happens for relative elements: 14587 // 1. If the css position is relative 14588 // 2. and the scroll parent is the document or similar to the offset parent 14589 // we have to refresh the relative offset during the scroll so there are no jumps 14590 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== this.document[0] && this.scrollParent[0] !== this.offsetParent[0])) { 14591 this.offset.relative = this._getRelativeOffset(); 14592 } 14593 14594 /* 14595 * - Position constraining - 14596 * Constrain the position to a mix of grid, containment. 14597 */ 14598 14599 if(this.originalPosition) { //If we are not dragging yet, we won't check for options 14600 14601 if(this.containment) { 14602 if(event.pageX - this.offset.click.left < this.containment[0]) { 14603 pageX = this.containment[0] + this.offset.click.left; 14604 } 14605 if(event.pageY - this.offset.click.top < this.containment[1]) { 14606 pageY = this.containment[1] + this.offset.click.top; 14607 } 14608 if(event.pageX - this.offset.click.left > this.containment[2]) { 14609 pageX = this.containment[2] + this.offset.click.left; 14610 } 14611 if(event.pageY - this.offset.click.top > this.containment[3]) { 14612 pageY = this.containment[3] + this.offset.click.top; 14613 } 14614 } 14615 14616 if(o.grid) { 14617 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; 14618 pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; 14619 14620 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; 14621 pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; 14622 } 14623 14624 } 14625 14626 return { 14627 top: ( 14628 pageY - // The absolute mouse position 14629 this.offset.click.top - // Click offset (relative to the element) 14630 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent 14631 this.offset.parent.top + // The offsetParent's offset without borders (offset + border) 14632 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) 14633 ), 14634 left: ( 14635 pageX - // The absolute mouse position 14636 this.offset.click.left - // Click offset (relative to the element) 14637 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent 14638 this.offset.parent.left + // The offsetParent's offset without borders (offset + border) 14639 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) 14640 ) 14641 }; 14642 14643 }, 14644 14645 _rearrange: function(event, i, a, hardRefresh) { 14646 14647 a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); 14648 14649 //Various things done here to improve the performance: 14650 // 1. we create a setTimeout, that calls refreshPositions 14651 // 2. on the instance, we have a counter variable, that get's higher after every append 14652 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same 14653 // 4. this lets only the last addition to the timeout stack through 14654 this.counter = this.counter ? ++this.counter : 1; 14655 var counter = this.counter; 14656 14657 this._delay(function() { 14658 if(counter === this.counter) { 14659 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove 14660 } 14661 }); 14662 14663 }, 14664 14665 _clear: function(event, noPropagation) { 14666 14667 this.reverting = false; 14668 // We delay all events that have to be triggered to after the point where the placeholder has been removed and 14669 // everything else normalized again 14670 var i, 14671 delayedTriggers = []; 14672 14673 // We first have to update the dom position of the actual currentItem 14674 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) 14675 if(!this._noFinalSort && this.currentItem.parent().length) { 14676 this.placeholder.before(this.currentItem); 14677 } 14678 this._noFinalSort = null; 14679 14680 if(this.helper[0] === this.currentItem[0]) { 14681 for(i in this._storedCSS) { 14682 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { 14683 this._storedCSS[i] = ""; 14684 } 14685 } 14686 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); 14687 } else { 14688 this.currentItem.show(); 14689 } 14690 14691 if(this.fromOutside && !noPropagation) { 14692 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); 14693 } 14694 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { 14695 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed 14696 } 14697 14698 // Check if the items Container has Changed and trigger appropriate 14699 // events. 14700 if (this !== this.currentContainer) { 14701 if(!noPropagation) { 14702 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); 14703 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); 14704 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); 14705 } 14706 } 14707 14708 14709 //Post events to containers 14710 function delayEvent( type, instance, container ) { 14711 return function( event ) { 14712 container._trigger( type, event, instance._uiHash( instance ) ); 14713 }; 14714 } 14715 for (i = this.containers.length - 1; i >= 0; i--){ 14716 if (!noPropagation) { 14717 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 14718 } 14719 if(this.containers[i].containerCache.over) { 14720 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 14721 this.containers[i].containerCache.over = 0; 14722 } 14723 } 14724 14725 //Do what was originally in plugins 14726 if ( this.storedCursor ) { 14727 this.document.find( "body" ).css( "cursor", this.storedCursor ); 14728 this.storedStylesheet.remove(); 14729 } 14730 if(this._storedOpacity) { 14731 this.helper.css("opacity", this._storedOpacity); 14732 } 14733 if(this._storedZIndex) { 14734 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); 14735 } 14736 14737 this.dragging = false; 14738 14739 if(!noPropagation) { 14740 this._trigger("beforeStop", event, this._uiHash()); 14741 } 14742 14743 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! 14744 this.placeholder[0].parentNode.removeChild(this.placeholder[0]); 14745 14746 if ( !this.cancelHelperRemoval ) { 14747 if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) { 14748 this.helper.remove(); 14749 } 14750 this.helper = null; 14751 } 14752 14753 if(!noPropagation) { 14754 for (i=0; i < delayedTriggers.length; i++) { 14755 delayedTriggers[i].call(this, event); 14756 } //Trigger all delayed events 14757 this._trigger("stop", event, this._uiHash()); 14758 } 14759 14760 this.fromOutside = false; 14761 return !this.cancelHelperRemoval; 14762 14763 }, 14764 14765 _trigger: function() { 14766 if ($.Widget.prototype._trigger.apply(this, arguments) === false) { 14767 this.cancel(); 14768 } 14769 }, 14770 14771 _uiHash: function(_inst) { 14772 var inst = _inst || this; 14773 return { 14774 helper: inst.helper, 14775 placeholder: inst.placeholder || $([]), 14776 position: inst.position, 14777 originalPosition: inst.originalPosition, 14778 offset: inst.positionAbs, 14779 item: inst.currentItem, 14780 sender: _inst ? _inst.element : null 14781 }; 14782 } 14783 14784 }); 14785 14786 14787 /*! 14788 * jQuery UI Spinner 1.11.4 14789 * http://jqueryui.com 14790 * 14791 * Copyright jQuery Foundation and other contributors 14792 * Released under the MIT license. 14793 * http://jquery.org/license 14794 * 14795 * http://api.jqueryui.com/spinner/ 14796 */ 14797 14798 14799 function spinner_modifier( fn ) { 14800 return function() { 14801 var previous = this.element.val(); 14802 fn.apply( this, arguments ); 14803 this._refresh(); 14804 if ( previous !== this.element.val() ) { 14805 this._trigger( "change" ); 14806 } 14807 }; 14808 } 14809 14810 var spinner = $.widget( "ui.spinner", { 14811 version: "1.11.4", 14812 defaultElement: "<input>", 14813 widgetEventPrefix: "spin", 14814 options: { 14815 culture: null, 14816 icons: { 14817 down: "ui-icon-triangle-1-s", 14818 up: "ui-icon-triangle-1-n" 14819 }, 14820 incremental: true, 14821 max: null, 14822 min: null, 14823 numberFormat: null, 14824 page: 10, 14825 step: 1, 14826 14827 change: null, 14828 spin: null, 14829 start: null, 14830 stop: null 14831 }, 14832 14833 _create: function() { 14834 // handle string values that need to be parsed 14835 this._setOption( "max", this.options.max ); 14836 this._setOption( "min", this.options.min ); 14837 this._setOption( "step", this.options.step ); 14838 14839 // Only format if there is a value, prevents the field from being marked 14840 // as invalid in Firefox, see #9573. 14841 if ( this.value() !== "" ) { 14842 // Format the value, but don't constrain. 14843 this._value( this.element.val(), true ); 14844 } 14845 14846 this._draw(); 14847 this._on( this._events ); 14848 this._refresh(); 14849 14850 // turning off autocomplete prevents the browser from remembering the 14851 // value when navigating through history, so we re-enable autocomplete 14852 // if the page is unloaded before the widget is destroyed. #7790 14853 this._on( this.window, { 14854 beforeunload: function() { 14855 this.element.removeAttr( "autocomplete" ); 14856 } 14857 }); 14858 }, 14859 14860 _getCreateOptions: function() { 14861 var options = {}, 14862 element = this.element; 14863 14864 $.each( [ "min", "max", "step" ], function( i, option ) { 14865 var value = element.attr( option ); 14866 if ( value !== undefined && value.length ) { 14867 options[ option ] = value; 14868 } 14869 }); 14870 14871 return options; 14872 }, 14873 14874 _events: { 14875 keydown: function( event ) { 14876 if ( this._start( event ) && this._keydown( event ) ) { 14877 event.preventDefault(); 14878 } 14879 }, 14880 keyup: "_stop", 14881 focus: function() { 14882 this.previous = this.element.val(); 14883 }, 14884 blur: function( event ) { 14885 if ( this.cancelBlur ) { 14886 delete this.cancelBlur; 14887 return; 14888 } 14889 14890 this._stop(); 14891 this._refresh(); 14892 if ( this.previous !== this.element.val() ) { 14893 this._trigger( "change", event ); 14894 } 14895 }, 14896 mousewheel: function( event, delta ) { 14897 if ( !delta ) { 14898 return; 14899 } 14900 if ( !this.spinning && !this._start( event ) ) { 14901 return false; 14902 } 14903 14904 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); 14905 clearTimeout( this.mousewheelTimer ); 14906 this.mousewheelTimer = this._delay(function() { 14907 if ( this.spinning ) { 14908 this._stop( event ); 14909 } 14910 }, 100 ); 14911 event.preventDefault(); 14912 }, 14913 "mousedown .ui-spinner-button": function( event ) { 14914 var previous; 14915 14916 // We never want the buttons to have focus; whenever the user is 14917 // interacting with the spinner, the focus should be on the input. 14918 // If the input is focused then this.previous is properly set from 14919 // when the input first received focus. If the input is not focused 14920 // then we need to set this.previous based on the value before spinning. 14921 previous = this.element[0] === this.document[0].activeElement ? 14922 this.previous : this.element.val(); 14923 function checkFocus() { 14924 var isActive = this.element[0] === this.document[0].activeElement; 14925 if ( !isActive ) { 14926 this.element.focus(); 14927 this.previous = previous; 14928 // support: IE 14929 // IE sets focus asynchronously, so we need to check if focus 14930 // moved off of the input because the user clicked on the button. 14931 this._delay(function() { 14932 this.previous = previous; 14933 }); 14934 } 14935 } 14936 14937 // ensure focus is on (or stays on) the text field 14938 event.preventDefault(); 14939 checkFocus.call( this ); 14940 14941 // support: IE 14942 // IE doesn't prevent moving focus even with event.preventDefault() 14943 // so we set a flag to know when we should ignore the blur event 14944 // and check (again) if focus moved off of the input. 14945 this.cancelBlur = true; 14946 this._delay(function() { 14947 delete this.cancelBlur; 14948 checkFocus.call( this ); 14949 }); 14950 14951 if ( this._start( event ) === false ) { 14952 return; 14953 } 14954 14955 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 14956 }, 14957 "mouseup .ui-spinner-button": "_stop", 14958 "mouseenter .ui-spinner-button": function( event ) { 14959 // button will add ui-state-active if mouse was down while mouseleave and kept down 14960 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 14961 return; 14962 } 14963 14964 if ( this._start( event ) === false ) { 14965 return false; 14966 } 14967 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 14968 }, 14969 // TODO: do we really want to consider this a stop? 14970 // shouldn't we just stop the repeater and wait until mouseup before 14971 // we trigger the stop event? 14972 "mouseleave .ui-spinner-button": "_stop" 14973 }, 14974 14975 _draw: function() { 14976 var uiSpinner = this.uiSpinner = this.element 14977 .addClass( "ui-spinner-input" ) 14978 .attr( "autocomplete", "off" ) 14979 .wrap( this._uiSpinnerHtml() ) 14980 .parent() 14981 // add buttons 14982 .append( this._buttonHtml() ); 14983 14984 this.element.attr( "role", "spinbutton" ); 14985 14986 // button bindings 14987 this.buttons = uiSpinner.find( ".ui-spinner-button" ) 14988 .attr( "tabIndex", -1 ) 14989 .button() 14990 .removeClass( "ui-corner-all" ); 14991 14992 // IE 6 doesn't understand height: 50% for the buttons 14993 // unless the wrapper has an explicit height 14994 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && 14995 uiSpinner.height() > 0 ) { 14996 uiSpinner.height( uiSpinner.height() ); 14997 } 14998 14999 // disable spinner if element was already disabled 15000 if ( this.options.disabled ) { 15001 this.disable(); 15002 } 15003 }, 15004 15005 _keydown: function( event ) { 15006 var options = this.options, 15007 keyCode = $.ui.keyCode; 15008 15009 switch ( event.keyCode ) { 15010 case keyCode.UP: 15011 this._repeat( null, 1, event ); 15012 return true; 15013 case keyCode.DOWN: 15014 this._repeat( null, -1, event ); 15015 return true; 15016 case keyCode.PAGE_UP: 15017 this._repeat( null, options.page, event ); 15018 return true; 15019 case keyCode.PAGE_DOWN: 15020 this._repeat( null, -options.page, event ); 15021 return true; 15022 } 15023 15024 return false; 15025 }, 15026 15027 _uiSpinnerHtml: function() { 15028 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"; 15029 }, 15030 15031 _buttonHtml: function() { 15032 return "" + 15033 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" + 15034 "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" + 15035 "</a>" + 15036 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" + 15037 "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" + 15038 "</a>"; 15039 }, 15040 15041 _start: function( event ) { 15042 if ( !this.spinning && this._trigger( "start", event ) === false ) { 15043 return false; 15044 } 15045 15046 if ( !this.counter ) { 15047 this.counter = 1; 15048 } 15049 this.spinning = true; 15050 return true; 15051 }, 15052 15053 _repeat: function( i, steps, event ) { 15054 i = i || 500; 15055 15056 clearTimeout( this.timer ); 15057 this.timer = this._delay(function() { 15058 this._repeat( 40, steps, event ); 15059 }, i ); 15060 15061 this._spin( steps * this.options.step, event ); 15062 }, 15063 15064 _spin: function( step, event ) { 15065 var value = this.value() || 0; 15066 15067 if ( !this.counter ) { 15068 this.counter = 1; 15069 } 15070 15071 value = this._adjustValue( value + step * this._increment( this.counter ) ); 15072 15073 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { 15074 this._value( value ); 15075 this.counter++; 15076 } 15077 }, 15078 15079 _increment: function( i ) { 15080 var incremental = this.options.incremental; 15081 15082 if ( incremental ) { 15083 return $.isFunction( incremental ) ? 15084 incremental( i ) : 15085 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 15086 } 15087 15088 return 1; 15089 }, 15090 15091 _precision: function() { 15092 var precision = this._precisionOf( this.options.step ); 15093 if ( this.options.min !== null ) { 15094 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 15095 } 15096 return precision; 15097 }, 15098 15099 _precisionOf: function( num ) { 15100 var str = num.toString(), 15101 decimal = str.indexOf( "." ); 15102 return decimal === -1 ? 0 : str.length - decimal - 1; 15103 }, 15104 15105 _adjustValue: function( value ) { 15106 var base, aboveMin, 15107 options = this.options; 15108 15109 // make sure we're at a valid step 15110 // - find out where we are relative to the base (min or 0) 15111 base = options.min !== null ? options.min : 0; 15112 aboveMin = value - base; 15113 // - round to the nearest step 15114 aboveMin = Math.round(aboveMin / options.step) * options.step; 15115 // - rounding is based on 0, so adjust back to our base 15116 value = base + aboveMin; 15117 15118 // fix precision from bad JS floating point math 15119 value = parseFloat( value.toFixed( this._precision() ) ); 15120 15121 // clamp the value 15122 if ( options.max !== null && value > options.max) { 15123 return options.max; 15124 } 15125 if ( options.min !== null && value < options.min ) { 15126 return options.min; 15127 } 15128 15129 return value; 15130 }, 15131 15132 _stop: function( event ) { 15133 if ( !this.spinning ) { 15134 return; 15135 } 15136 15137 clearTimeout( this.timer ); 15138 clearTimeout( this.mousewheelTimer ); 15139 this.counter = 0; 15140 this.spinning = false; 15141 this._trigger( "stop", event ); 15142 }, 15143 15144 _setOption: function( key, value ) { 15145 if ( key === "culture" || key === "numberFormat" ) { 15146 var prevValue = this._parse( this.element.val() ); 15147 this.options[ key ] = value; 15148 this.element.val( this._format( prevValue ) ); 15149 return; 15150 } 15151 15152 if ( key === "max" || key === "min" || key === "step" ) { 15153 if ( typeof value === "string" ) { 15154 value = this._parse( value ); 15155 } 15156 } 15157 if ( key === "icons" ) { 15158 this.buttons.first().find( ".ui-icon" ) 15159 .removeClass( this.options.icons.up ) 15160 .addClass( value.up ); 15161 this.buttons.last().find( ".ui-icon" ) 15162 .removeClass( this.options.icons.down ) 15163 .addClass( value.down ); 15164 } 15165 15166 this._super( key, value ); 15167 15168 if ( key === "disabled" ) { 15169 this.widget().toggleClass( "ui-state-disabled", !!value ); 15170 this.element.prop( "disabled", !!value ); 15171 this.buttons.button( value ? "disable" : "enable" ); 15172 } 15173 }, 15174 15175 _setOptions: spinner_modifier(function( options ) { 15176 this._super( options ); 15177 }), 15178 15179 _parse: function( val ) { 15180 if ( typeof val === "string" && val !== "" ) { 15181 val = window.Globalize && this.options.numberFormat ? 15182 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 15183 } 15184 return val === "" || isNaN( val ) ? null : val; 15185 }, 15186 15187 _format: function( value ) { 15188 if ( value === "" ) { 15189 return ""; 15190 } 15191 return window.Globalize && this.options.numberFormat ? 15192 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 15193 value; 15194 }, 15195 15196 _refresh: function() { 15197 this.element.attr({ 15198 "aria-valuemin": this.options.min, 15199 "aria-valuemax": this.options.max, 15200 // TODO: what should we do with values that can't be parsed? 15201 "aria-valuenow": this._parse( this.element.val() ) 15202 }); 15203 }, 15204 15205 isValid: function() { 15206 var value = this.value(); 15207 15208 // null is invalid 15209 if ( value === null ) { 15210 return false; 15211 } 15212 15213 // if value gets adjusted, it's invalid 15214 return value === this._adjustValue( value ); 15215 }, 15216 15217 // update the value without triggering change 15218 _value: function( value, allowAny ) { 15219 var parsed; 15220 if ( value !== "" ) { 15221 parsed = this._parse( value ); 15222 if ( parsed !== null ) { 15223 if ( !allowAny ) { 15224 parsed = this._adjustValue( parsed ); 15225 } 15226 value = this._format( parsed ); 15227 } 15228 } 15229 this.element.val( value ); 15230 this._refresh(); 15231 }, 15232 15233 _destroy: function() { 15234 this.element 15235 .removeClass( "ui-spinner-input" ) 15236 .prop( "disabled", false ) 15237 .removeAttr( "autocomplete" ) 15238 .removeAttr( "role" ) 15239 .removeAttr( "aria-valuemin" ) 15240 .removeAttr( "aria-valuemax" ) 15241 .removeAttr( "aria-valuenow" ); 15242 this.uiSpinner.replaceWith( this.element ); 15243 }, 15244 15245 stepUp: spinner_modifier(function( steps ) { 15246 this._stepUp( steps ); 15247 }), 15248 _stepUp: function( steps ) { 15249 if ( this._start() ) { 15250 this._spin( (steps || 1) * this.options.step ); 15251 this._stop(); 15252 } 15253 }, 15254 15255 stepDown: spinner_modifier(function( steps ) { 15256 this._stepDown( steps ); 15257 }), 15258 _stepDown: function( steps ) { 15259 if ( this._start() ) { 15260 this._spin( (steps || 1) * -this.options.step ); 15261 this._stop(); 15262 } 15263 }, 15264 15265 pageUp: spinner_modifier(function( pages ) { 15266 this._stepUp( (pages || 1) * this.options.page ); 15267 }), 15268 15269 pageDown: spinner_modifier(function( pages ) { 15270 this._stepDown( (pages || 1) * this.options.page ); 15271 }), 15272 15273 value: function( newVal ) { 15274 if ( !arguments.length ) { 15275 return this._parse( this.element.val() ); 15276 } 15277 spinner_modifier( this._value ).call( this, newVal ); 15278 }, 15279 15280 widget: function() { 15281 return this.uiSpinner; 15282 } 15283 }); 15284 15285 15286 /*! 15287 * jQuery UI Tabs 1.11.4 15288 * http://jqueryui.com 15289 * 15290 * Copyright jQuery Foundation and other contributors 15291 * Released under the MIT license. 15292 * http://jquery.org/license 15293 * 15294 * http://api.jqueryui.com/tabs/ 15295 */ 15296 15297 15298 var tabs = $.widget( "ui.tabs", { 15299 version: "1.11.4", 15300 delay: 300, 15301 options: { 15302 active: null, 15303 collapsible: false, 15304 event: "click", 15305 heightStyle: "content", 15306 hide: null, 15307 show: null, 15308 15309 // callbacks 15310 activate: null, 15311 beforeActivate: null, 15312 beforeLoad: null, 15313 load: null 15314 }, 15315 15316 _isLocal: (function() { 15317 var rhash = /#.*$/; 15318 15319 return function( anchor ) { 15320 var anchorUrl, locationUrl; 15321 15322 // support: IE7 15323 // IE7 doesn't normalize the href property when set via script (#9317) 15324 anchor = anchor.cloneNode( false ); 15325 15326 anchorUrl = anchor.href.replace( rhash, "" ); 15327 locationUrl = location.href.replace( rhash, "" ); 15328 15329 // decoding may throw an error if the URL isn't UTF-8 (#9518) 15330 try { 15331 anchorUrl = decodeURIComponent( anchorUrl ); 15332 } catch ( error ) {} 15333 try { 15334 locationUrl = decodeURIComponent( locationUrl ); 15335 } catch ( error ) {} 15336 15337 return anchor.hash.length > 1 && anchorUrl === locationUrl; 15338 }; 15339 })(), 15340 15341 _create: function() { 15342 var that = this, 15343 options = this.options; 15344 15345 this.running = false; 15346 15347 this.element 15348 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) 15349 .toggleClass( "ui-tabs-collapsible", options.collapsible ); 15350 15351 this._processTabs(); 15352 options.active = this._initialActive(); 15353 15354 // Take disabling tabs via class attribute from HTML 15355 // into account and update option properly. 15356 if ( $.isArray( options.disabled ) ) { 15357 options.disabled = $.unique( options.disabled.concat( 15358 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { 15359 return that.tabs.index( li ); 15360 }) 15361 ) ).sort(); 15362 } 15363 15364 // check for length avoids error when initializing empty list 15365 if ( this.options.active !== false && this.anchors.length ) { 15366 this.active = this._findActive( options.active ); 15367 } else { 15368 this.active = $(); 15369 } 15370 15371 this._refresh(); 15372 15373 if ( this.active.length ) { 15374 this.load( options.active ); 15375 } 15376 }, 15377 15378 _initialActive: function() { 15379 var active = this.options.active, 15380 collapsible = this.options.collapsible, 15381 locationHash = location.hash.substring( 1 ); 15382 15383 if ( active === null ) { 15384 // check the fragment identifier in the URL 15385 if ( locationHash ) { 15386 this.tabs.each(function( i, tab ) { 15387 if ( $( tab ).attr( "aria-controls" ) === locationHash ) { 15388 active = i; 15389 return false; 15390 } 15391 }); 15392 } 15393 15394 // check for a tab marked active via a class 15395 if ( active === null ) { 15396 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); 15397 } 15398 15399 // no active tab, set to false 15400 if ( active === null || active === -1 ) { 15401 active = this.tabs.length ? 0 : false; 15402 } 15403 } 15404 15405 // handle numbers: negative, out of range 15406 if ( active !== false ) { 15407 active = this.tabs.index( this.tabs.eq( active ) ); 15408 if ( active === -1 ) { 15409 active = collapsible ? false : 0; 15410 } 15411 } 15412 15413 // don't allow collapsible: false and active: false 15414 if ( !collapsible && active === false && this.anchors.length ) { 15415 active = 0; 15416 } 15417 15418 return active; 15419 }, 15420 15421 _getCreateEventData: function() { 15422 return { 15423 tab: this.active, 15424 panel: !this.active.length ? $() : this._getPanelForTab( this.active ) 15425 }; 15426 }, 15427 15428 _tabKeydown: function( event ) { 15429 var focusedTab = $( this.document[0].activeElement ).closest( "li" ), 15430 selectedIndex = this.tabs.index( focusedTab ), 15431 goingForward = true; 15432 15433 if ( this._handlePageNav( event ) ) { 15434 return; 15435 } 15436 15437 switch ( event.keyCode ) { 15438 case $.ui.keyCode.RIGHT: 15439 case $.ui.keyCode.DOWN: 15440 selectedIndex++; 15441 break; 15442 case $.ui.keyCode.UP: 15443 case $.ui.keyCode.LEFT: 15444 goingForward = false; 15445 selectedIndex--; 15446 break; 15447 case $.ui.keyCode.END: 15448 selectedIndex = this.anchors.length - 1; 15449 break; 15450 case $.ui.keyCode.HOME: 15451 selectedIndex = 0; 15452 break; 15453 case $.ui.keyCode.SPACE: 15454 // Activate only, no collapsing 15455 event.preventDefault(); 15456 clearTimeout( this.activating ); 15457 this._activate( selectedIndex ); 15458 return; 15459 case $.ui.keyCode.ENTER: 15460 // Toggle (cancel delayed activation, allow collapsing) 15461 event.preventDefault(); 15462 clearTimeout( this.activating ); 15463 // Determine if we should collapse or activate 15464 this._activate( selectedIndex === this.options.active ? false : selectedIndex ); 15465 return; 15466 default: 15467 return; 15468 } 15469 15470 // Focus the appropriate tab, based on which key was pressed 15471 event.preventDefault(); 15472 clearTimeout( this.activating ); 15473 selectedIndex = this._focusNextTab( selectedIndex, goingForward ); 15474 15475 // Navigating with control/command key will prevent automatic activation 15476 if ( !event.ctrlKey && !event.metaKey ) { 15477 15478 // Update aria-selected immediately so that AT think the tab is already selected. 15479 // Otherwise AT may confuse the user by stating that they need to activate the tab, 15480 // but the tab will already be activated by the time the announcement finishes. 15481 focusedTab.attr( "aria-selected", "false" ); 15482 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); 15483 15484 this.activating = this._delay(function() { 15485 this.option( "active", selectedIndex ); 15486 }, this.delay ); 15487 } 15488 }, 15489 15490 _panelKeydown: function( event ) { 15491 if ( this._handlePageNav( event ) ) { 15492 return; 15493 } 15494 15495 // Ctrl+up moves focus to the current tab 15496 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { 15497 event.preventDefault(); 15498 this.active.focus(); 15499 } 15500 }, 15501 15502 // Alt+page up/down moves focus to the previous/next tab (and activates) 15503 _handlePageNav: function( event ) { 15504 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { 15505 this._activate( this._focusNextTab( this.options.active - 1, false ) ); 15506 return true; 15507 } 15508 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { 15509 this._activate( this._focusNextTab( this.options.active + 1, true ) ); 15510 return true; 15511 } 15512 }, 15513 15514 _findNextTab: function( index, goingForward ) { 15515 var lastTabIndex = this.tabs.length - 1; 15516 15517 function constrain() { 15518 if ( index > lastTabIndex ) { 15519 index = 0; 15520 } 15521 if ( index < 0 ) { 15522 index = lastTabIndex; 15523 } 15524 return index; 15525 } 15526 15527 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { 15528 index = goingForward ? index + 1 : index - 1; 15529 } 15530 15531 return index; 15532 }, 15533 15534 _focusNextTab: function( index, goingForward ) { 15535 index = this._findNextTab( index, goingForward ); 15536 this.tabs.eq( index ).focus(); 15537 return index; 15538 }, 15539 15540 _setOption: function( key, value ) { 15541 if ( key === "active" ) { 15542 // _activate() will handle invalid values and update this.options 15543 this._activate( value ); 15544 return; 15545 } 15546 15547 if ( key === "disabled" ) { 15548 // don't use the widget factory's disabled handling 15549 this._setupDisabled( value ); 15550 return; 15551 } 15552 15553 this._super( key, value); 15554 15555 if ( key === "collapsible" ) { 15556 this.element.toggleClass( "ui-tabs-collapsible", value ); 15557 // Setting collapsible: false while collapsed; open first panel 15558 if ( !value && this.options.active === false ) { 15559 this._activate( 0 ); 15560 } 15561 } 15562 15563 if ( key === "event" ) { 15564 this._setupEvents( value ); 15565 } 15566 15567 if ( key === "heightStyle" ) { 15568 this._setupHeightStyle( value ); 15569 } 15570 }, 15571 15572 _sanitizeSelector: function( hash ) { 15573 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; 15574 }, 15575 15576 refresh: function() { 15577 var options = this.options, 15578 lis = this.tablist.children( ":has(a[href])" ); 15579 15580 // get disabled tabs from class attribute from HTML 15581 // this will get converted to a boolean if needed in _refresh() 15582 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { 15583 return lis.index( tab ); 15584 }); 15585 15586 this._processTabs(); 15587 15588 // was collapsed or no tabs 15589 if ( options.active === false || !this.anchors.length ) { 15590 options.active = false; 15591 this.active = $(); 15592 // was active, but active tab is gone 15593 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { 15594 // all remaining tabs are disabled 15595 if ( this.tabs.length === options.disabled.length ) { 15596 options.active = false; 15597 this.active = $(); 15598 // activate previous tab 15599 } else { 15600 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); 15601 } 15602 // was active, active tab still exists 15603 } else { 15604 // make sure active index is correct 15605 options.active = this.tabs.index( this.active ); 15606 } 15607 15608 this._refresh(); 15609 }, 15610 15611 _refresh: function() { 15612 this._setupDisabled( this.options.disabled ); 15613 this._setupEvents( this.options.event ); 15614 this._setupHeightStyle( this.options.heightStyle ); 15615 15616 this.tabs.not( this.active ).attr({ 15617 "aria-selected": "false", 15618 "aria-expanded": "false", 15619 tabIndex: -1 15620 }); 15621 this.panels.not( this._getPanelForTab( this.active ) ) 15622 .hide() 15623 .attr({ 15624 "aria-hidden": "true" 15625 }); 15626 15627 // Make sure one tab is in the tab order 15628 if ( !this.active.length ) { 15629 this.tabs.eq( 0 ).attr( "tabIndex", 0 ); 15630 } else { 15631 this.active 15632 .addClass( "ui-tabs-active ui-state-active" ) 15633 .attr({ 15634 "aria-selected": "true", 15635 "aria-expanded": "true", 15636 tabIndex: 0 15637 }); 15638 this._getPanelForTab( this.active ) 15639 .show() 15640 .attr({ 15641 "aria-hidden": "false" 15642 }); 15643 } 15644 }, 15645 15646 _processTabs: function() { 15647 var that = this, 15648 prevTabs = this.tabs, 15649 prevAnchors = this.anchors, 15650 prevPanels = this.panels; 15651 15652 this.tablist = this._getList() 15653 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) 15654 .attr( "role", "tablist" ) 15655 15656 // Prevent users from focusing disabled tabs via click 15657 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) { 15658 if ( $( this ).is( ".ui-state-disabled" ) ) { 15659 event.preventDefault(); 15660 } 15661 }) 15662 15663 // support: IE <9 15664 // Preventing the default action in mousedown doesn't prevent IE 15665 // from focusing the element, so if the anchor gets focused, blur. 15666 // We don't have to worry about focusing the previously focused 15667 // element since clicking on a non-focusable element should focus 15668 // the body anyway. 15669 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { 15670 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { 15671 this.blur(); 15672 } 15673 }); 15674 15675 this.tabs = this.tablist.find( "> li:has(a[href])" ) 15676 .addClass( "ui-state-default ui-corner-top" ) 15677 .attr({ 15678 role: "tab", 15679 tabIndex: -1 15680 }); 15681 15682 this.anchors = this.tabs.map(function() { 15683 return $( "a", this )[ 0 ]; 15684 }) 15685 .addClass( "ui-tabs-anchor" ) 15686 .attr({ 15687 role: "presentation", 15688 tabIndex: -1 15689 }); 15690 15691 this.panels = $(); 15692 15693 this.anchors.each(function( i, anchor ) { 15694 var selector, panel, panelId, 15695 anchorId = $( anchor ).uniqueId().attr( "id" ), 15696 tab = $( anchor ).closest( "li" ), 15697 originalAriaControls = tab.attr( "aria-controls" ); 15698 15699 // inline tab 15700 if ( that._isLocal( anchor ) ) { 15701 selector = anchor.hash; 15702 panelId = selector.substring( 1 ); 15703 panel = that.element.find( that._sanitizeSelector( selector ) ); 15704 // remote tab 15705 } else { 15706 // If the tab doesn't already have aria-controls, 15707 // generate an id by using a throw-away element 15708 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; 15709 selector = "#" + panelId; 15710 panel = that.element.find( selector ); 15711 if ( !panel.length ) { 15712 panel = that._createPanel( panelId ); 15713 panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); 15714 } 15715 panel.attr( "aria-live", "polite" ); 15716 } 15717 15718 if ( panel.length) { 15719 that.panels = that.panels.add( panel ); 15720 } 15721 if ( originalAriaControls ) { 15722 tab.data( "ui-tabs-aria-controls", originalAriaControls ); 15723 } 15724 tab.attr({ 15725 "aria-controls": panelId, 15726 "aria-labelledby": anchorId 15727 }); 15728 panel.attr( "aria-labelledby", anchorId ); 15729 }); 15730 15731 this.panels 15732 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) 15733 .attr( "role", "tabpanel" ); 15734 15735 // Avoid memory leaks (#10056) 15736 if ( prevTabs ) { 15737 this._off( prevTabs.not( this.tabs ) ); 15738 this._off( prevAnchors.not( this.anchors ) ); 15739 this._off( prevPanels.not( this.panels ) ); 15740 } 15741 }, 15742 15743 // allow overriding how to find the list for rare usage scenarios (#7715) 15744 _getList: function() { 15745 return this.tablist || this.element.find( "ol,ul" ).eq( 0 ); 15746 }, 15747 15748 _createPanel: function( id ) { 15749 return $( "<div>" ) 15750 .attr( "id", id ) 15751 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) 15752 .data( "ui-tabs-destroy", true ); 15753 }, 15754 15755 _setupDisabled: function( disabled ) { 15756 if ( $.isArray( disabled ) ) { 15757 if ( !disabled.length ) { 15758 disabled = false; 15759 } else if ( disabled.length === this.anchors.length ) { 15760 disabled = true; 15761 } 15762 } 15763 15764 // disable tabs 15765 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { 15766 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { 15767 $( li ) 15768 .addClass( "ui-state-disabled" ) 15769 .attr( "aria-disabled", "true" ); 15770 } else { 15771 $( li ) 15772 .removeClass( "ui-state-disabled" ) 15773 .removeAttr( "aria-disabled" ); 15774 } 15775 } 15776 15777 this.options.disabled = disabled; 15778 }, 15779 15780 _setupEvents: function( event ) { 15781 var events = {}; 15782 if ( event ) { 15783 $.each( event.split(" "), function( index, eventName ) { 15784 events[ eventName ] = "_eventHandler"; 15785 }); 15786 } 15787 15788 this._off( this.anchors.add( this.tabs ).add( this.panels ) ); 15789 // Always prevent the default action, even when disabled 15790 this._on( true, this.anchors, { 15791 click: function( event ) { 15792 event.preventDefault(); 15793 } 15794 }); 15795 this._on( this.anchors, events ); 15796 this._on( this.tabs, { keydown: "_tabKeydown" } ); 15797 this._on( this.panels, { keydown: "_panelKeydown" } ); 15798 15799 this._focusable( this.tabs ); 15800 this._hoverable( this.tabs ); 15801 }, 15802 15803 _setupHeightStyle: function( heightStyle ) { 15804 var maxHeight, 15805 parent = this.element.parent(); 15806 15807 if ( heightStyle === "fill" ) { 15808 maxHeight = parent.height(); 15809 maxHeight -= this.element.outerHeight() - this.element.height(); 15810 15811 this.element.siblings( ":visible" ).each(function() { 15812 var elem = $( this ), 15813 position = elem.css( "position" ); 15814 15815 if ( position === "absolute" || position === "fixed" ) { 15816 return; 15817 } 15818 maxHeight -= elem.outerHeight( true ); 15819 }); 15820 15821 this.element.children().not( this.panels ).each(function() { 15822 maxHeight -= $( this ).outerHeight( true ); 15823 }); 15824 15825 this.panels.each(function() { 15826 $( this ).height( Math.max( 0, maxHeight - 15827 $( this ).innerHeight() + $( this ).height() ) ); 15828 }) 15829 .css( "overflow", "auto" ); 15830 } else if ( heightStyle === "auto" ) { 15831 maxHeight = 0; 15832 this.panels.each(function() { 15833 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 15834 }).height( maxHeight ); 15835 } 15836 }, 15837 15838 _eventHandler: function( event ) { 15839 var options = this.options, 15840 active = this.active, 15841 anchor = $( event.currentTarget ), 15842 tab = anchor.closest( "li" ), 15843 clickedIsActive = tab[ 0 ] === active[ 0 ], 15844 collapsing = clickedIsActive && options.collapsible, 15845 toShow = collapsing ? $() : this._getPanelForTab( tab ), 15846 toHide = !active.length ? $() : this._getPanelForTab( active ), 15847 eventData = { 15848 oldTab: active, 15849 oldPanel: toHide, 15850 newTab: collapsing ? $() : tab, 15851 newPanel: toShow 15852 }; 15853 15854 event.preventDefault(); 15855 15856 if ( tab.hasClass( "ui-state-disabled" ) || 15857 // tab is already loading 15858 tab.hasClass( "ui-tabs-loading" ) || 15859 // can't switch durning an animation 15860 this.running || 15861 // click on active header, but not collapsible 15862 ( clickedIsActive && !options.collapsible ) || 15863 // allow canceling activation 15864 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 15865 return; 15866 } 15867 15868 options.active = collapsing ? false : this.tabs.index( tab ); 15869 15870 this.active = clickedIsActive ? $() : tab; 15871 if ( this.xhr ) { 15872 this.xhr.abort(); 15873 } 15874 15875 if ( !toHide.length && !toShow.length ) { 15876 $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); 15877 } 15878 15879 if ( toShow.length ) { 15880 this.load( this.tabs.index( tab ), event ); 15881 } 15882 this._toggle( event, eventData ); 15883 }, 15884 15885 // handles show/hide for selecting tabs 15886 _toggle: function( event, eventData ) { 15887 var that = this, 15888 toShow = eventData.newPanel, 15889 toHide = eventData.oldPanel; 15890 15891 this.running = true; 15892 15893 function complete() { 15894 that.running = false; 15895 that._trigger( "activate", event, eventData ); 15896 } 15897 15898 function show() { 15899 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); 15900 15901 if ( toShow.length && that.options.show ) { 15902 that._show( toShow, that.options.show, complete ); 15903 } else { 15904 toShow.show(); 15905 complete(); 15906 } 15907 } 15908 15909 // start out by hiding, then showing, then completing 15910 if ( toHide.length && this.options.hide ) { 15911 this._hide( toHide, this.options.hide, function() { 15912 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); 15913 show(); 15914 }); 15915 } else { 15916 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); 15917 toHide.hide(); 15918 show(); 15919 } 15920 15921 toHide.attr( "aria-hidden", "true" ); 15922 eventData.oldTab.attr({ 15923 "aria-selected": "false", 15924 "aria-expanded": "false" 15925 }); 15926 // If we're switching tabs, remove the old tab from the tab order. 15927 // If we're opening from collapsed state, remove the previous tab from the tab order. 15928 // If we're collapsing, then keep the collapsing tab in the tab order. 15929 if ( toShow.length && toHide.length ) { 15930 eventData.oldTab.attr( "tabIndex", -1 ); 15931 } else if ( toShow.length ) { 15932 this.tabs.filter(function() { 15933 return $( this ).attr( "tabIndex" ) === 0; 15934 }) 15935 .attr( "tabIndex", -1 ); 15936 } 15937 15938 toShow.attr( "aria-hidden", "false" ); 15939 eventData.newTab.attr({ 15940 "aria-selected": "true", 15941 "aria-expanded": "true", 15942 tabIndex: 0 15943 }); 15944 }, 15945 15946 _activate: function( index ) { 15947 var anchor, 15948 active = this._findActive( index ); 15949 15950 // trying to activate the already active panel 15951 if ( active[ 0 ] === this.active[ 0 ] ) { 15952 return; 15953 } 15954 15955 // trying to collapse, simulate a click on the current active header 15956 if ( !active.length ) { 15957 active = this.active; 15958 } 15959 15960 anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; 15961 this._eventHandler({ 15962 target: anchor, 15963 currentTarget: anchor, 15964 preventDefault: $.noop 15965 }); 15966 }, 15967 15968 _findActive: function( index ) { 15969 return index === false ? $() : this.tabs.eq( index ); 15970 }, 15971 15972 _getIndex: function( index ) { 15973 // meta-function to give users option to provide a href string instead of a numerical index. 15974 if ( typeof index === "string" ) { 15975 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); 15976 } 15977 15978 return index; 15979 }, 15980 15981 _destroy: function() { 15982 if ( this.xhr ) { 15983 this.xhr.abort(); 15984 } 15985 15986 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); 15987 15988 this.tablist 15989 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) 15990 .removeAttr( "role" ); 15991 15992 this.anchors 15993 .removeClass( "ui-tabs-anchor" ) 15994 .removeAttr( "role" ) 15995 .removeAttr( "tabIndex" ) 15996 .removeUniqueId(); 15997 15998 this.tablist.unbind( this.eventNamespace ); 15999 16000 this.tabs.add( this.panels ).each(function() { 16001 if ( $.data( this, "ui-tabs-destroy" ) ) { 16002 $( this ).remove(); 16003 } else { 16004 $( this ) 16005 .removeClass( "ui-state-default ui-state-active ui-state-disabled " + 16006 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) 16007 .removeAttr( "tabIndex" ) 16008 .removeAttr( "aria-live" ) 16009 .removeAttr( "aria-busy" ) 16010 .removeAttr( "aria-selected" ) 16011 .removeAttr( "aria-labelledby" ) 16012 .removeAttr( "aria-hidden" ) 16013 .removeAttr( "aria-expanded" ) 16014 .removeAttr( "role" ); 16015 } 16016 }); 16017 16018 this.tabs.each(function() { 16019 var li = $( this ), 16020 prev = li.data( "ui-tabs-aria-controls" ); 16021 if ( prev ) { 16022 li 16023 .attr( "aria-controls", prev ) 16024 .removeData( "ui-tabs-aria-controls" ); 16025 } else { 16026 li.removeAttr( "aria-controls" ); 16027 } 16028 }); 16029 16030 this.panels.show(); 16031 16032 if ( this.options.heightStyle !== "content" ) { 16033 this.panels.css( "height", "" ); 16034 } 16035 }, 16036 16037 enable: function( index ) { 16038 var disabled = this.options.disabled; 16039 if ( disabled === false ) { 16040 return; 16041 } 16042 16043 if ( index === undefined ) { 16044 disabled = false; 16045 } else { 16046 index = this._getIndex( index ); 16047 if ( $.isArray( disabled ) ) { 16048 disabled = $.map( disabled, function( num ) { 16049 return num !== index ? num : null; 16050 }); 16051 } else { 16052 disabled = $.map( this.tabs, function( li, num ) { 16053 return num !== index ? num : null; 16054 }); 16055 } 16056 } 16057 this._setupDisabled( disabled ); 16058 }, 16059 16060 disable: function( index ) { 16061 var disabled = this.options.disabled; 16062 if ( disabled === true ) { 16063 return; 16064 } 16065 16066 if ( index === undefined ) { 16067 disabled = true; 16068 } else { 16069 index = this._getIndex( index ); 16070 if ( $.inArray( index, disabled ) !== -1 ) { 16071 return; 16072 } 16073 if ( $.isArray( disabled ) ) { 16074 disabled = $.merge( [ index ], disabled ).sort(); 16075 } else { 16076 disabled = [ index ]; 16077 } 16078 } 16079 this._setupDisabled( disabled ); 16080 }, 16081 16082 load: function( index, event ) { 16083 index = this._getIndex( index ); 16084 var that = this, 16085 tab = this.tabs.eq( index ), 16086 anchor = tab.find( ".ui-tabs-anchor" ), 16087 panel = this._getPanelForTab( tab ), 16088 eventData = { 16089 tab: tab, 16090 panel: panel 16091 }, 16092 complete = function( jqXHR, status ) { 16093 if ( status === "abort" ) { 16094 that.panels.stop( false, true ); 16095 } 16096 16097 tab.removeClass( "ui-tabs-loading" ); 16098 panel.removeAttr( "aria-busy" ); 16099 16100 if ( jqXHR === that.xhr ) { 16101 delete that.xhr; 16102 } 16103 }; 16104 16105 // not remote 16106 if ( this._isLocal( anchor[ 0 ] ) ) { 16107 return; 16108 } 16109 16110 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); 16111 16112 // support: jQuery <1.8 16113 // jQuery <1.8 returns false if the request is canceled in beforeSend, 16114 // but as of 1.8, $.ajax() always returns a jqXHR object. 16115 if ( this.xhr && this.xhr.statusText !== "canceled" ) { 16116 tab.addClass( "ui-tabs-loading" ); 16117 panel.attr( "aria-busy", "true" ); 16118 16119 this.xhr 16120 .done(function( response, status, jqXHR ) { 16121 // support: jQuery <1.8 16122 // http://bugs.jquery.com/ticket/11778 16123 setTimeout(function() { 16124 panel.html( response ); 16125 that._trigger( "load", event, eventData ); 16126 16127 complete( jqXHR, status ); 16128 }, 1 ); 16129 }) 16130 .fail(function( jqXHR, status ) { 16131 // support: jQuery <1.8 16132 // http://bugs.jquery.com/ticket/11778 16133 setTimeout(function() { 16134 complete( jqXHR, status ); 16135 }, 1 ); 16136 }); 16137 } 16138 }, 16139 16140 _ajaxSettings: function( anchor, event, eventData ) { 16141 var that = this; 16142 return { 16143 url: anchor.attr( "href" ), 16144 beforeSend: function( jqXHR, settings ) { 16145 return that._trigger( "beforeLoad", event, 16146 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); 16147 } 16148 }; 16149 }, 16150 16151 _getPanelForTab: function( tab ) { 16152 var id = $( tab ).attr( "aria-controls" ); 16153 return this.element.find( this._sanitizeSelector( "#" + id ) ); 16154 } 16155 }); 16156 16157 16158 /*! 16159 * jQuery UI Tooltip 1.11.4 16160 * http://jqueryui.com 16161 * 16162 * Copyright jQuery Foundation and other contributors 16163 * Released under the MIT license. 16164 * http://jquery.org/license 16165 * 16166 * http://api.jqueryui.com/tooltip/ 16167 */ 16168 16169 16170 var tooltip = $.widget( "ui.tooltip", { 16171 version: "1.11.4", 16172 options: { 16173 content: function() { 16174 // support: IE<9, Opera in jQuery <1.7 16175 // .text() can't accept undefined, so coerce to a string 16176 var title = $( this ).attr( "title" ) || ""; 16177 // Escape title, since we're going from an attribute to raw HTML 16178 return $( "<a>" ).text( title ).html(); 16179 }, 16180 hide: true, 16181 // Disabled elements have inconsistent behavior across browsers (#8661) 16182 items: "[title]:not([disabled])", 16183 position: { 16184 my: "left top+15", 16185 at: "left bottom", 16186 collision: "flipfit flip" 16187 }, 16188 show: true, 16189 tooltipClass: null, 16190 track: false, 16191 16192 // callbacks 16193 close: null, 16194 open: null 16195 }, 16196 16197 _addDescribedBy: function( elem, id ) { 16198 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); 16199 describedby.push( id ); 16200 elem 16201 .data( "ui-tooltip-id", id ) 16202 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); 16203 }, 16204 16205 _removeDescribedBy: function( elem ) { 16206 var id = elem.data( "ui-tooltip-id" ), 16207 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), 16208 index = $.inArray( id, describedby ); 16209 16210 if ( index !== -1 ) { 16211 describedby.splice( index, 1 ); 16212 } 16213 16214 elem.removeData( "ui-tooltip-id" ); 16215 describedby = $.trim( describedby.join( " " ) ); 16216 if ( describedby ) { 16217 elem.attr( "aria-describedby", describedby ); 16218 } else { 16219 elem.removeAttr( "aria-describedby" ); 16220 } 16221 }, 16222 16223 _create: function() { 16224 this._on({ 16225 mouseover: "open", 16226 focusin: "open" 16227 }); 16228 16229 // IDs of generated tooltips, needed for destroy 16230 this.tooltips = {}; 16231 16232 // IDs of parent tooltips where we removed the title attribute 16233 this.parents = {}; 16234 16235 if ( this.options.disabled ) { 16236 this._disable(); 16237 } 16238 16239 // Append the aria-live region so tooltips announce correctly 16240 this.liveRegion = $( "<div>" ) 16241 .attr({ 16242 role: "log", 16243 "aria-live": "assertive", 16244 "aria-relevant": "additions" 16245 }) 16246 .addClass( "ui-helper-hidden-accessible" ) 16247 .appendTo( this.document[ 0 ].body ); 16248 }, 16249 16250 _setOption: function( key, value ) { 16251 var that = this; 16252 16253 if ( key === "disabled" ) { 16254 this[ value ? "_disable" : "_enable" ](); 16255 this.options[ key ] = value; 16256 // disable element style changes 16257 return; 16258 } 16259 16260 this._super( key, value ); 16261 16262 if ( key === "content" ) { 16263 $.each( this.tooltips, function( id, tooltipData ) { 16264 that._updateContent( tooltipData.element ); 16265 }); 16266 } 16267 }, 16268 16269 _disable: function() { 16270 var that = this; 16271 16272 // close open tooltips 16273 $.each( this.tooltips, function( id, tooltipData ) { 16274 var event = $.Event( "blur" ); 16275 event.target = event.currentTarget = tooltipData.element[ 0 ]; 16276 that.close( event, true ); 16277 }); 16278 16279 // remove title attributes to prevent native tooltips 16280 this.element.find( this.options.items ).addBack().each(function() { 16281 var element = $( this ); 16282 if ( element.is( "[title]" ) ) { 16283 element 16284 .data( "ui-tooltip-title", element.attr( "title" ) ) 16285 .removeAttr( "title" ); 16286 } 16287 }); 16288 }, 16289 16290 _enable: function() { 16291 // restore title attributes 16292 this.element.find( this.options.items ).addBack().each(function() { 16293 var element = $( this ); 16294 if ( element.data( "ui-tooltip-title" ) ) { 16295 element.attr( "title", element.data( "ui-tooltip-title" ) ); 16296 } 16297 }); 16298 }, 16299 16300 open: function( event ) { 16301 var that = this, 16302 target = $( event ? event.target : this.element ) 16303 // we need closest here due to mouseover bubbling, 16304 // but always pointing at the same event target 16305 .closest( this.options.items ); 16306 16307 // No element to show a tooltip for or the tooltip is already open 16308 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 16309 return; 16310 } 16311 16312 if ( target.attr( "title" ) ) { 16313 target.data( "ui-tooltip-title", target.attr( "title" ) ); 16314 } 16315 16316 target.data( "ui-tooltip-open", true ); 16317 16318 // kill parent tooltips, custom or native, for hover 16319 if ( event && event.type === "mouseover" ) { 16320 target.parents().each(function() { 16321 var parent = $( this ), 16322 blurEvent; 16323 if ( parent.data( "ui-tooltip-open" ) ) { 16324 blurEvent = $.Event( "blur" ); 16325 blurEvent.target = blurEvent.currentTarget = this; 16326 that.close( blurEvent, true ); 16327 } 16328 if ( parent.attr( "title" ) ) { 16329 parent.uniqueId(); 16330 that.parents[ this.id ] = { 16331 element: this, 16332 title: parent.attr( "title" ) 16333 }; 16334 parent.attr( "title", "" ); 16335 } 16336 }); 16337 } 16338 16339 this._registerCloseHandlers( event, target ); 16340 this._updateContent( target, event ); 16341 }, 16342 16343 _updateContent: function( target, event ) { 16344 var content, 16345 contentOption = this.options.content, 16346 that = this, 16347 eventType = event ? event.type : null; 16348 16349 if ( typeof contentOption === "string" ) { 16350 return this._open( event, target, contentOption ); 16351 } 16352 16353 content = contentOption.call( target[0], function( response ) { 16354 16355 // IE may instantly serve a cached response for ajax requests 16356 // delay this call to _open so the other call to _open runs first 16357 that._delay(function() { 16358 16359 // Ignore async response if tooltip was closed already 16360 if ( !target.data( "ui-tooltip-open" ) ) { 16361 return; 16362 } 16363 16364 // jQuery creates a special event for focusin when it doesn't 16365 // exist natively. To improve performance, the native event 16366 // object is reused and the type is changed. Therefore, we can't 16367 // rely on the type being correct after the event finished 16368 // bubbling, so we set it back to the previous value. (#8740) 16369 if ( event ) { 16370 event.type = eventType; 16371 } 16372 this._open( event, target, response ); 16373 }); 16374 }); 16375 if ( content ) { 16376 this._open( event, target, content ); 16377 } 16378 }, 16379 16380 _open: function( event, target, content ) { 16381 var tooltipData, tooltip, delayedShow, a11yContent, 16382 positionOption = $.extend( {}, this.options.position ); 16383 16384 if ( !content ) { 16385 return; 16386 } 16387 16388 // Content can be updated multiple times. If the tooltip already 16389 // exists, then just update the content and bail. 16390 tooltipData = this._find( target ); 16391 if ( tooltipData ) { 16392 tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); 16393 return; 16394 } 16395 16396 // if we have a title, clear it to prevent the native tooltip 16397 // we have to check first to avoid defining a title if none exists 16398 // (we don't want to cause an element to start matching [title]) 16399 // 16400 // We use removeAttr only for key events, to allow IE to export the correct 16401 // accessible attributes. For mouse events, set to empty string to avoid 16402 // native tooltip showing up (happens only when removing inside mouseover). 16403 if ( target.is( "[title]" ) ) { 16404 if ( event && event.type === "mouseover" ) { 16405 target.attr( "title", "" ); 16406 } else { 16407 target.removeAttr( "title" ); 16408 } 16409 } 16410 16411 tooltipData = this._tooltip( target ); 16412 tooltip = tooltipData.tooltip; 16413 this._addDescribedBy( target, tooltip.attr( "id" ) ); 16414 tooltip.find( ".ui-tooltip-content" ).html( content ); 16415 16416 // Support: Voiceover on OS X, JAWS on IE <= 9 16417 // JAWS announces deletions even when aria-relevant="additions" 16418 // Voiceover will sometimes re-read the entire log region's contents from the beginning 16419 this.liveRegion.children().hide(); 16420 if ( content.clone ) { 16421 a11yContent = content.clone(); 16422 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 16423 } else { 16424 a11yContent = content; 16425 } 16426 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion ); 16427 16428 function position( event ) { 16429 positionOption.of = event; 16430 if ( tooltip.is( ":hidden" ) ) { 16431 return; 16432 } 16433 tooltip.position( positionOption ); 16434 } 16435 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 16436 this._on( this.document, { 16437 mousemove: position 16438 }); 16439 // trigger once to override element-relative positioning 16440 position( event ); 16441 } else { 16442 tooltip.position( $.extend({ 16443 of: target 16444 }, this.options.position ) ); 16445 } 16446 16447 tooltip.hide(); 16448 16449 this._show( tooltip, this.options.show ); 16450 // Handle tracking tooltips that are shown with a delay (#8644). As soon 16451 // as the tooltip is visible, position the tooltip using the most recent 16452 // event. 16453 if ( this.options.show && this.options.show.delay ) { 16454 delayedShow = this.delayedShow = setInterval(function() { 16455 if ( tooltip.is( ":visible" ) ) { 16456 position( positionOption.of ); 16457 clearInterval( delayedShow ); 16458 } 16459 }, $.fx.interval ); 16460 } 16461 16462 this._trigger( "open", event, { tooltip: tooltip } ); 16463 }, 16464 16465 _registerCloseHandlers: function( event, target ) { 16466 var events = { 16467 keyup: function( event ) { 16468 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 16469 var fakeEvent = $.Event(event); 16470 fakeEvent.currentTarget = target[0]; 16471 this.close( fakeEvent, true ); 16472 } 16473 } 16474 }; 16475 16476 // Only bind remove handler for delegated targets. Non-delegated 16477 // tooltips will handle this in destroy. 16478 if ( target[ 0 ] !== this.element[ 0 ] ) { 16479 events.remove = function() { 16480 this._removeTooltip( this._find( target ).tooltip ); 16481 }; 16482 } 16483 16484 if ( !event || event.type === "mouseover" ) { 16485 events.mouseleave = "close"; 16486 } 16487 if ( !event || event.type === "focusin" ) { 16488 events.focusout = "close"; 16489 } 16490 this._on( true, target, events ); 16491 }, 16492 16493 close: function( event ) { 16494 var tooltip, 16495 that = this, 16496 target = $( event ? event.currentTarget : this.element ), 16497 tooltipData = this._find( target ); 16498 16499 // The tooltip may already be closed 16500 if ( !tooltipData ) { 16501 16502 // We set ui-tooltip-open immediately upon open (in open()), but only set the 16503 // additional data once there's actually content to show (in _open()). So even if the 16504 // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in 16505 // the period between open() and _open(). 16506 target.removeData( "ui-tooltip-open" ); 16507 return; 16508 } 16509 16510 tooltip = tooltipData.tooltip; 16511 16512 // disabling closes the tooltip, so we need to track when we're closing 16513 // to avoid an infinite loop in case the tooltip becomes disabled on close 16514 if ( tooltipData.closing ) { 16515 return; 16516 } 16517 16518 // Clear the interval for delayed tracking tooltips 16519 clearInterval( this.delayedShow ); 16520 16521 // only set title if we had one before (see comment in _open()) 16522 // If the title attribute has changed since open(), don't restore 16523 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 16524 target.attr( "title", target.data( "ui-tooltip-title" ) ); 16525 } 16526 16527 this._removeDescribedBy( target ); 16528 16529 tooltipData.hiding = true; 16530 tooltip.stop( true ); 16531 this._hide( tooltip, this.options.hide, function() { 16532 that._removeTooltip( $( this ) ); 16533 }); 16534 16535 target.removeData( "ui-tooltip-open" ); 16536 this._off( target, "mouseleave focusout keyup" ); 16537 16538 // Remove 'remove' binding only on delegated targets 16539 if ( target[ 0 ] !== this.element[ 0 ] ) { 16540 this._off( target, "remove" ); 16541 } 16542 this._off( this.document, "mousemove" ); 16543 16544 if ( event && event.type === "mouseleave" ) { 16545 $.each( this.parents, function( id, parent ) { 16546 $( parent.element ).attr( "title", parent.title ); 16547 delete that.parents[ id ]; 16548 }); 16549 } 16550 16551 tooltipData.closing = true; 16552 this._trigger( "close", event, { tooltip: tooltip } ); 16553 if ( !tooltipData.hiding ) { 16554 tooltipData.closing = false; 16555 } 16556 }, 16557 16558 _tooltip: function( element ) { 16559 var tooltip = $( "<div>" ) 16560 .attr( "role", "tooltip" ) 16561 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + 16562 ( this.options.tooltipClass || "" ) ), 16563 id = tooltip.uniqueId().attr( "id" ); 16564 16565 $( "<div>" ) 16566 .addClass( "ui-tooltip-content" ) 16567 .appendTo( tooltip ); 16568 16569 tooltip.appendTo( this.document[0].body ); 16570 16571 return this.tooltips[ id ] = { 16572 element: element, 16573 tooltip: tooltip 16574 }; 16575 }, 16576 16577 _find: function( target ) { 16578 var id = target.data( "ui-tooltip-id" ); 16579 return id ? this.tooltips[ id ] : null; 16580 }, 16581 16582 _removeTooltip: function( tooltip ) { 16583 tooltip.remove(); 16584 delete this.tooltips[ tooltip.attr( "id" ) ]; 16585 }, 16586 16587 _destroy: function() { 16588 var that = this; 16589 16590 // close open tooltips 16591 $.each( this.tooltips, function( id, tooltipData ) { 16592 // Delegate to close method to handle common cleanup 16593 var event = $.Event( "blur" ), 16594 element = tooltipData.element; 16595 event.target = event.currentTarget = element[ 0 ]; 16596 that.close( event, true ); 16597 16598 // Remove immediately; destroying an open tooltip doesn't use the 16599 // hide animation 16600 $( "#" + id ).remove(); 16601 16602 // Restore the title 16603 if ( element.data( "ui-tooltip-title" ) ) { 16604 // If the title attribute has changed since open(), don't restore 16605 if ( !element.attr( "title" ) ) { 16606 element.attr( "title", element.data( "ui-tooltip-title" ) ); 16607 } 16608 element.removeData( "ui-tooltip-title" ); 16609 } 16610 }); 16611 this.liveRegion.remove(); 16612 } 16613 }); 16614 16615 16616 16617 }));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body