[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 /*! jQuery UI - v1.11.1 - 2014-08-13 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 2014 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.1 19 * http://jqueryui.com 20 * 21 * Copyright 2014 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.1", 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.1 313 * http://jqueryui.com 314 * 315 * Copyright 2014 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 // allow multiple hashes to be passed on init 494 options = !isMethodCall && args.length ? 495 $.widget.extend.apply( null, [ options ].concat(args) ) : 496 options; 497 498 if ( isMethodCall ) { 499 this.each(function() { 500 var methodValue, 501 instance = $.data( this, fullName ); 502 if ( options === "instance" ) { 503 returnValue = instance; 504 return false; 505 } 506 if ( !instance ) { 507 return $.error( "cannot call methods on " + name + " prior to initialization; " + 508 "attempted to call method '" + options + "'" ); 509 } 510 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { 511 return $.error( "no such method '" + options + "' for " + name + " widget instance" ); 512 } 513 methodValue = instance[ options ].apply( instance, args ); 514 if ( methodValue !== instance && methodValue !== undefined ) { 515 returnValue = methodValue && methodValue.jquery ? 516 returnValue.pushStack( methodValue.get() ) : 517 methodValue; 518 return false; 519 } 520 }); 521 } else { 522 this.each(function() { 523 var instance = $.data( this, fullName ); 524 if ( instance ) { 525 instance.option( options || {} ); 526 if ( instance._init ) { 527 instance._init(); 528 } 529 } else { 530 $.data( this, fullName, new object( options, this ) ); 531 } 532 }); 533 } 534 535 return returnValue; 536 }; 537 }; 538 539 $.Widget = function( /* options, element */ ) {}; 540 $.Widget._childConstructors = []; 541 542 $.Widget.prototype = { 543 widgetName: "widget", 544 widgetEventPrefix: "", 545 defaultElement: "<div>", 546 options: { 547 disabled: false, 548 549 // callbacks 550 create: null 551 }, 552 _createWidget: function( options, element ) { 553 element = $( element || this.defaultElement || this )[ 0 ]; 554 this.element = $( element ); 555 this.uuid = widget_uuid++; 556 this.eventNamespace = "." + this.widgetName + this.uuid; 557 this.options = $.widget.extend( {}, 558 this.options, 559 this._getCreateOptions(), 560 options ); 561 562 this.bindings = $(); 563 this.hoverable = $(); 564 this.focusable = $(); 565 566 if ( element !== this ) { 567 $.data( element, this.widgetFullName, this ); 568 this._on( true, this.element, { 569 remove: function( event ) { 570 if ( event.target === element ) { 571 this.destroy(); 572 } 573 } 574 }); 575 this.document = $( element.style ? 576 // element within the document 577 element.ownerDocument : 578 // element is window or document 579 element.document || element ); 580 this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); 581 } 582 583 this._create(); 584 this._trigger( "create", null, this._getCreateEventData() ); 585 this._init(); 586 }, 587 _getCreateOptions: $.noop, 588 _getCreateEventData: $.noop, 589 _create: $.noop, 590 _init: $.noop, 591 592 destroy: function() { 593 this._destroy(); 594 // we can probably remove the unbind calls in 2.0 595 // all event bindings should go through this._on() 596 this.element 597 .unbind( this.eventNamespace ) 598 .removeData( this.widgetFullName ) 599 // support: jquery <1.6.3 600 // http://bugs.jquery.com/ticket/9413 601 .removeData( $.camelCase( this.widgetFullName ) ); 602 this.widget() 603 .unbind( this.eventNamespace ) 604 .removeAttr( "aria-disabled" ) 605 .removeClass( 606 this.widgetFullName + "-disabled " + 607 "ui-state-disabled" ); 608 609 // clean up events and states 610 this.bindings.unbind( this.eventNamespace ); 611 this.hoverable.removeClass( "ui-state-hover" ); 612 this.focusable.removeClass( "ui-state-focus" ); 613 }, 614 _destroy: $.noop, 615 616 widget: function() { 617 return this.element; 618 }, 619 620 option: function( key, value ) { 621 var options = key, 622 parts, 623 curOption, 624 i; 625 626 if ( arguments.length === 0 ) { 627 // don't return a reference to the internal hash 628 return $.widget.extend( {}, this.options ); 629 } 630 631 if ( typeof key === "string" ) { 632 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } 633 options = {}; 634 parts = key.split( "." ); 635 key = parts.shift(); 636 if ( parts.length ) { 637 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); 638 for ( i = 0; i < parts.length - 1; i++ ) { 639 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; 640 curOption = curOption[ parts[ i ] ]; 641 } 642 key = parts.pop(); 643 if ( arguments.length === 1 ) { 644 return curOption[ key ] === undefined ? null : curOption[ key ]; 645 } 646 curOption[ key ] = value; 647 } else { 648 if ( arguments.length === 1 ) { 649 return this.options[ key ] === undefined ? null : this.options[ key ]; 650 } 651 options[ key ] = value; 652 } 653 } 654 655 this._setOptions( options ); 656 657 return this; 658 }, 659 _setOptions: function( options ) { 660 var key; 661 662 for ( key in options ) { 663 this._setOption( key, options[ key ] ); 664 } 665 666 return this; 667 }, 668 _setOption: function( key, value ) { 669 this.options[ key ] = value; 670 671 if ( key === "disabled" ) { 672 this.widget() 673 .toggleClass( this.widgetFullName + "-disabled", !!value ); 674 675 // If the widget is becoming disabled, then nothing is interactive 676 if ( value ) { 677 this.hoverable.removeClass( "ui-state-hover" ); 678 this.focusable.removeClass( "ui-state-focus" ); 679 } 680 } 681 682 return this; 683 }, 684 685 enable: function() { 686 return this._setOptions({ disabled: false }); 687 }, 688 disable: function() { 689 return this._setOptions({ disabled: true }); 690 }, 691 692 _on: function( suppressDisabledCheck, element, handlers ) { 693 var delegateElement, 694 instance = this; 695 696 // no suppressDisabledCheck flag, shuffle arguments 697 if ( typeof suppressDisabledCheck !== "boolean" ) { 698 handlers = element; 699 element = suppressDisabledCheck; 700 suppressDisabledCheck = false; 701 } 702 703 // no element argument, shuffle and use this.element 704 if ( !handlers ) { 705 handlers = element; 706 element = this.element; 707 delegateElement = this.widget(); 708 } else { 709 element = delegateElement = $( element ); 710 this.bindings = this.bindings.add( element ); 711 } 712 713 $.each( handlers, function( event, handler ) { 714 function handlerProxy() { 715 // allow widgets to customize the disabled handling 716 // - disabled as an array instead of boolean 717 // - disabled class as method for disabling individual parts 718 if ( !suppressDisabledCheck && 719 ( instance.options.disabled === true || 720 $( this ).hasClass( "ui-state-disabled" ) ) ) { 721 return; 722 } 723 return ( typeof handler === "string" ? instance[ handler ] : handler ) 724 .apply( instance, arguments ); 725 } 726 727 // copy the guid so direct unbinding works 728 if ( typeof handler !== "string" ) { 729 handlerProxy.guid = handler.guid = 730 handler.guid || handlerProxy.guid || $.guid++; 731 } 732 733 var match = event.match( /^([\w:-]*)\s*(.*)$/ ), 734 eventName = match[1] + instance.eventNamespace, 735 selector = match[2]; 736 if ( selector ) { 737 delegateElement.delegate( selector, eventName, handlerProxy ); 738 } else { 739 element.bind( eventName, handlerProxy ); 740 } 741 }); 742 }, 743 744 _off: function( element, eventName ) { 745 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; 746 element.unbind( eventName ).undelegate( eventName ); 747 }, 748 749 _delay: function( handler, delay ) { 750 function handlerProxy() { 751 return ( typeof handler === "string" ? instance[ handler ] : handler ) 752 .apply( instance, arguments ); 753 } 754 var instance = this; 755 return setTimeout( handlerProxy, delay || 0 ); 756 }, 757 758 _hoverable: function( element ) { 759 this.hoverable = this.hoverable.add( element ); 760 this._on( element, { 761 mouseenter: function( event ) { 762 $( event.currentTarget ).addClass( "ui-state-hover" ); 763 }, 764 mouseleave: function( event ) { 765 $( event.currentTarget ).removeClass( "ui-state-hover" ); 766 } 767 }); 768 }, 769 770 _focusable: function( element ) { 771 this.focusable = this.focusable.add( element ); 772 this._on( element, { 773 focusin: function( event ) { 774 $( event.currentTarget ).addClass( "ui-state-focus" ); 775 }, 776 focusout: function( event ) { 777 $( event.currentTarget ).removeClass( "ui-state-focus" ); 778 } 779 }); 780 }, 781 782 _trigger: function( type, event, data ) { 783 var prop, orig, 784 callback = this.options[ type ]; 785 786 data = data || {}; 787 event = $.Event( event ); 788 event.type = ( type === this.widgetEventPrefix ? 789 type : 790 this.widgetEventPrefix + type ).toLowerCase(); 791 // the original event may come from any element 792 // so we need to reset the target on the new event 793 event.target = this.element[ 0 ]; 794 795 // copy original event properties over to the new event 796 orig = event.originalEvent; 797 if ( orig ) { 798 for ( prop in orig ) { 799 if ( !( prop in event ) ) { 800 event[ prop ] = orig[ prop ]; 801 } 802 } 803 } 804 805 this.element.trigger( event, data ); 806 return !( $.isFunction( callback ) && 807 callback.apply( this.element[0], [ event ].concat( data ) ) === false || 808 event.isDefaultPrevented() ); 809 } 810 }; 811 812 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { 813 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { 814 if ( typeof options === "string" ) { 815 options = { effect: options }; 816 } 817 var hasOptions, 818 effectName = !options ? 819 method : 820 options === true || typeof options === "number" ? 821 defaultEffect : 822 options.effect || defaultEffect; 823 options = options || {}; 824 if ( typeof options === "number" ) { 825 options = { duration: options }; 826 } 827 hasOptions = !$.isEmptyObject( options ); 828 options.complete = callback; 829 if ( options.delay ) { 830 element.delay( options.delay ); 831 } 832 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { 833 element[ method ]( options ); 834 } else if ( effectName !== method && element[ effectName ] ) { 835 element[ effectName ]( options.duration, options.easing, callback ); 836 } else { 837 element.queue(function( next ) { 838 $( this )[ method ](); 839 if ( callback ) { 840 callback.call( element[ 0 ] ); 841 } 842 next(); 843 }); 844 } 845 }; 846 }); 847 848 var widget = $.widget; 849 850 851 /*! 852 * jQuery UI Mouse 1.11.1 853 * http://jqueryui.com 854 * 855 * Copyright 2014 jQuery Foundation and other contributors 856 * Released under the MIT license. 857 * http://jquery.org/license 858 * 859 * http://api.jqueryui.com/mouse/ 860 */ 861 862 863 var mouseHandled = false; 864 $( document ).mouseup( function() { 865 mouseHandled = false; 866 }); 867 868 var mouse = $.widget("ui.mouse", { 869 version: "1.11.1", 870 options: { 871 cancel: "input,textarea,button,select,option", 872 distance: 1, 873 delay: 0 874 }, 875 _mouseInit: function() { 876 var that = this; 877 878 this.element 879 .bind("mousedown." + this.widgetName, function(event) { 880 return that._mouseDown(event); 881 }) 882 .bind("click." + this.widgetName, function(event) { 883 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { 884 $.removeData(event.target, that.widgetName + ".preventClickEvent"); 885 event.stopImmediatePropagation(); 886 return false; 887 } 888 }); 889 890 this.started = false; 891 }, 892 893 // TODO: make sure destroying one instance of mouse doesn't mess with 894 // other instances of mouse 895 _mouseDestroy: function() { 896 this.element.unbind("." + this.widgetName); 897 if ( this._mouseMoveDelegate ) { 898 this.document 899 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate) 900 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate); 901 } 902 }, 903 904 _mouseDown: function(event) { 905 // don't let more than one widget handle mouseStart 906 if ( mouseHandled ) { 907 return; 908 } 909 910 // we may have missed mouseup (out of window) 911 (this._mouseStarted && this._mouseUp(event)); 912 913 this._mouseDownEvent = event; 914 915 var that = this, 916 btnIsLeft = (event.which === 1), 917 // event.target.nodeName works around a bug in IE 8 with 918 // disabled inputs (#7620) 919 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); 920 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { 921 return true; 922 } 923 924 this.mouseDelayMet = !this.options.delay; 925 if (!this.mouseDelayMet) { 926 this._mouseDelayTimer = setTimeout(function() { 927 that.mouseDelayMet = true; 928 }, this.options.delay); 929 } 930 931 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 932 this._mouseStarted = (this._mouseStart(event) !== false); 933 if (!this._mouseStarted) { 934 event.preventDefault(); 935 return true; 936 } 937 } 938 939 // Click event may never have fired (Gecko & Opera) 940 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { 941 $.removeData(event.target, this.widgetName + ".preventClickEvent"); 942 } 943 944 // these delegates are required to keep context 945 this._mouseMoveDelegate = function(event) { 946 return that._mouseMove(event); 947 }; 948 this._mouseUpDelegate = function(event) { 949 return that._mouseUp(event); 950 }; 951 952 this.document 953 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 954 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate ); 955 956 event.preventDefault(); 957 958 mouseHandled = true; 959 return true; 960 }, 961 962 _mouseMove: function(event) { 963 // IE mouseup check - mouseup happened when mouse was out of window 964 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { 965 return this._mouseUp(event); 966 967 // Iframe mouseup check - mouseup occurred in another document 968 } else if ( !event.which ) { 969 return this._mouseUp( event ); 970 } 971 972 if (this._mouseStarted) { 973 this._mouseDrag(event); 974 return event.preventDefault(); 975 } 976 977 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { 978 this._mouseStarted = 979 (this._mouseStart(this._mouseDownEvent, event) !== false); 980 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); 981 } 982 983 return !this._mouseStarted; 984 }, 985 986 _mouseUp: function(event) { 987 this.document 988 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate ) 989 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate ); 990 991 if (this._mouseStarted) { 992 this._mouseStarted = false; 993 994 if (event.target === this._mouseDownEvent.target) { 995 $.data(event.target, this.widgetName + ".preventClickEvent", true); 996 } 997 998 this._mouseStop(event); 999 } 1000 1001 mouseHandled = false; 1002 return false; 1003 }, 1004 1005 _mouseDistanceMet: function(event) { 1006 return (Math.max( 1007 Math.abs(this._mouseDownEvent.pageX - event.pageX), 1008 Math.abs(this._mouseDownEvent.pageY - event.pageY) 1009 ) >= this.options.distance 1010 ); 1011 }, 1012 1013 _mouseDelayMet: function(/* event */) { 1014 return this.mouseDelayMet; 1015 }, 1016 1017 // These are placeholder methods, to be overriden by extending plugin 1018 _mouseStart: function(/* event */) {}, 1019 _mouseDrag: function(/* event */) {}, 1020 _mouseStop: function(/* event */) {}, 1021 _mouseCapture: function(/* event */) { return true; } 1022 }); 1023 1024 1025 /*! 1026 * jQuery UI Position 1.11.1 1027 * http://jqueryui.com 1028 * 1029 * Copyright 2014 jQuery Foundation and other contributors 1030 * Released under the MIT license. 1031 * http://jquery.org/license 1032 * 1033 * http://api.jqueryui.com/position/ 1034 */ 1035 1036 (function() { 1037 1038 $.ui = $.ui || {}; 1039 1040 var cachedScrollbarWidth, supportsOffsetFractions, 1041 max = Math.max, 1042 abs = Math.abs, 1043 round = Math.round, 1044 rhorizontal = /left|center|right/, 1045 rvertical = /top|center|bottom/, 1046 roffset = /[\+\-]\d+(\.[\d]+)?%?/, 1047 rposition = /^\w+/, 1048 rpercent = /%$/, 1049 _position = $.fn.position; 1050 1051 function getOffsets( offsets, width, height ) { 1052 return [ 1053 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), 1054 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) 1055 ]; 1056 } 1057 1058 function parseCss( element, property ) { 1059 return parseInt( $.css( element, property ), 10 ) || 0; 1060 } 1061 1062 function getDimensions( elem ) { 1063 var raw = elem[0]; 1064 if ( raw.nodeType === 9 ) { 1065 return { 1066 width: elem.width(), 1067 height: elem.height(), 1068 offset: { top: 0, left: 0 } 1069 }; 1070 } 1071 if ( $.isWindow( raw ) ) { 1072 return { 1073 width: elem.width(), 1074 height: elem.height(), 1075 offset: { top: elem.scrollTop(), left: elem.scrollLeft() } 1076 }; 1077 } 1078 if ( raw.preventDefault ) { 1079 return { 1080 width: 0, 1081 height: 0, 1082 offset: { top: raw.pageY, left: raw.pageX } 1083 }; 1084 } 1085 return { 1086 width: elem.outerWidth(), 1087 height: elem.outerHeight(), 1088 offset: elem.offset() 1089 }; 1090 } 1091 1092 $.position = { 1093 scrollbarWidth: function() { 1094 if ( cachedScrollbarWidth !== undefined ) { 1095 return cachedScrollbarWidth; 1096 } 1097 var w1, w2, 1098 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ), 1099 innerDiv = div.children()[0]; 1100 1101 $( "body" ).append( div ); 1102 w1 = innerDiv.offsetWidth; 1103 div.css( "overflow", "scroll" ); 1104 1105 w2 = innerDiv.offsetWidth; 1106 1107 if ( w1 === w2 ) { 1108 w2 = div[0].clientWidth; 1109 } 1110 1111 div.remove(); 1112 1113 return (cachedScrollbarWidth = w1 - w2); 1114 }, 1115 getScrollInfo: function( within ) { 1116 var overflowX = within.isWindow || within.isDocument ? "" : 1117 within.element.css( "overflow-x" ), 1118 overflowY = within.isWindow || within.isDocument ? "" : 1119 within.element.css( "overflow-y" ), 1120 hasOverflowX = overflowX === "scroll" || 1121 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ), 1122 hasOverflowY = overflowY === "scroll" || 1123 ( overflowY === "auto" && within.height < within.element[0].scrollHeight ); 1124 return { 1125 width: hasOverflowY ? $.position.scrollbarWidth() : 0, 1126 height: hasOverflowX ? $.position.scrollbarWidth() : 0 1127 }; 1128 }, 1129 getWithinInfo: function( element ) { 1130 var withinElement = $( element || window ), 1131 isWindow = $.isWindow( withinElement[0] ), 1132 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9; 1133 return { 1134 element: withinElement, 1135 isWindow: isWindow, 1136 isDocument: isDocument, 1137 offset: withinElement.offset() || { left: 0, top: 0 }, 1138 scrollLeft: withinElement.scrollLeft(), 1139 scrollTop: withinElement.scrollTop(), 1140 1141 // support: jQuery 1.6.x 1142 // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows 1143 width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(), 1144 height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight() 1145 }; 1146 } 1147 }; 1148 1149 $.fn.position = function( options ) { 1150 if ( !options || !options.of ) { 1151 return _position.apply( this, arguments ); 1152 } 1153 1154 // make a copy, we don't want to modify arguments 1155 options = $.extend( {}, options ); 1156 1157 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, 1158 target = $( options.of ), 1159 within = $.position.getWithinInfo( options.within ), 1160 scrollInfo = $.position.getScrollInfo( within ), 1161 collision = ( options.collision || "flip" ).split( " " ), 1162 offsets = {}; 1163 1164 dimensions = getDimensions( target ); 1165 if ( target[0].preventDefault ) { 1166 // force left top to allow flipping 1167 options.at = "left top"; 1168 } 1169 targetWidth = dimensions.width; 1170 targetHeight = dimensions.height; 1171 targetOffset = dimensions.offset; 1172 // clone to reuse original targetOffset later 1173 basePosition = $.extend( {}, targetOffset ); 1174 1175 // force my and at to have valid horizontal and vertical positions 1176 // if a value is missing or invalid, it will be converted to center 1177 $.each( [ "my", "at" ], function() { 1178 var pos = ( options[ this ] || "" ).split( " " ), 1179 horizontalOffset, 1180 verticalOffset; 1181 1182 if ( pos.length === 1) { 1183 pos = rhorizontal.test( pos[ 0 ] ) ? 1184 pos.concat( [ "center" ] ) : 1185 rvertical.test( pos[ 0 ] ) ? 1186 [ "center" ].concat( pos ) : 1187 [ "center", "center" ]; 1188 } 1189 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; 1190 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; 1191 1192 // calculate offsets 1193 horizontalOffset = roffset.exec( pos[ 0 ] ); 1194 verticalOffset = roffset.exec( pos[ 1 ] ); 1195 offsets[ this ] = [ 1196 horizontalOffset ? horizontalOffset[ 0 ] : 0, 1197 verticalOffset ? verticalOffset[ 0 ] : 0 1198 ]; 1199 1200 // reduce to just the positions without the offsets 1201 options[ this ] = [ 1202 rposition.exec( pos[ 0 ] )[ 0 ], 1203 rposition.exec( pos[ 1 ] )[ 0 ] 1204 ]; 1205 }); 1206 1207 // normalize collision option 1208 if ( collision.length === 1 ) { 1209 collision[ 1 ] = collision[ 0 ]; 1210 } 1211 1212 if ( options.at[ 0 ] === "right" ) { 1213 basePosition.left += targetWidth; 1214 } else if ( options.at[ 0 ] === "center" ) { 1215 basePosition.left += targetWidth / 2; 1216 } 1217 1218 if ( options.at[ 1 ] === "bottom" ) { 1219 basePosition.top += targetHeight; 1220 } else if ( options.at[ 1 ] === "center" ) { 1221 basePosition.top += targetHeight / 2; 1222 } 1223 1224 atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); 1225 basePosition.left += atOffset[ 0 ]; 1226 basePosition.top += atOffset[ 1 ]; 1227 1228 return this.each(function() { 1229 var collisionPosition, using, 1230 elem = $( this ), 1231 elemWidth = elem.outerWidth(), 1232 elemHeight = elem.outerHeight(), 1233 marginLeft = parseCss( this, "marginLeft" ), 1234 marginTop = parseCss( this, "marginTop" ), 1235 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width, 1236 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height, 1237 position = $.extend( {}, basePosition ), 1238 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); 1239 1240 if ( options.my[ 0 ] === "right" ) { 1241 position.left -= elemWidth; 1242 } else if ( options.my[ 0 ] === "center" ) { 1243 position.left -= elemWidth / 2; 1244 } 1245 1246 if ( options.my[ 1 ] === "bottom" ) { 1247 position.top -= elemHeight; 1248 } else if ( options.my[ 1 ] === "center" ) { 1249 position.top -= elemHeight / 2; 1250 } 1251 1252 position.left += myOffset[ 0 ]; 1253 position.top += myOffset[ 1 ]; 1254 1255 // if the browser doesn't support fractions, then round for consistent results 1256 if ( !supportsOffsetFractions ) { 1257 position.left = round( position.left ); 1258 position.top = round( position.top ); 1259 } 1260 1261 collisionPosition = { 1262 marginLeft: marginLeft, 1263 marginTop: marginTop 1264 }; 1265 1266 $.each( [ "left", "top" ], function( i, dir ) { 1267 if ( $.ui.position[ collision[ i ] ] ) { 1268 $.ui.position[ collision[ i ] ][ dir ]( position, { 1269 targetWidth: targetWidth, 1270 targetHeight: targetHeight, 1271 elemWidth: elemWidth, 1272 elemHeight: elemHeight, 1273 collisionPosition: collisionPosition, 1274 collisionWidth: collisionWidth, 1275 collisionHeight: collisionHeight, 1276 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], 1277 my: options.my, 1278 at: options.at, 1279 within: within, 1280 elem: elem 1281 }); 1282 } 1283 }); 1284 1285 if ( options.using ) { 1286 // adds feedback as second argument to using callback, if present 1287 using = function( props ) { 1288 var left = targetOffset.left - position.left, 1289 right = left + targetWidth - elemWidth, 1290 top = targetOffset.top - position.top, 1291 bottom = top + targetHeight - elemHeight, 1292 feedback = { 1293 target: { 1294 element: target, 1295 left: targetOffset.left, 1296 top: targetOffset.top, 1297 width: targetWidth, 1298 height: targetHeight 1299 }, 1300 element: { 1301 element: elem, 1302 left: position.left, 1303 top: position.top, 1304 width: elemWidth, 1305 height: elemHeight 1306 }, 1307 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", 1308 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" 1309 }; 1310 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { 1311 feedback.horizontal = "center"; 1312 } 1313 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { 1314 feedback.vertical = "middle"; 1315 } 1316 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { 1317 feedback.important = "horizontal"; 1318 } else { 1319 feedback.important = "vertical"; 1320 } 1321 options.using.call( this, props, feedback ); 1322 }; 1323 } 1324 1325 elem.offset( $.extend( position, { using: using } ) ); 1326 }); 1327 }; 1328 1329 $.ui.position = { 1330 fit: { 1331 left: function( position, data ) { 1332 var within = data.within, 1333 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, 1334 outerWidth = within.width, 1335 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1336 overLeft = withinOffset - collisionPosLeft, 1337 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, 1338 newOverRight; 1339 1340 // element is wider than within 1341 if ( data.collisionWidth > outerWidth ) { 1342 // element is initially over the left side of within 1343 if ( overLeft > 0 && overRight <= 0 ) { 1344 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset; 1345 position.left += overLeft - newOverRight; 1346 // element is initially over right side of within 1347 } else if ( overRight > 0 && overLeft <= 0 ) { 1348 position.left = withinOffset; 1349 // element is initially over both left and right sides of within 1350 } else { 1351 if ( overLeft > overRight ) { 1352 position.left = withinOffset + outerWidth - data.collisionWidth; 1353 } else { 1354 position.left = withinOffset; 1355 } 1356 } 1357 // too far left -> align with left edge 1358 } else if ( overLeft > 0 ) { 1359 position.left += overLeft; 1360 // too far right -> align with right edge 1361 } else if ( overRight > 0 ) { 1362 position.left -= overRight; 1363 // adjust based on position and margin 1364 } else { 1365 position.left = max( position.left - collisionPosLeft, position.left ); 1366 } 1367 }, 1368 top: function( position, data ) { 1369 var within = data.within, 1370 withinOffset = within.isWindow ? within.scrollTop : within.offset.top, 1371 outerHeight = data.within.height, 1372 collisionPosTop = position.top - data.collisionPosition.marginTop, 1373 overTop = withinOffset - collisionPosTop, 1374 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, 1375 newOverBottom; 1376 1377 // element is taller than within 1378 if ( data.collisionHeight > outerHeight ) { 1379 // element is initially over the top of within 1380 if ( overTop > 0 && overBottom <= 0 ) { 1381 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset; 1382 position.top += overTop - newOverBottom; 1383 // element is initially over bottom of within 1384 } else if ( overBottom > 0 && overTop <= 0 ) { 1385 position.top = withinOffset; 1386 // element is initially over both top and bottom of within 1387 } else { 1388 if ( overTop > overBottom ) { 1389 position.top = withinOffset + outerHeight - data.collisionHeight; 1390 } else { 1391 position.top = withinOffset; 1392 } 1393 } 1394 // too far up -> align with top 1395 } else if ( overTop > 0 ) { 1396 position.top += overTop; 1397 // too far down -> align with bottom edge 1398 } else if ( overBottom > 0 ) { 1399 position.top -= overBottom; 1400 // adjust based on position and margin 1401 } else { 1402 position.top = max( position.top - collisionPosTop, position.top ); 1403 } 1404 } 1405 }, 1406 flip: { 1407 left: function( position, data ) { 1408 var within = data.within, 1409 withinOffset = within.offset.left + within.scrollLeft, 1410 outerWidth = within.width, 1411 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, 1412 collisionPosLeft = position.left - data.collisionPosition.marginLeft, 1413 overLeft = collisionPosLeft - offsetLeft, 1414 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, 1415 myOffset = data.my[ 0 ] === "left" ? 1416 -data.elemWidth : 1417 data.my[ 0 ] === "right" ? 1418 data.elemWidth : 1419 0, 1420 atOffset = data.at[ 0 ] === "left" ? 1421 data.targetWidth : 1422 data.at[ 0 ] === "right" ? 1423 -data.targetWidth : 1424 0, 1425 offset = -2 * data.offset[ 0 ], 1426 newOverRight, 1427 newOverLeft; 1428 1429 if ( overLeft < 0 ) { 1430 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset; 1431 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { 1432 position.left += myOffset + atOffset + offset; 1433 } 1434 } else if ( overRight > 0 ) { 1435 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft; 1436 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { 1437 position.left += myOffset + atOffset + offset; 1438 } 1439 } 1440 }, 1441 top: function( position, data ) { 1442 var within = data.within, 1443 withinOffset = within.offset.top + within.scrollTop, 1444 outerHeight = within.height, 1445 offsetTop = within.isWindow ? within.scrollTop : within.offset.top, 1446 collisionPosTop = position.top - data.collisionPosition.marginTop, 1447 overTop = collisionPosTop - offsetTop, 1448 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, 1449 top = data.my[ 1 ] === "top", 1450 myOffset = top ? 1451 -data.elemHeight : 1452 data.my[ 1 ] === "bottom" ? 1453 data.elemHeight : 1454 0, 1455 atOffset = data.at[ 1 ] === "top" ? 1456 data.targetHeight : 1457 data.at[ 1 ] === "bottom" ? 1458 -data.targetHeight : 1459 0, 1460 offset = -2 * data.offset[ 1 ], 1461 newOverTop, 1462 newOverBottom; 1463 if ( overTop < 0 ) { 1464 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset; 1465 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) { 1466 position.top += myOffset + atOffset + offset; 1467 } 1468 } else if ( overBottom > 0 ) { 1469 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop; 1470 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) { 1471 position.top += myOffset + atOffset + offset; 1472 } 1473 } 1474 } 1475 }, 1476 flipfit: { 1477 left: function() { 1478 $.ui.position.flip.left.apply( this, arguments ); 1479 $.ui.position.fit.left.apply( this, arguments ); 1480 }, 1481 top: function() { 1482 $.ui.position.flip.top.apply( this, arguments ); 1483 $.ui.position.fit.top.apply( this, arguments ); 1484 } 1485 } 1486 }; 1487 1488 // fraction support test 1489 (function() { 1490 var testElement, testElementParent, testElementStyle, offsetLeft, i, 1491 body = document.getElementsByTagName( "body" )[ 0 ], 1492 div = document.createElement( "div" ); 1493 1494 //Create a "fake body" for testing based on method used in jQuery.support 1495 testElement = document.createElement( body ? "div" : "body" ); 1496 testElementStyle = { 1497 visibility: "hidden", 1498 width: 0, 1499 height: 0, 1500 border: 0, 1501 margin: 0, 1502 background: "none" 1503 }; 1504 if ( body ) { 1505 $.extend( testElementStyle, { 1506 position: "absolute", 1507 left: "-1000px", 1508 top: "-1000px" 1509 }); 1510 } 1511 for ( i in testElementStyle ) { 1512 testElement.style[ i ] = testElementStyle[ i ]; 1513 } 1514 testElement.appendChild( div ); 1515 testElementParent = body || document.documentElement; 1516 testElementParent.insertBefore( testElement, testElementParent.firstChild ); 1517 1518 div.style.cssText = "position: absolute; left: 10.7432222px;"; 1519 1520 offsetLeft = $( div ).offset().left; 1521 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11; 1522 1523 testElement.innerHTML = ""; 1524 testElementParent.removeChild( testElement ); 1525 })(); 1526 1527 })(); 1528 1529 var position = $.ui.position; 1530 1531 1532 /*! 1533 * jQuery UI Accordion 1.11.1 1534 * http://jqueryui.com 1535 * 1536 * Copyright 2014 jQuery Foundation and other contributors 1537 * Released under the MIT license. 1538 * http://jquery.org/license 1539 * 1540 * http://api.jqueryui.com/accordion/ 1541 */ 1542 1543 1544 var accordion = $.widget( "ui.accordion", { 1545 version: "1.11.1", 1546 options: { 1547 active: 0, 1548 animate: {}, 1549 collapsible: false, 1550 event: "click", 1551 header: "> li > :first-child,> :not(li):even", 1552 heightStyle: "auto", 1553 icons: { 1554 activeHeader: "ui-icon-triangle-1-s", 1555 header: "ui-icon-triangle-1-e" 1556 }, 1557 1558 // callbacks 1559 activate: null, 1560 beforeActivate: null 1561 }, 1562 1563 hideProps: { 1564 borderTopWidth: "hide", 1565 borderBottomWidth: "hide", 1566 paddingTop: "hide", 1567 paddingBottom: "hide", 1568 height: "hide" 1569 }, 1570 1571 showProps: { 1572 borderTopWidth: "show", 1573 borderBottomWidth: "show", 1574 paddingTop: "show", 1575 paddingBottom: "show", 1576 height: "show" 1577 }, 1578 1579 _create: function() { 1580 var options = this.options; 1581 this.prevShow = this.prevHide = $(); 1582 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) 1583 // ARIA 1584 .attr( "role", "tablist" ); 1585 1586 // don't allow collapsible: false and active: false / null 1587 if ( !options.collapsible && (options.active === false || options.active == null) ) { 1588 options.active = 0; 1589 } 1590 1591 this._processPanels(); 1592 // handle negative values 1593 if ( options.active < 0 ) { 1594 options.active += this.headers.length; 1595 } 1596 this._refresh(); 1597 }, 1598 1599 _getCreateEventData: function() { 1600 return { 1601 header: this.active, 1602 panel: !this.active.length ? $() : this.active.next() 1603 }; 1604 }, 1605 1606 _createIcons: function() { 1607 var icons = this.options.icons; 1608 if ( icons ) { 1609 $( "<span>" ) 1610 .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) 1611 .prependTo( this.headers ); 1612 this.active.children( ".ui-accordion-header-icon" ) 1613 .removeClass( icons.header ) 1614 .addClass( icons.activeHeader ); 1615 this.headers.addClass( "ui-accordion-icons" ); 1616 } 1617 }, 1618 1619 _destroyIcons: function() { 1620 this.headers 1621 .removeClass( "ui-accordion-icons" ) 1622 .children( ".ui-accordion-header-icon" ) 1623 .remove(); 1624 }, 1625 1626 _destroy: function() { 1627 var contents; 1628 1629 // clean up main element 1630 this.element 1631 .removeClass( "ui-accordion ui-widget ui-helper-reset" ) 1632 .removeAttr( "role" ); 1633 1634 // clean up headers 1635 this.headers 1636 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " + 1637 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) 1638 .removeAttr( "role" ) 1639 .removeAttr( "aria-expanded" ) 1640 .removeAttr( "aria-selected" ) 1641 .removeAttr( "aria-controls" ) 1642 .removeAttr( "tabIndex" ) 1643 .removeUniqueId(); 1644 1645 this._destroyIcons(); 1646 1647 // clean up content panels 1648 contents = this.headers.next() 1649 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " + 1650 "ui-accordion-content ui-accordion-content-active ui-state-disabled" ) 1651 .css( "display", "" ) 1652 .removeAttr( "role" ) 1653 .removeAttr( "aria-hidden" ) 1654 .removeAttr( "aria-labelledby" ) 1655 .removeUniqueId(); 1656 1657 if ( this.options.heightStyle !== "content" ) { 1658 contents.css( "height", "" ); 1659 } 1660 }, 1661 1662 _setOption: function( key, value ) { 1663 if ( key === "active" ) { 1664 // _activate() will handle invalid values and update this.options 1665 this._activate( value ); 1666 return; 1667 } 1668 1669 if ( key === "event" ) { 1670 if ( this.options.event ) { 1671 this._off( this.headers, this.options.event ); 1672 } 1673 this._setupEvents( value ); 1674 } 1675 1676 this._super( key, value ); 1677 1678 // setting collapsible: false while collapsed; open first panel 1679 if ( key === "collapsible" && !value && this.options.active === false ) { 1680 this._activate( 0 ); 1681 } 1682 1683 if ( key === "icons" ) { 1684 this._destroyIcons(); 1685 if ( value ) { 1686 this._createIcons(); 1687 } 1688 } 1689 1690 // #5332 - opacity doesn't cascade to positioned elements in IE 1691 // so we need to add the disabled class to the headers and panels 1692 if ( key === "disabled" ) { 1693 this.element 1694 .toggleClass( "ui-state-disabled", !!value ) 1695 .attr( "aria-disabled", value ); 1696 this.headers.add( this.headers.next() ) 1697 .toggleClass( "ui-state-disabled", !!value ); 1698 } 1699 }, 1700 1701 _keydown: function( event ) { 1702 if ( event.altKey || event.ctrlKey ) { 1703 return; 1704 } 1705 1706 var keyCode = $.ui.keyCode, 1707 length = this.headers.length, 1708 currentIndex = this.headers.index( event.target ), 1709 toFocus = false; 1710 1711 switch ( event.keyCode ) { 1712 case keyCode.RIGHT: 1713 case keyCode.DOWN: 1714 toFocus = this.headers[ ( currentIndex + 1 ) % length ]; 1715 break; 1716 case keyCode.LEFT: 1717 case keyCode.UP: 1718 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; 1719 break; 1720 case keyCode.SPACE: 1721 case keyCode.ENTER: 1722 this._eventHandler( event ); 1723 break; 1724 case keyCode.HOME: 1725 toFocus = this.headers[ 0 ]; 1726 break; 1727 case keyCode.END: 1728 toFocus = this.headers[ length - 1 ]; 1729 break; 1730 } 1731 1732 if ( toFocus ) { 1733 $( event.target ).attr( "tabIndex", -1 ); 1734 $( toFocus ).attr( "tabIndex", 0 ); 1735 toFocus.focus(); 1736 event.preventDefault(); 1737 } 1738 }, 1739 1740 _panelKeyDown: function( event ) { 1741 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { 1742 $( event.currentTarget ).prev().focus(); 1743 } 1744 }, 1745 1746 refresh: function() { 1747 var options = this.options; 1748 this._processPanels(); 1749 1750 // was collapsed or no panel 1751 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { 1752 options.active = false; 1753 this.active = $(); 1754 // active false only when collapsible is true 1755 } else if ( options.active === false ) { 1756 this._activate( 0 ); 1757 // was active, but active panel is gone 1758 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 1759 // all remaining panel are disabled 1760 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { 1761 options.active = false; 1762 this.active = $(); 1763 // activate previous panel 1764 } else { 1765 this._activate( Math.max( 0, options.active - 1 ) ); 1766 } 1767 // was active, active panel still exists 1768 } else { 1769 // make sure active index is correct 1770 options.active = this.headers.index( this.active ); 1771 } 1772 1773 this._destroyIcons(); 1774 1775 this._refresh(); 1776 }, 1777 1778 _processPanels: function() { 1779 this.headers = this.element.find( this.options.header ) 1780 .addClass( "ui-accordion-header ui-state-default ui-corner-all" ); 1781 1782 this.headers.next() 1783 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) 1784 .filter( ":not(.ui-accordion-content-active)" ) 1785 .hide(); 1786 }, 1787 1788 _refresh: function() { 1789 var maxHeight, 1790 options = this.options, 1791 heightStyle = options.heightStyle, 1792 parent = this.element.parent(); 1793 1794 this.active = this._findActive( options.active ) 1795 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) 1796 .removeClass( "ui-corner-all" ); 1797 this.active.next() 1798 .addClass( "ui-accordion-content-active" ) 1799 .show(); 1800 1801 this.headers 1802 .attr( "role", "tab" ) 1803 .each(function() { 1804 var header = $( this ), 1805 headerId = header.uniqueId().attr( "id" ), 1806 panel = header.next(), 1807 panelId = panel.uniqueId().attr( "id" ); 1808 header.attr( "aria-controls", panelId ); 1809 panel.attr( "aria-labelledby", headerId ); 1810 }) 1811 .next() 1812 .attr( "role", "tabpanel" ); 1813 1814 this.headers 1815 .not( this.active ) 1816 .attr({ 1817 "aria-selected": "false", 1818 "aria-expanded": "false", 1819 tabIndex: -1 1820 }) 1821 .next() 1822 .attr({ 1823 "aria-hidden": "true" 1824 }) 1825 .hide(); 1826 1827 // make sure at least one header is in the tab order 1828 if ( !this.active.length ) { 1829 this.headers.eq( 0 ).attr( "tabIndex", 0 ); 1830 } else { 1831 this.active.attr({ 1832 "aria-selected": "true", 1833 "aria-expanded": "true", 1834 tabIndex: 0 1835 }) 1836 .next() 1837 .attr({ 1838 "aria-hidden": "false" 1839 }); 1840 } 1841 1842 this._createIcons(); 1843 1844 this._setupEvents( options.event ); 1845 1846 if ( heightStyle === "fill" ) { 1847 maxHeight = parent.height(); 1848 this.element.siblings( ":visible" ).each(function() { 1849 var elem = $( this ), 1850 position = elem.css( "position" ); 1851 1852 if ( position === "absolute" || position === "fixed" ) { 1853 return; 1854 } 1855 maxHeight -= elem.outerHeight( true ); 1856 }); 1857 1858 this.headers.each(function() { 1859 maxHeight -= $( this ).outerHeight( true ); 1860 }); 1861 1862 this.headers.next() 1863 .each(function() { 1864 $( this ).height( Math.max( 0, maxHeight - 1865 $( this ).innerHeight() + $( this ).height() ) ); 1866 }) 1867 .css( "overflow", "auto" ); 1868 } else if ( heightStyle === "auto" ) { 1869 maxHeight = 0; 1870 this.headers.next() 1871 .each(function() { 1872 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); 1873 }) 1874 .height( maxHeight ); 1875 } 1876 }, 1877 1878 _activate: function( index ) { 1879 var active = this._findActive( index )[ 0 ]; 1880 1881 // trying to activate the already active panel 1882 if ( active === this.active[ 0 ] ) { 1883 return; 1884 } 1885 1886 // trying to collapse, simulate a click on the currently active header 1887 active = active || this.active[ 0 ]; 1888 1889 this._eventHandler({ 1890 target: active, 1891 currentTarget: active, 1892 preventDefault: $.noop 1893 }); 1894 }, 1895 1896 _findActive: function( selector ) { 1897 return typeof selector === "number" ? this.headers.eq( selector ) : $(); 1898 }, 1899 1900 _setupEvents: function( event ) { 1901 var events = { 1902 keydown: "_keydown" 1903 }; 1904 if ( event ) { 1905 $.each( event.split( " " ), function( index, eventName ) { 1906 events[ eventName ] = "_eventHandler"; 1907 }); 1908 } 1909 1910 this._off( this.headers.add( this.headers.next() ) ); 1911 this._on( this.headers, events ); 1912 this._on( this.headers.next(), { keydown: "_panelKeyDown" }); 1913 this._hoverable( this.headers ); 1914 this._focusable( this.headers ); 1915 }, 1916 1917 _eventHandler: function( event ) { 1918 var options = this.options, 1919 active = this.active, 1920 clicked = $( event.currentTarget ), 1921 clickedIsActive = clicked[ 0 ] === active[ 0 ], 1922 collapsing = clickedIsActive && options.collapsible, 1923 toShow = collapsing ? $() : clicked.next(), 1924 toHide = active.next(), 1925 eventData = { 1926 oldHeader: active, 1927 oldPanel: toHide, 1928 newHeader: collapsing ? $() : clicked, 1929 newPanel: toShow 1930 }; 1931 1932 event.preventDefault(); 1933 1934 if ( 1935 // click on active header, but not collapsible 1936 ( clickedIsActive && !options.collapsible ) || 1937 // allow canceling activation 1938 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 1939 return; 1940 } 1941 1942 options.active = collapsing ? false : this.headers.index( clicked ); 1943 1944 // when the call to ._toggle() comes after the class changes 1945 // it causes a very odd bug in IE 8 (see #6720) 1946 this.active = clickedIsActive ? $() : clicked; 1947 this._toggle( eventData ); 1948 1949 // switch classes 1950 // corner classes on the previously active header stay after the animation 1951 active.removeClass( "ui-accordion-header-active ui-state-active" ); 1952 if ( options.icons ) { 1953 active.children( ".ui-accordion-header-icon" ) 1954 .removeClass( options.icons.activeHeader ) 1955 .addClass( options.icons.header ); 1956 } 1957 1958 if ( !clickedIsActive ) { 1959 clicked 1960 .removeClass( "ui-corner-all" ) 1961 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); 1962 if ( options.icons ) { 1963 clicked.children( ".ui-accordion-header-icon" ) 1964 .removeClass( options.icons.header ) 1965 .addClass( options.icons.activeHeader ); 1966 } 1967 1968 clicked 1969 .next() 1970 .addClass( "ui-accordion-content-active" ); 1971 } 1972 }, 1973 1974 _toggle: function( data ) { 1975 var toShow = data.newPanel, 1976 toHide = this.prevShow.length ? this.prevShow : data.oldPanel; 1977 1978 // handle activating a panel during the animation for another activation 1979 this.prevShow.add( this.prevHide ).stop( true, true ); 1980 this.prevShow = toShow; 1981 this.prevHide = toHide; 1982 1983 if ( this.options.animate ) { 1984 this._animate( toShow, toHide, data ); 1985 } else { 1986 toHide.hide(); 1987 toShow.show(); 1988 this._toggleComplete( data ); 1989 } 1990 1991 toHide.attr({ 1992 "aria-hidden": "true" 1993 }); 1994 toHide.prev().attr( "aria-selected", "false" ); 1995 // if we're switching panels, remove the old header from the tab order 1996 // if we're opening from collapsed state, remove the previous header from the tab order 1997 // if we're collapsing, then keep the collapsing header in the tab order 1998 if ( toShow.length && toHide.length ) { 1999 toHide.prev().attr({ 2000 "tabIndex": -1, 2001 "aria-expanded": "false" 2002 }); 2003 } else if ( toShow.length ) { 2004 this.headers.filter(function() { 2005 return $( this ).attr( "tabIndex" ) === 0; 2006 }) 2007 .attr( "tabIndex", -1 ); 2008 } 2009 2010 toShow 2011 .attr( "aria-hidden", "false" ) 2012 .prev() 2013 .attr({ 2014 "aria-selected": "true", 2015 tabIndex: 0, 2016 "aria-expanded": "true" 2017 }); 2018 }, 2019 2020 _animate: function( toShow, toHide, data ) { 2021 var total, easing, duration, 2022 that = this, 2023 adjust = 0, 2024 down = toShow.length && 2025 ( !toHide.length || ( toShow.index() < toHide.index() ) ), 2026 animate = this.options.animate || {}, 2027 options = down && animate.down || animate, 2028 complete = function() { 2029 that._toggleComplete( data ); 2030 }; 2031 2032 if ( typeof options === "number" ) { 2033 duration = options; 2034 } 2035 if ( typeof options === "string" ) { 2036 easing = options; 2037 } 2038 // fall back from options to animation in case of partial down settings 2039 easing = easing || options.easing || animate.easing; 2040 duration = duration || options.duration || animate.duration; 2041 2042 if ( !toHide.length ) { 2043 return toShow.animate( this.showProps, duration, easing, complete ); 2044 } 2045 if ( !toShow.length ) { 2046 return toHide.animate( this.hideProps, duration, easing, complete ); 2047 } 2048 2049 total = toShow.show().outerHeight(); 2050 toHide.animate( this.hideProps, { 2051 duration: duration, 2052 easing: easing, 2053 step: function( now, fx ) { 2054 fx.now = Math.round( now ); 2055 } 2056 }); 2057 toShow 2058 .hide() 2059 .animate( this.showProps, { 2060 duration: duration, 2061 easing: easing, 2062 complete: complete, 2063 step: function( now, fx ) { 2064 fx.now = Math.round( now ); 2065 if ( fx.prop !== "height" ) { 2066 adjust += fx.now; 2067 } else if ( that.options.heightStyle !== "content" ) { 2068 fx.now = Math.round( total - toHide.outerHeight() - adjust ); 2069 adjust = 0; 2070 } 2071 } 2072 }); 2073 }, 2074 2075 _toggleComplete: function( data ) { 2076 var toHide = data.oldPanel; 2077 2078 toHide 2079 .removeClass( "ui-accordion-content-active" ) 2080 .prev() 2081 .removeClass( "ui-corner-top" ) 2082 .addClass( "ui-corner-all" ); 2083 2084 // Work around for rendering bug in IE (#5421) 2085 if ( toHide.length ) { 2086 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className; 2087 } 2088 this._trigger( "activate", null, data ); 2089 } 2090 }); 2091 2092 2093 /*! 2094 * jQuery UI Menu 1.11.1 2095 * http://jqueryui.com 2096 * 2097 * Copyright 2014 jQuery Foundation and other contributors 2098 * Released under the MIT license. 2099 * http://jquery.org/license 2100 * 2101 * http://api.jqueryui.com/menu/ 2102 */ 2103 2104 2105 var menu = $.widget( "ui.menu", { 2106 version: "1.11.1", 2107 defaultElement: "<ul>", 2108 delay: 300, 2109 options: { 2110 icons: { 2111 submenu: "ui-icon-carat-1-e" 2112 }, 2113 items: "> *", 2114 menus: "ul", 2115 position: { 2116 my: "left-1 top", 2117 at: "right top" 2118 }, 2119 role: "menu", 2120 2121 // callbacks 2122 blur: null, 2123 focus: null, 2124 select: null 2125 }, 2126 2127 _create: function() { 2128 this.activeMenu = this.element; 2129 2130 // Flag used to prevent firing of the click handler 2131 // as the event bubbles up through nested menus 2132 this.mouseHandled = false; 2133 this.element 2134 .uniqueId() 2135 .addClass( "ui-menu ui-widget ui-widget-content" ) 2136 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ) 2137 .attr({ 2138 role: this.options.role, 2139 tabIndex: 0 2140 }); 2141 2142 if ( this.options.disabled ) { 2143 this.element 2144 .addClass( "ui-state-disabled" ) 2145 .attr( "aria-disabled", "true" ); 2146 } 2147 2148 this._on({ 2149 // Prevent focus from sticking to links inside menu after clicking 2150 // them (focus should always stay on UL during navigation). 2151 "mousedown .ui-menu-item": function( event ) { 2152 event.preventDefault(); 2153 }, 2154 "click .ui-menu-item": function( event ) { 2155 var target = $( event.target ); 2156 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { 2157 this.select( event ); 2158 2159 // Only set the mouseHandled flag if the event will bubble, see #9469. 2160 if ( !event.isPropagationStopped() ) { 2161 this.mouseHandled = true; 2162 } 2163 2164 // Open submenu on click 2165 if ( target.has( ".ui-menu" ).length ) { 2166 this.expand( event ); 2167 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) { 2168 2169 // Redirect focus to the menu 2170 this.element.trigger( "focus", [ true ] ); 2171 2172 // If the active item is on the top level, let it stay active. 2173 // Otherwise, blur the active item since it is no longer visible. 2174 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { 2175 clearTimeout( this.timer ); 2176 } 2177 } 2178 } 2179 }, 2180 "mouseenter .ui-menu-item": function( event ) { 2181 var target = $( event.currentTarget ); 2182 // Remove ui-state-active class from siblings of the newly focused menu item 2183 // to avoid a jump caused by adjacent elements both having a class with a border 2184 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" ); 2185 this.focus( event, target ); 2186 }, 2187 mouseleave: "collapseAll", 2188 "mouseleave .ui-menu": "collapseAll", 2189 focus: function( event, keepActiveItem ) { 2190 // If there's already an active item, keep it active 2191 // If not, activate the first item 2192 var item = this.active || this.element.find( this.options.items ).eq( 0 ); 2193 2194 if ( !keepActiveItem ) { 2195 this.focus( event, item ); 2196 } 2197 }, 2198 blur: function( event ) { 2199 this._delay(function() { 2200 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) { 2201 this.collapseAll( event ); 2202 } 2203 }); 2204 }, 2205 keydown: "_keydown" 2206 }); 2207 2208 this.refresh(); 2209 2210 // Clicks outside of a menu collapse any open menus 2211 this._on( this.document, { 2212 click: function( event ) { 2213 if ( this._closeOnDocumentClick( event ) ) { 2214 this.collapseAll( event ); 2215 } 2216 2217 // Reset the mouseHandled flag 2218 this.mouseHandled = false; 2219 } 2220 }); 2221 }, 2222 2223 _destroy: function() { 2224 // Destroy (sub)menus 2225 this.element 2226 .removeAttr( "aria-activedescendant" ) 2227 .find( ".ui-menu" ).addBack() 2228 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" ) 2229 .removeAttr( "role" ) 2230 .removeAttr( "tabIndex" ) 2231 .removeAttr( "aria-labelledby" ) 2232 .removeAttr( "aria-expanded" ) 2233 .removeAttr( "aria-hidden" ) 2234 .removeAttr( "aria-disabled" ) 2235 .removeUniqueId() 2236 .show(); 2237 2238 // Destroy menu items 2239 this.element.find( ".ui-menu-item" ) 2240 .removeClass( "ui-menu-item" ) 2241 .removeAttr( "role" ) 2242 .removeAttr( "aria-disabled" ) 2243 .removeUniqueId() 2244 .removeClass( "ui-state-hover" ) 2245 .removeAttr( "tabIndex" ) 2246 .removeAttr( "role" ) 2247 .removeAttr( "aria-haspopup" ) 2248 .children().each( function() { 2249 var elem = $( this ); 2250 if ( elem.data( "ui-menu-submenu-carat" ) ) { 2251 elem.remove(); 2252 } 2253 }); 2254 2255 // Destroy menu dividers 2256 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" ); 2257 }, 2258 2259 _keydown: function( event ) { 2260 var match, prev, character, skip, regex, 2261 preventDefault = true; 2262 2263 function escape( value ) { 2264 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 2265 } 2266 2267 switch ( event.keyCode ) { 2268 case $.ui.keyCode.PAGE_UP: 2269 this.previousPage( event ); 2270 break; 2271 case $.ui.keyCode.PAGE_DOWN: 2272 this.nextPage( event ); 2273 break; 2274 case $.ui.keyCode.HOME: 2275 this._move( "first", "first", event ); 2276 break; 2277 case $.ui.keyCode.END: 2278 this._move( "last", "last", event ); 2279 break; 2280 case $.ui.keyCode.UP: 2281 this.previous( event ); 2282 break; 2283 case $.ui.keyCode.DOWN: 2284 this.next( event ); 2285 break; 2286 case $.ui.keyCode.LEFT: 2287 this.collapse( event ); 2288 break; 2289 case $.ui.keyCode.RIGHT: 2290 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { 2291 this.expand( event ); 2292 } 2293 break; 2294 case $.ui.keyCode.ENTER: 2295 case $.ui.keyCode.SPACE: 2296 this._activate( event ); 2297 break; 2298 case $.ui.keyCode.ESCAPE: 2299 this.collapse( event ); 2300 break; 2301 default: 2302 preventDefault = false; 2303 prev = this.previousFilter || ""; 2304 character = String.fromCharCode( event.keyCode ); 2305 skip = false; 2306 2307 clearTimeout( this.filterTimer ); 2308 2309 if ( character === prev ) { 2310 skip = true; 2311 } else { 2312 character = prev + character; 2313 } 2314 2315 regex = new RegExp( "^" + escape( character ), "i" ); 2316 match = this.activeMenu.find( this.options.items ).filter(function() { 2317 return regex.test( $( this ).text() ); 2318 }); 2319 match = skip && match.index( this.active.next() ) !== -1 ? 2320 this.active.nextAll( ".ui-menu-item" ) : 2321 match; 2322 2323 // If no matches on the current filter, reset to the last character pressed 2324 // to move down the menu to the first item that starts with that character 2325 if ( !match.length ) { 2326 character = String.fromCharCode( event.keyCode ); 2327 regex = new RegExp( "^" + escape( character ), "i" ); 2328 match = this.activeMenu.find( this.options.items ).filter(function() { 2329 return regex.test( $( this ).text() ); 2330 }); 2331 } 2332 2333 if ( match.length ) { 2334 this.focus( event, match ); 2335 if ( match.length > 1 ) { 2336 this.previousFilter = character; 2337 this.filterTimer = this._delay(function() { 2338 delete this.previousFilter; 2339 }, 1000 ); 2340 } else { 2341 delete this.previousFilter; 2342 } 2343 } else { 2344 delete this.previousFilter; 2345 } 2346 } 2347 2348 if ( preventDefault ) { 2349 event.preventDefault(); 2350 } 2351 }, 2352 2353 _activate: function( event ) { 2354 if ( !this.active.is( ".ui-state-disabled" ) ) { 2355 if ( this.active.is( "[aria-haspopup='true']" ) ) { 2356 this.expand( event ); 2357 } else { 2358 this.select( event ); 2359 } 2360 } 2361 }, 2362 2363 refresh: function() { 2364 var menus, items, 2365 that = this, 2366 icon = this.options.icons.submenu, 2367 submenus = this.element.find( this.options.menus ); 2368 2369 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length ); 2370 2371 // Initialize nested menus 2372 submenus.filter( ":not(.ui-menu)" ) 2373 .addClass( "ui-menu ui-widget ui-widget-content ui-front" ) 2374 .hide() 2375 .attr({ 2376 role: this.options.role, 2377 "aria-hidden": "true", 2378 "aria-expanded": "false" 2379 }) 2380 .each(function() { 2381 var menu = $( this ), 2382 item = menu.parent(), 2383 submenuCarat = $( "<span>" ) 2384 .addClass( "ui-menu-icon ui-icon " + icon ) 2385 .data( "ui-menu-submenu-carat", true ); 2386 2387 item 2388 .attr( "aria-haspopup", "true" ) 2389 .prepend( submenuCarat ); 2390 menu.attr( "aria-labelledby", item.attr( "id" ) ); 2391 }); 2392 2393 menus = submenus.add( this.element ); 2394 items = menus.find( this.options.items ); 2395 2396 // Initialize menu-items containing spaces and/or dashes only as dividers 2397 items.not( ".ui-menu-item" ).each(function() { 2398 var item = $( this ); 2399 if ( that._isDivider( item ) ) { 2400 item.addClass( "ui-widget-content ui-menu-divider" ); 2401 } 2402 }); 2403 2404 // Don't refresh list items that are already adapted 2405 items.not( ".ui-menu-item, .ui-menu-divider" ) 2406 .addClass( "ui-menu-item" ) 2407 .uniqueId() 2408 .attr({ 2409 tabIndex: -1, 2410 role: this._itemRole() 2411 }); 2412 2413 // Add aria-disabled attribute to any disabled menu item 2414 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); 2415 2416 // If the active item has been removed, blur the menu 2417 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { 2418 this.blur(); 2419 } 2420 }, 2421 2422 _itemRole: function() { 2423 return { 2424 menu: "menuitem", 2425 listbox: "option" 2426 }[ this.options.role ]; 2427 }, 2428 2429 _setOption: function( key, value ) { 2430 if ( key === "icons" ) { 2431 this.element.find( ".ui-menu-icon" ) 2432 .removeClass( this.options.icons.submenu ) 2433 .addClass( value.submenu ); 2434 } 2435 if ( key === "disabled" ) { 2436 this.element 2437 .toggleClass( "ui-state-disabled", !!value ) 2438 .attr( "aria-disabled", value ); 2439 } 2440 this._super( key, value ); 2441 }, 2442 2443 focus: function( event, item ) { 2444 var nested, focused; 2445 this.blur( event, event && event.type === "focus" ); 2446 2447 this._scrollIntoView( item ); 2448 2449 this.active = item.first(); 2450 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" ); 2451 // Only update aria-activedescendant if there's a role 2452 // otherwise we assume focus is managed elsewhere 2453 if ( this.options.role ) { 2454 this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); 2455 } 2456 2457 // Highlight active parent menu item, if any 2458 this.active 2459 .parent() 2460 .closest( ".ui-menu-item" ) 2461 .addClass( "ui-state-active" ); 2462 2463 if ( event && event.type === "keydown" ) { 2464 this._close(); 2465 } else { 2466 this.timer = this._delay(function() { 2467 this._close(); 2468 }, this.delay ); 2469 } 2470 2471 nested = item.children( ".ui-menu" ); 2472 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { 2473 this._startOpening(nested); 2474 } 2475 this.activeMenu = item.parent(); 2476 2477 this._trigger( "focus", event, { item: item } ); 2478 }, 2479 2480 _scrollIntoView: function( item ) { 2481 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; 2482 if ( this._hasScroll() ) { 2483 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0; 2484 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0; 2485 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; 2486 scroll = this.activeMenu.scrollTop(); 2487 elementHeight = this.activeMenu.height(); 2488 itemHeight = item.outerHeight(); 2489 2490 if ( offset < 0 ) { 2491 this.activeMenu.scrollTop( scroll + offset ); 2492 } else if ( offset + itemHeight > elementHeight ) { 2493 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); 2494 } 2495 } 2496 }, 2497 2498 blur: function( event, fromFocus ) { 2499 if ( !fromFocus ) { 2500 clearTimeout( this.timer ); 2501 } 2502 2503 if ( !this.active ) { 2504 return; 2505 } 2506 2507 this.active.removeClass( "ui-state-focus" ); 2508 this.active = null; 2509 2510 this._trigger( "blur", event, { item: this.active } ); 2511 }, 2512 2513 _startOpening: function( submenu ) { 2514 clearTimeout( this.timer ); 2515 2516 // Don't open if already open fixes a Firefox bug that caused a .5 pixel 2517 // shift in the submenu position when mousing over the carat icon 2518 if ( submenu.attr( "aria-hidden" ) !== "true" ) { 2519 return; 2520 } 2521 2522 this.timer = this._delay(function() { 2523 this._close(); 2524 this._open( submenu ); 2525 }, this.delay ); 2526 }, 2527 2528 _open: function( submenu ) { 2529 var position = $.extend({ 2530 of: this.active 2531 }, this.options.position ); 2532 2533 clearTimeout( this.timer ); 2534 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) 2535 .hide() 2536 .attr( "aria-hidden", "true" ); 2537 2538 submenu 2539 .show() 2540 .removeAttr( "aria-hidden" ) 2541 .attr( "aria-expanded", "true" ) 2542 .position( position ); 2543 }, 2544 2545 collapseAll: function( event, all ) { 2546 clearTimeout( this.timer ); 2547 this.timer = this._delay(function() { 2548 // If we were passed an event, look for the submenu that contains the event 2549 var currentMenu = all ? this.element : 2550 $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); 2551 2552 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway 2553 if ( !currentMenu.length ) { 2554 currentMenu = this.element; 2555 } 2556 2557 this._close( currentMenu ); 2558 2559 this.blur( event ); 2560 this.activeMenu = currentMenu; 2561 }, this.delay ); 2562 }, 2563 2564 // With no arguments, closes the currently active menu - if nothing is active 2565 // it closes all menus. If passed an argument, it will search for menus BELOW 2566 _close: function( startMenu ) { 2567 if ( !startMenu ) { 2568 startMenu = this.active ? this.active.parent() : this.element; 2569 } 2570 2571 startMenu 2572 .find( ".ui-menu" ) 2573 .hide() 2574 .attr( "aria-hidden", "true" ) 2575 .attr( "aria-expanded", "false" ) 2576 .end() 2577 .find( ".ui-state-active" ).not( ".ui-state-focus" ) 2578 .removeClass( "ui-state-active" ); 2579 }, 2580 2581 _closeOnDocumentClick: function( event ) { 2582 return !$( event.target ).closest( ".ui-menu" ).length; 2583 }, 2584 2585 _isDivider: function( item ) { 2586 2587 // Match hyphen, em dash, en dash 2588 return !/[^\-\u2014\u2013\s]/.test( item.text() ); 2589 }, 2590 2591 collapse: function( event ) { 2592 var newItem = this.active && 2593 this.active.parent().closest( ".ui-menu-item", this.element ); 2594 if ( newItem && newItem.length ) { 2595 this._close(); 2596 this.focus( event, newItem ); 2597 } 2598 }, 2599 2600 expand: function( event ) { 2601 var newItem = this.active && 2602 this.active 2603 .children( ".ui-menu " ) 2604 .find( this.options.items ) 2605 .first(); 2606 2607 if ( newItem && newItem.length ) { 2608 this._open( newItem.parent() ); 2609 2610 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT 2611 this._delay(function() { 2612 this.focus( event, newItem ); 2613 }); 2614 } 2615 }, 2616 2617 next: function( event ) { 2618 this._move( "next", "first", event ); 2619 }, 2620 2621 previous: function( event ) { 2622 this._move( "prev", "last", event ); 2623 }, 2624 2625 isFirstItem: function() { 2626 return this.active && !this.active.prevAll( ".ui-menu-item" ).length; 2627 }, 2628 2629 isLastItem: function() { 2630 return this.active && !this.active.nextAll( ".ui-menu-item" ).length; 2631 }, 2632 2633 _move: function( direction, filter, event ) { 2634 var next; 2635 if ( this.active ) { 2636 if ( direction === "first" || direction === "last" ) { 2637 next = this.active 2638 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) 2639 .eq( -1 ); 2640 } else { 2641 next = this.active 2642 [ direction + "All" ]( ".ui-menu-item" ) 2643 .eq( 0 ); 2644 } 2645 } 2646 if ( !next || !next.length || !this.active ) { 2647 next = this.activeMenu.find( this.options.items )[ filter ](); 2648 } 2649 2650 this.focus( event, next ); 2651 }, 2652 2653 nextPage: function( event ) { 2654 var item, base, height; 2655 2656 if ( !this.active ) { 2657 this.next( event ); 2658 return; 2659 } 2660 if ( this.isLastItem() ) { 2661 return; 2662 } 2663 if ( this._hasScroll() ) { 2664 base = this.active.offset().top; 2665 height = this.element.height(); 2666 this.active.nextAll( ".ui-menu-item" ).each(function() { 2667 item = $( this ); 2668 return item.offset().top - base - height < 0; 2669 }); 2670 2671 this.focus( event, item ); 2672 } else { 2673 this.focus( event, this.activeMenu.find( this.options.items ) 2674 [ !this.active ? "first" : "last" ]() ); 2675 } 2676 }, 2677 2678 previousPage: function( event ) { 2679 var item, base, height; 2680 if ( !this.active ) { 2681 this.next( event ); 2682 return; 2683 } 2684 if ( this.isFirstItem() ) { 2685 return; 2686 } 2687 if ( this._hasScroll() ) { 2688 base = this.active.offset().top; 2689 height = this.element.height(); 2690 this.active.prevAll( ".ui-menu-item" ).each(function() { 2691 item = $( this ); 2692 return item.offset().top - base + height > 0; 2693 }); 2694 2695 this.focus( event, item ); 2696 } else { 2697 this.focus( event, this.activeMenu.find( this.options.items ).first() ); 2698 } 2699 }, 2700 2701 _hasScroll: function() { 2702 return this.element.outerHeight() < this.element.prop( "scrollHeight" ); 2703 }, 2704 2705 select: function( event ) { 2706 // TODO: It should never be possible to not have an active item at this 2707 // point, but the tests don't trigger mouseenter before click. 2708 this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); 2709 var ui = { item: this.active }; 2710 if ( !this.active.has( ".ui-menu" ).length ) { 2711 this.collapseAll( event, true ); 2712 } 2713 this._trigger( "select", event, ui ); 2714 } 2715 }); 2716 2717 2718 /*! 2719 * jQuery UI Autocomplete 1.11.1 2720 * http://jqueryui.com 2721 * 2722 * Copyright 2014 jQuery Foundation and other contributors 2723 * Released under the MIT license. 2724 * http://jquery.org/license 2725 * 2726 * http://api.jqueryui.com/autocomplete/ 2727 */ 2728 2729 2730 $.widget( "ui.autocomplete", { 2731 version: "1.11.1", 2732 defaultElement: "<input>", 2733 options: { 2734 appendTo: null, 2735 autoFocus: false, 2736 delay: 300, 2737 minLength: 1, 2738 position: { 2739 my: "left top", 2740 at: "left bottom", 2741 collision: "none" 2742 }, 2743 source: null, 2744 2745 // callbacks 2746 change: null, 2747 close: null, 2748 focus: null, 2749 open: null, 2750 response: null, 2751 search: null, 2752 select: null 2753 }, 2754 2755 requestIndex: 0, 2756 pending: 0, 2757 2758 _create: function() { 2759 // Some browsers only repeat keydown events, not keypress events, 2760 // so we use the suppressKeyPress flag to determine if we've already 2761 // handled the keydown event. #7269 2762 // Unfortunately the code for & in keypress is the same as the up arrow, 2763 // so we use the suppressKeyPressRepeat flag to avoid handling keypress 2764 // events when we know the keydown event was used to modify the 2765 // search term. #7799 2766 var suppressKeyPress, suppressKeyPressRepeat, suppressInput, 2767 nodeName = this.element[ 0 ].nodeName.toLowerCase(), 2768 isTextarea = nodeName === "textarea", 2769 isInput = nodeName === "input"; 2770 2771 this.isMultiLine = 2772 // Textareas are always multi-line 2773 isTextarea ? true : 2774 // Inputs are always single-line, even if inside a contentEditable element 2775 // IE also treats inputs as contentEditable 2776 isInput ? false : 2777 // All other element types are determined by whether or not they're contentEditable 2778 this.element.prop( "isContentEditable" ); 2779 2780 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; 2781 this.isNewMenu = true; 2782 2783 this.element 2784 .addClass( "ui-autocomplete-input" ) 2785 .attr( "autocomplete", "off" ); 2786 2787 this._on( this.element, { 2788 keydown: function( event ) { 2789 if ( this.element.prop( "readOnly" ) ) { 2790 suppressKeyPress = true; 2791 suppressInput = true; 2792 suppressKeyPressRepeat = true; 2793 return; 2794 } 2795 2796 suppressKeyPress = false; 2797 suppressInput = false; 2798 suppressKeyPressRepeat = false; 2799 var keyCode = $.ui.keyCode; 2800 switch ( event.keyCode ) { 2801 case keyCode.PAGE_UP: 2802 suppressKeyPress = true; 2803 this._move( "previousPage", event ); 2804 break; 2805 case keyCode.PAGE_DOWN: 2806 suppressKeyPress = true; 2807 this._move( "nextPage", event ); 2808 break; 2809 case keyCode.UP: 2810 suppressKeyPress = true; 2811 this._keyEvent( "previous", event ); 2812 break; 2813 case keyCode.DOWN: 2814 suppressKeyPress = true; 2815 this._keyEvent( "next", event ); 2816 break; 2817 case keyCode.ENTER: 2818 // when menu is open and has focus 2819 if ( this.menu.active ) { 2820 // #6055 - Opera still allows the keypress to occur 2821 // which causes forms to submit 2822 suppressKeyPress = true; 2823 event.preventDefault(); 2824 this.menu.select( event ); 2825 } 2826 break; 2827 case keyCode.TAB: 2828 if ( this.menu.active ) { 2829 this.menu.select( event ); 2830 } 2831 break; 2832 case keyCode.ESCAPE: 2833 if ( this.menu.element.is( ":visible" ) ) { 2834 if ( !this.isMultiLine ) { 2835 this._value( this.term ); 2836 } 2837 this.close( event ); 2838 // Different browsers have different default behavior for escape 2839 // Single press can mean undo or clear 2840 // Double press in IE means clear the whole form 2841 event.preventDefault(); 2842 } 2843 break; 2844 default: 2845 suppressKeyPressRepeat = true; 2846 // search timeout should be triggered before the input value is changed 2847 this._searchTimeout( event ); 2848 break; 2849 } 2850 }, 2851 keypress: function( event ) { 2852 if ( suppressKeyPress ) { 2853 suppressKeyPress = false; 2854 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 2855 event.preventDefault(); 2856 } 2857 return; 2858 } 2859 if ( suppressKeyPressRepeat ) { 2860 return; 2861 } 2862 2863 // replicate some key handlers to allow them to repeat in Firefox and Opera 2864 var keyCode = $.ui.keyCode; 2865 switch ( event.keyCode ) { 2866 case keyCode.PAGE_UP: 2867 this._move( "previousPage", event ); 2868 break; 2869 case keyCode.PAGE_DOWN: 2870 this._move( "nextPage", event ); 2871 break; 2872 case keyCode.UP: 2873 this._keyEvent( "previous", event ); 2874 break; 2875 case keyCode.DOWN: 2876 this._keyEvent( "next", event ); 2877 break; 2878 } 2879 }, 2880 input: function( event ) { 2881 if ( suppressInput ) { 2882 suppressInput = false; 2883 event.preventDefault(); 2884 return; 2885 } 2886 this._searchTimeout( event ); 2887 }, 2888 focus: function() { 2889 this.selectedItem = null; 2890 this.previous = this._value(); 2891 }, 2892 blur: function( event ) { 2893 if ( this.cancelBlur ) { 2894 delete this.cancelBlur; 2895 return; 2896 } 2897 2898 clearTimeout( this.searching ); 2899 this.close( event ); 2900 this._change( event ); 2901 } 2902 }); 2903 2904 this._initSource(); 2905 this.menu = $( "<ul>" ) 2906 .addClass( "ui-autocomplete ui-front" ) 2907 .appendTo( this._appendTo() ) 2908 .menu({ 2909 // disable ARIA support, the live region takes care of that 2910 role: null 2911 }) 2912 .hide() 2913 .menu( "instance" ); 2914 2915 this._on( this.menu.element, { 2916 mousedown: function( event ) { 2917 // prevent moving focus out of the text field 2918 event.preventDefault(); 2919 2920 // IE doesn't prevent moving focus even with event.preventDefault() 2921 // so we set a flag to know when we should ignore the blur event 2922 this.cancelBlur = true; 2923 this._delay(function() { 2924 delete this.cancelBlur; 2925 }); 2926 2927 // clicking on the scrollbar causes focus to shift to the body 2928 // but we can't detect a mouseup or a click immediately afterward 2929 // so we have to track the next mousedown and close the menu if 2930 // the user clicks somewhere outside of the autocomplete 2931 var menuElement = this.menu.element[ 0 ]; 2932 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) { 2933 this._delay(function() { 2934 var that = this; 2935 this.document.one( "mousedown", function( event ) { 2936 if ( event.target !== that.element[ 0 ] && 2937 event.target !== menuElement && 2938 !$.contains( menuElement, event.target ) ) { 2939 that.close(); 2940 } 2941 }); 2942 }); 2943 } 2944 }, 2945 menufocus: function( event, ui ) { 2946 var label, item; 2947 // support: Firefox 2948 // Prevent accidental activation of menu items in Firefox (#7024 #9118) 2949 if ( this.isNewMenu ) { 2950 this.isNewMenu = false; 2951 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { 2952 this.menu.blur(); 2953 2954 this.document.one( "mousemove", function() { 2955 $( event.target ).trigger( event.originalEvent ); 2956 }); 2957 2958 return; 2959 } 2960 } 2961 2962 item = ui.item.data( "ui-autocomplete-item" ); 2963 if ( false !== this._trigger( "focus", event, { item: item } ) ) { 2964 // use value to match what will end up in the input, if it was a key event 2965 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { 2966 this._value( item.value ); 2967 } 2968 } 2969 2970 // Announce the value in the liveRegion 2971 label = ui.item.attr( "aria-label" ) || item.value; 2972 if ( label && $.trim( label ).length ) { 2973 this.liveRegion.children().hide(); 2974 $( "<div>" ).text( label ).appendTo( this.liveRegion ); 2975 } 2976 }, 2977 menuselect: function( event, ui ) { 2978 var item = ui.item.data( "ui-autocomplete-item" ), 2979 previous = this.previous; 2980 2981 // only trigger when focus was lost (click on menu) 2982 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { 2983 this.element.focus(); 2984 this.previous = previous; 2985 // #6109 - IE triggers two focus events and the second 2986 // is asynchronous, so we need to reset the previous 2987 // term synchronously and asynchronously :-( 2988 this._delay(function() { 2989 this.previous = previous; 2990 this.selectedItem = item; 2991 }); 2992 } 2993 2994 if ( false !== this._trigger( "select", event, { item: item } ) ) { 2995 this._value( item.value ); 2996 } 2997 // reset the term after the select event 2998 // this allows custom select handling to work properly 2999 this.term = this._value(); 3000 3001 this.close( event ); 3002 this.selectedItem = item; 3003 } 3004 }); 3005 3006 this.liveRegion = $( "<span>", { 3007 role: "status", 3008 "aria-live": "assertive", 3009 "aria-relevant": "additions" 3010 }) 3011 .addClass( "ui-helper-hidden-accessible" ) 3012 .appendTo( this.document[ 0 ].body ); 3013 3014 // turning off autocomplete prevents the browser from remembering the 3015 // value when navigating through history, so we re-enable autocomplete 3016 // if the page is unloaded before the widget is destroyed. #7790 3017 this._on( this.window, { 3018 beforeunload: function() { 3019 this.element.removeAttr( "autocomplete" ); 3020 } 3021 }); 3022 }, 3023 3024 _destroy: function() { 3025 clearTimeout( this.searching ); 3026 this.element 3027 .removeClass( "ui-autocomplete-input" ) 3028 .removeAttr( "autocomplete" ); 3029 this.menu.element.remove(); 3030 this.liveRegion.remove(); 3031 }, 3032 3033 _setOption: function( key, value ) { 3034 this._super( key, value ); 3035 if ( key === "source" ) { 3036 this._initSource(); 3037 } 3038 if ( key === "appendTo" ) { 3039 this.menu.element.appendTo( this._appendTo() ); 3040 } 3041 if ( key === "disabled" && value && this.xhr ) { 3042 this.xhr.abort(); 3043 } 3044 }, 3045 3046 _appendTo: function() { 3047 var element = this.options.appendTo; 3048 3049 if ( element ) { 3050 element = element.jquery || element.nodeType ? 3051 $( element ) : 3052 this.document.find( element ).eq( 0 ); 3053 } 3054 3055 if ( !element || !element[ 0 ] ) { 3056 element = this.element.closest( ".ui-front" ); 3057 } 3058 3059 if ( !element.length ) { 3060 element = this.document[ 0 ].body; 3061 } 3062 3063 return element; 3064 }, 3065 3066 _initSource: function() { 3067 var array, url, 3068 that = this; 3069 if ( $.isArray( this.options.source ) ) { 3070 array = this.options.source; 3071 this.source = function( request, response ) { 3072 response( $.ui.autocomplete.filter( array, request.term ) ); 3073 }; 3074 } else if ( typeof this.options.source === "string" ) { 3075 url = this.options.source; 3076 this.source = function( request, response ) { 3077 if ( that.xhr ) { 3078 that.xhr.abort(); 3079 } 3080 that.xhr = $.ajax({ 3081 url: url, 3082 data: request, 3083 dataType: "json", 3084 success: function( data ) { 3085 response( data ); 3086 }, 3087 error: function() { 3088 response([]); 3089 } 3090 }); 3091 }; 3092 } else { 3093 this.source = this.options.source; 3094 } 3095 }, 3096 3097 _searchTimeout: function( event ) { 3098 clearTimeout( this.searching ); 3099 this.searching = this._delay(function() { 3100 3101 // Search if the value has changed, or if the user retypes the same value (see #7434) 3102 var equalValues = this.term === this._value(), 3103 menuVisible = this.menu.element.is( ":visible" ), 3104 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; 3105 3106 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { 3107 this.selectedItem = null; 3108 this.search( null, event ); 3109 } 3110 }, this.options.delay ); 3111 }, 3112 3113 search: function( value, event ) { 3114 value = value != null ? value : this._value(); 3115 3116 // always save the actual value, not the one passed as an argument 3117 this.term = this._value(); 3118 3119 if ( value.length < this.options.minLength ) { 3120 return this.close( event ); 3121 } 3122 3123 if ( this._trigger( "search", event ) === false ) { 3124 return; 3125 } 3126 3127 return this._search( value ); 3128 }, 3129 3130 _search: function( value ) { 3131 this.pending++; 3132 this.element.addClass( "ui-autocomplete-loading" ); 3133 this.cancelSearch = false; 3134 3135 this.source( { term: value }, this._response() ); 3136 }, 3137 3138 _response: function() { 3139 var index = ++this.requestIndex; 3140 3141 return $.proxy(function( content ) { 3142 if ( index === this.requestIndex ) { 3143 this.__response( content ); 3144 } 3145 3146 this.pending--; 3147 if ( !this.pending ) { 3148 this.element.removeClass( "ui-autocomplete-loading" ); 3149 } 3150 }, this ); 3151 }, 3152 3153 __response: function( content ) { 3154 if ( content ) { 3155 content = this._normalize( content ); 3156 } 3157 this._trigger( "response", null, { content: content } ); 3158 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { 3159 this._suggest( content ); 3160 this._trigger( "open" ); 3161 } else { 3162 // use ._close() instead of .close() so we don't cancel future searches 3163 this._close(); 3164 } 3165 }, 3166 3167 close: function( event ) { 3168 this.cancelSearch = true; 3169 this._close( event ); 3170 }, 3171 3172 _close: function( event ) { 3173 if ( this.menu.element.is( ":visible" ) ) { 3174 this.menu.element.hide(); 3175 this.menu.blur(); 3176 this.isNewMenu = true; 3177 this._trigger( "close", event ); 3178 } 3179 }, 3180 3181 _change: function( event ) { 3182 if ( this.previous !== this._value() ) { 3183 this._trigger( "change", event, { item: this.selectedItem } ); 3184 } 3185 }, 3186 3187 _normalize: function( items ) { 3188 // assume all items have the right format when the first item is complete 3189 if ( items.length && items[ 0 ].label && items[ 0 ].value ) { 3190 return items; 3191 } 3192 return $.map( items, function( item ) { 3193 if ( typeof item === "string" ) { 3194 return { 3195 label: item, 3196 value: item 3197 }; 3198 } 3199 return $.extend( {}, item, { 3200 label: item.label || item.value, 3201 value: item.value || item.label 3202 }); 3203 }); 3204 }, 3205 3206 _suggest: function( items ) { 3207 var ul = this.menu.element.empty(); 3208 this._renderMenu( ul, items ); 3209 this.isNewMenu = true; 3210 this.menu.refresh(); 3211 3212 // size and position menu 3213 ul.show(); 3214 this._resizeMenu(); 3215 ul.position( $.extend({ 3216 of: this.element 3217 }, this.options.position ) ); 3218 3219 if ( this.options.autoFocus ) { 3220 this.menu.next(); 3221 } 3222 }, 3223 3224 _resizeMenu: function() { 3225 var ul = this.menu.element; 3226 ul.outerWidth( Math.max( 3227 // Firefox wraps long text (possibly a rounding bug) 3228 // so we add 1px to avoid the wrapping (#7513) 3229 ul.width( "" ).outerWidth() + 1, 3230 this.element.outerWidth() 3231 ) ); 3232 }, 3233 3234 _renderMenu: function( ul, items ) { 3235 var that = this; 3236 $.each( items, function( index, item ) { 3237 that._renderItemData( ul, item ); 3238 }); 3239 }, 3240 3241 _renderItemData: function( ul, item ) { 3242 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); 3243 }, 3244 3245 _renderItem: function( ul, item ) { 3246 return $( "<li>" ).text( item.label ).appendTo( ul ); 3247 }, 3248 3249 _move: function( direction, event ) { 3250 if ( !this.menu.element.is( ":visible" ) ) { 3251 this.search( null, event ); 3252 return; 3253 } 3254 if ( this.menu.isFirstItem() && /^previous/.test( direction ) || 3255 this.menu.isLastItem() && /^next/.test( direction ) ) { 3256 3257 if ( !this.isMultiLine ) { 3258 this._value( this.term ); 3259 } 3260 3261 this.menu.blur(); 3262 return; 3263 } 3264 this.menu[ direction ]( event ); 3265 }, 3266 3267 widget: function() { 3268 return this.menu.element; 3269 }, 3270 3271 _value: function() { 3272 return this.valueMethod.apply( this.element, arguments ); 3273 }, 3274 3275 _keyEvent: function( keyEvent, event ) { 3276 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { 3277 this._move( keyEvent, event ); 3278 3279 // prevents moving cursor to beginning/end of the text field in some browsers 3280 event.preventDefault(); 3281 } 3282 } 3283 }); 3284 3285 $.extend( $.ui.autocomplete, { 3286 escapeRegex: function( value ) { 3287 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); 3288 }, 3289 filter: function( array, term ) { 3290 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); 3291 return $.grep( array, function( value ) { 3292 return matcher.test( value.label || value.value || value ); 3293 }); 3294 } 3295 }); 3296 3297 // live region extension, adding a `messages` option 3298 // NOTE: This is an experimental API. We are still investigating 3299 // a full solution for string manipulation and internationalization. 3300 $.widget( "ui.autocomplete", $.ui.autocomplete, { 3301 options: { 3302 messages: { 3303 noResults: "No search results.", 3304 results: function( amount ) { 3305 return amount + ( amount > 1 ? " results are" : " result is" ) + 3306 " available, use up and down arrow keys to navigate."; 3307 } 3308 } 3309 }, 3310 3311 __response: function( content ) { 3312 var message; 3313 this._superApply( arguments ); 3314 if ( this.options.disabled || this.cancelSearch ) { 3315 return; 3316 } 3317 if ( content && content.length ) { 3318 message = this.options.messages.results( content.length ); 3319 } else { 3320 message = this.options.messages.noResults; 3321 } 3322 this.liveRegion.children().hide(); 3323 $( "<div>" ).text( message ).appendTo( this.liveRegion ); 3324 } 3325 }); 3326 3327 var autocomplete = $.ui.autocomplete; 3328 3329 3330 /*! 3331 * jQuery UI Button 1.11.1 3332 * http://jqueryui.com 3333 * 3334 * Copyright 2014 jQuery Foundation and other contributors 3335 * Released under the MIT license. 3336 * http://jquery.org/license 3337 * 3338 * http://api.jqueryui.com/button/ 3339 */ 3340 3341 3342 var lastActive, 3343 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all", 3344 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", 3345 formResetHandler = function() { 3346 var form = $( this ); 3347 setTimeout(function() { 3348 form.find( ":ui-button" ).button( "refresh" ); 3349 }, 1 ); 3350 }, 3351 radioGroup = function( radio ) { 3352 var name = radio.name, 3353 form = radio.form, 3354 radios = $( [] ); 3355 if ( name ) { 3356 name = name.replace( /'/g, "\\'" ); 3357 if ( form ) { 3358 radios = $( form ).find( "[name='" + name + "'][type=radio]" ); 3359 } else { 3360 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument ) 3361 .filter(function() { 3362 return !this.form; 3363 }); 3364 } 3365 } 3366 return radios; 3367 }; 3368 3369 $.widget( "ui.button", { 3370 version: "1.11.1", 3371 defaultElement: "<button>", 3372 options: { 3373 disabled: null, 3374 text: true, 3375 label: null, 3376 icons: { 3377 primary: null, 3378 secondary: null 3379 } 3380 }, 3381 _create: function() { 3382 this.element.closest( "form" ) 3383 .unbind( "reset" + this.eventNamespace ) 3384 .bind( "reset" + this.eventNamespace, formResetHandler ); 3385 3386 if ( typeof this.options.disabled !== "boolean" ) { 3387 this.options.disabled = !!this.element.prop( "disabled" ); 3388 } else { 3389 this.element.prop( "disabled", this.options.disabled ); 3390 } 3391 3392 this._determineButtonType(); 3393 this.hasTitle = !!this.buttonElement.attr( "title" ); 3394 3395 var that = this, 3396 options = this.options, 3397 toggleButton = this.type === "checkbox" || this.type === "radio", 3398 activeClass = !toggleButton ? "ui-state-active" : ""; 3399 3400 if ( options.label === null ) { 3401 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html()); 3402 } 3403 3404 this._hoverable( this.buttonElement ); 3405 3406 this.buttonElement 3407 .addClass( baseClasses ) 3408 .attr( "role", "button" ) 3409 .bind( "mouseenter" + this.eventNamespace, function() { 3410 if ( options.disabled ) { 3411 return; 3412 } 3413 if ( this === lastActive ) { 3414 $( this ).addClass( "ui-state-active" ); 3415 } 3416 }) 3417 .bind( "mouseleave" + this.eventNamespace, function() { 3418 if ( options.disabled ) { 3419 return; 3420 } 3421 $( this ).removeClass( activeClass ); 3422 }) 3423 .bind( "click" + this.eventNamespace, function( event ) { 3424 if ( options.disabled ) { 3425 event.preventDefault(); 3426 event.stopImmediatePropagation(); 3427 } 3428 }); 3429 3430 // Can't use _focusable() because the element that receives focus 3431 // and the element that gets the ui-state-focus class are different 3432 this._on({ 3433 focus: function() { 3434 this.buttonElement.addClass( "ui-state-focus" ); 3435 }, 3436 blur: function() { 3437 this.buttonElement.removeClass( "ui-state-focus" ); 3438 } 3439 }); 3440 3441 if ( toggleButton ) { 3442 this.element.bind( "change" + this.eventNamespace, function() { 3443 that.refresh(); 3444 }); 3445 } 3446 3447 if ( this.type === "checkbox" ) { 3448 this.buttonElement.bind( "click" + this.eventNamespace, function() { 3449 if ( options.disabled ) { 3450 return false; 3451 } 3452 }); 3453 } else if ( this.type === "radio" ) { 3454 this.buttonElement.bind( "click" + this.eventNamespace, function() { 3455 if ( options.disabled ) { 3456 return false; 3457 } 3458 $( this ).addClass( "ui-state-active" ); 3459 that.buttonElement.attr( "aria-pressed", "true" ); 3460 3461 var radio = that.element[ 0 ]; 3462 radioGroup( radio ) 3463 .not( radio ) 3464 .map(function() { 3465 return $( this ).button( "widget" )[ 0 ]; 3466 }) 3467 .removeClass( "ui-state-active" ) 3468 .attr( "aria-pressed", "false" ); 3469 }); 3470 } else { 3471 this.buttonElement 3472 .bind( "mousedown" + this.eventNamespace, function() { 3473 if ( options.disabled ) { 3474 return false; 3475 } 3476 $( this ).addClass( "ui-state-active" ); 3477 lastActive = this; 3478 that.document.one( "mouseup", function() { 3479 lastActive = null; 3480 }); 3481 }) 3482 .bind( "mouseup" + this.eventNamespace, function() { 3483 if ( options.disabled ) { 3484 return false; 3485 } 3486 $( this ).removeClass( "ui-state-active" ); 3487 }) 3488 .bind( "keydown" + this.eventNamespace, function(event) { 3489 if ( options.disabled ) { 3490 return false; 3491 } 3492 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) { 3493 $( this ).addClass( "ui-state-active" ); 3494 } 3495 }) 3496 // see #8559, we bind to blur here in case the button element loses 3497 // focus between keydown and keyup, it would be left in an "active" state 3498 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() { 3499 $( this ).removeClass( "ui-state-active" ); 3500 }); 3501 3502 if ( this.buttonElement.is("a") ) { 3503 this.buttonElement.keyup(function(event) { 3504 if ( event.keyCode === $.ui.keyCode.SPACE ) { 3505 // TODO pass through original event correctly (just as 2nd argument doesn't work) 3506 $( this ).click(); 3507 } 3508 }); 3509 } 3510 } 3511 3512 this._setOption( "disabled", options.disabled ); 3513 this._resetButton(); 3514 }, 3515 3516 _determineButtonType: function() { 3517 var ancestor, labelSelector, checked; 3518 3519 if ( this.element.is("[type=checkbox]") ) { 3520 this.type = "checkbox"; 3521 } else if ( this.element.is("[type=radio]") ) { 3522 this.type = "radio"; 3523 } else if ( this.element.is("input") ) { 3524 this.type = "input"; 3525 } else { 3526 this.type = "button"; 3527 } 3528 3529 if ( this.type === "checkbox" || this.type === "radio" ) { 3530 // we don't search against the document in case the element 3531 // is disconnected from the DOM 3532 ancestor = this.element.parents().last(); 3533 labelSelector = "label[for='" + this.element.attr("id") + "']"; 3534 this.buttonElement = ancestor.find( labelSelector ); 3535 if ( !this.buttonElement.length ) { 3536 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings(); 3537 this.buttonElement = ancestor.filter( labelSelector ); 3538 if ( !this.buttonElement.length ) { 3539 this.buttonElement = ancestor.find( labelSelector ); 3540 } 3541 } 3542 this.element.addClass( "ui-helper-hidden-accessible" ); 3543 3544 checked = this.element.is( ":checked" ); 3545 if ( checked ) { 3546 this.buttonElement.addClass( "ui-state-active" ); 3547 } 3548 this.buttonElement.prop( "aria-pressed", checked ); 3549 } else { 3550 this.buttonElement = this.element; 3551 } 3552 }, 3553 3554 widget: function() { 3555 return this.buttonElement; 3556 }, 3557 3558 _destroy: function() { 3559 this.element 3560 .removeClass( "ui-helper-hidden-accessible" ); 3561 this.buttonElement 3562 .removeClass( baseClasses + " ui-state-active " + typeClasses ) 3563 .removeAttr( "role" ) 3564 .removeAttr( "aria-pressed" ) 3565 .html( this.buttonElement.find(".ui-button-text").html() ); 3566 3567 if ( !this.hasTitle ) { 3568 this.buttonElement.removeAttr( "title" ); 3569 } 3570 }, 3571 3572 _setOption: function( key, value ) { 3573 this._super( key, value ); 3574 if ( key === "disabled" ) { 3575 this.widget().toggleClass( "ui-state-disabled", !!value ); 3576 this.element.prop( "disabled", !!value ); 3577 if ( value ) { 3578 if ( this.type === "checkbox" || this.type === "radio" ) { 3579 this.buttonElement.removeClass( "ui-state-focus" ); 3580 } else { 3581 this.buttonElement.removeClass( "ui-state-focus ui-state-active" ); 3582 } 3583 } 3584 return; 3585 } 3586 this._resetButton(); 3587 }, 3588 3589 refresh: function() { 3590 //See #8237 & #8828 3591 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" ); 3592 3593 if ( isDisabled !== this.options.disabled ) { 3594 this._setOption( "disabled", isDisabled ); 3595 } 3596 if ( this.type === "radio" ) { 3597 radioGroup( this.element[0] ).each(function() { 3598 if ( $( this ).is( ":checked" ) ) { 3599 $( this ).button( "widget" ) 3600 .addClass( "ui-state-active" ) 3601 .attr( "aria-pressed", "true" ); 3602 } else { 3603 $( this ).button( "widget" ) 3604 .removeClass( "ui-state-active" ) 3605 .attr( "aria-pressed", "false" ); 3606 } 3607 }); 3608 } else if ( this.type === "checkbox" ) { 3609 if ( this.element.is( ":checked" ) ) { 3610 this.buttonElement 3611 .addClass( "ui-state-active" ) 3612 .attr( "aria-pressed", "true" ); 3613 } else { 3614 this.buttonElement 3615 .removeClass( "ui-state-active" ) 3616 .attr( "aria-pressed", "false" ); 3617 } 3618 } 3619 }, 3620 3621 _resetButton: function() { 3622 if ( this.type === "input" ) { 3623 if ( this.options.label ) { 3624 this.element.val( this.options.label ); 3625 } 3626 return; 3627 } 3628 var buttonElement = this.buttonElement.removeClass( typeClasses ), 3629 buttonText = $( "<span></span>", this.document[0] ) 3630 .addClass( "ui-button-text" ) 3631 .html( this.options.label ) 3632 .appendTo( buttonElement.empty() ) 3633 .text(), 3634 icons = this.options.icons, 3635 multipleIcons = icons.primary && icons.secondary, 3636 buttonClasses = []; 3637 3638 if ( icons.primary || icons.secondary ) { 3639 if ( this.options.text ) { 3640 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) ); 3641 } 3642 3643 if ( icons.primary ) { 3644 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" ); 3645 } 3646 3647 if ( icons.secondary ) { 3648 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" ); 3649 } 3650 3651 if ( !this.options.text ) { 3652 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" ); 3653 3654 if ( !this.hasTitle ) { 3655 buttonElement.attr( "title", $.trim( buttonText ) ); 3656 } 3657 } 3658 } else { 3659 buttonClasses.push( "ui-button-text-only" ); 3660 } 3661 buttonElement.addClass( buttonClasses.join( " " ) ); 3662 } 3663 }); 3664 3665 $.widget( "ui.buttonset", { 3666 version: "1.11.1", 3667 options: { 3668 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)" 3669 }, 3670 3671 _create: function() { 3672 this.element.addClass( "ui-buttonset" ); 3673 }, 3674 3675 _init: function() { 3676 this.refresh(); 3677 }, 3678 3679 _setOption: function( key, value ) { 3680 if ( key === "disabled" ) { 3681 this.buttons.button( "option", key, value ); 3682 } 3683 3684 this._super( key, value ); 3685 }, 3686 3687 refresh: function() { 3688 var rtl = this.element.css( "direction" ) === "rtl", 3689 allButtons = this.element.find( this.options.items ), 3690 existingButtons = allButtons.filter( ":ui-button" ); 3691 3692 // Initialize new buttons 3693 allButtons.not( ":ui-button" ).button(); 3694 3695 // Refresh existing buttons 3696 existingButtons.button( "refresh" ); 3697 3698 this.buttons = allButtons 3699 .map(function() { 3700 return $( this ).button( "widget" )[ 0 ]; 3701 }) 3702 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" ) 3703 .filter( ":first" ) 3704 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" ) 3705 .end() 3706 .filter( ":last" ) 3707 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" ) 3708 .end() 3709 .end(); 3710 }, 3711 3712 _destroy: function() { 3713 this.element.removeClass( "ui-buttonset" ); 3714 this.buttons 3715 .map(function() { 3716 return $( this ).button( "widget" )[ 0 ]; 3717 }) 3718 .removeClass( "ui-corner-left ui-corner-right" ) 3719 .end() 3720 .button( "destroy" ); 3721 } 3722 }); 3723 3724 var button = $.ui.button; 3725 3726 3727 /*! 3728 * jQuery UI Datepicker 1.11.1 3729 * http://jqueryui.com 3730 * 3731 * Copyright 2014 jQuery Foundation and other contributors 3732 * Released under the MIT license. 3733 * http://jquery.org/license 3734 * 3735 * http://api.jqueryui.com/datepicker/ 3736 */ 3737 3738 3739 $.extend($.ui, { datepicker: { version: "1.11.1" } }); 3740 3741 var datepicker_instActive; 3742 3743 function datepicker_getZindex( elem ) { 3744 var position, value; 3745 while ( elem.length && elem[ 0 ] !== document ) { 3746 // Ignore z-index if position is set to a value where z-index is ignored by the browser 3747 // This makes behavior of this function consistent across browsers 3748 // WebKit always returns auto if the element is positioned 3749 position = elem.css( "position" ); 3750 if ( position === "absolute" || position === "relative" || position === "fixed" ) { 3751 // IE returns 0 when zIndex is not specified 3752 // other browsers return a string 3753 // we ignore the case of nested elements with an explicit value of 0 3754 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div> 3755 value = parseInt( elem.css( "zIndex" ), 10 ); 3756 if ( !isNaN( value ) && value !== 0 ) { 3757 return value; 3758 } 3759 } 3760 elem = elem.parent(); 3761 } 3762 3763 return 0; 3764 } 3765 /* Date picker manager. 3766 Use the singleton instance of this class, $.datepicker, to interact with the date picker. 3767 Settings for (groups of) date pickers are maintained in an instance object, 3768 allowing multiple different settings on the same page. */ 3769 3770 function Datepicker() { 3771 this._curInst = null; // The current instance in use 3772 this._keyEvent = false; // If the last event was a key event 3773 this._disabledInputs = []; // List of date picker inputs that have been disabled 3774 this._datepickerShowing = false; // True if the popup picker is showing , false if not 3775 this._inDialog = false; // True if showing within a "dialog", false if not 3776 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division 3777 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class 3778 this._appendClass = "ui-datepicker-append"; // The name of the append marker class 3779 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class 3780 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class 3781 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class 3782 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class 3783 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class 3784 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class 3785 this.regional = []; // Available regional settings, indexed by language code 3786 this.regional[""] = { // Default regional settings 3787 closeText: "Done", // Display text for close link 3788 prevText: "Prev", // Display text for previous month link 3789 nextText: "Next", // Display text for next month link 3790 currentText: "Today", // Display text for current month link 3791 monthNames: ["January","February","March","April","May","June", 3792 "July","August","September","October","November","December"], // Names of months for drop-down and formatting 3793 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting 3794 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting 3795 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting 3796 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday 3797 weekHeader: "Wk", // Column header for week of the year 3798 dateFormat: "mm/dd/yy", // See format options on parseDate 3799 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ... 3800 isRTL: false, // True if right-to-left language, false if left-to-right 3801 showMonthAfterYear: false, // True if the year select precedes month, false for month then year 3802 yearSuffix: "" // Additional text to append to the year in the month headers 3803 }; 3804 this._defaults = { // Global defaults for all the date picker instances 3805 showOn: "focus", // "focus" for popup on focus, 3806 // "button" for trigger button, or "both" for either 3807 showAnim: "fadeIn", // Name of jQuery animation for popup 3808 showOptions: {}, // Options for enhanced animations 3809 defaultDate: null, // Used when field is blank: actual date, 3810 // +/-number for offset from today, null for today 3811 appendText: "", // Display text following the input box, e.g. showing the format 3812 buttonText: "...", // Text for trigger button 3813 buttonImage: "", // URL for trigger button image 3814 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button 3815 hideIfNoPrevNext: false, // True to hide next/previous month links 3816 // if not applicable, false to just disable them 3817 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links 3818 gotoCurrent: false, // True if today link goes back to current selection instead 3819 changeMonth: false, // True if month can be selected directly, false if only prev/next 3820 changeYear: false, // True if year can be selected directly, false if only prev/next 3821 yearRange: "c-10:c+10", // Range of years to display in drop-down, 3822 // either relative to today's year (-nn:+nn), relative to currently displayed year 3823 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n) 3824 showOtherMonths: false, // True to show dates in other months, false to leave blank 3825 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable 3826 showWeek: false, // True to show week of the year, false to not show it 3827 calculateWeek: this.iso8601Week, // How to calculate the week of the year, 3828 // takes a Date and returns the number of the week for it 3829 shortYearCutoff: "+10", // Short year values < this are in the current century, 3830 // > this are in the previous century, 3831 // string value starting with "+" for current year + value 3832 minDate: null, // The earliest selectable date, or null for no limit 3833 maxDate: null, // The latest selectable date, or null for no limit 3834 duration: "fast", // Duration of display/closure 3835 beforeShowDay: null, // Function that takes a date and returns an array with 3836 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "", 3837 // [2] = cell title (optional), e.g. $.datepicker.noWeekends 3838 beforeShow: null, // Function that takes an input field and 3839 // returns a set of custom settings for the date picker 3840 onSelect: null, // Define a callback function when a date is selected 3841 onChangeMonthYear: null, // Define a callback function when the month or year is changed 3842 onClose: null, // Define a callback function when the datepicker is closed 3843 numberOfMonths: 1, // Number of months to show at a time 3844 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0) 3845 stepMonths: 1, // Number of months to step back/forward 3846 stepBigMonths: 12, // Number of months to step back/forward for the big links 3847 altField: "", // Selector for an alternate field to store selected dates into 3848 altFormat: "", // The date format to use for the alternate field 3849 constrainInput: true, // The input is constrained by the current date format 3850 showButtonPanel: false, // True to show button panel, false to not show it 3851 autoSize: false, // True to size the input for the date format, false to leave as is 3852 disabled: false // The initial disabled state 3853 }; 3854 $.extend(this._defaults, this.regional[""]); 3855 this.regional.en = $.extend( true, {}, this.regional[ "" ]); 3856 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en ); 3857 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")); 3858 } 3859 3860 $.extend(Datepicker.prototype, { 3861 /* Class name added to elements to indicate already configured with a date picker. */ 3862 markerClassName: "hasDatepicker", 3863 3864 //Keep track of the maximum number of rows displayed (see #7043) 3865 maxRows: 4, 3866 3867 // TODO rename to "widget" when switching to widget factory 3868 _widgetDatepicker: function() { 3869 return this.dpDiv; 3870 }, 3871 3872 /* Override the default settings for all instances of the date picker. 3873 * @param settings object - the new settings to use as defaults (anonymous object) 3874 * @return the manager object 3875 */ 3876 setDefaults: function(settings) { 3877 datepicker_extendRemove(this._defaults, settings || {}); 3878 return this; 3879 }, 3880 3881 /* Attach the date picker to a jQuery selection. 3882 * @param target element - the target input field or division or span 3883 * @param settings object - the new settings to use for this date picker instance (anonymous) 3884 */ 3885 _attachDatepicker: function(target, settings) { 3886 var nodeName, inline, inst; 3887 nodeName = target.nodeName.toLowerCase(); 3888 inline = (nodeName === "div" || nodeName === "span"); 3889 if (!target.id) { 3890 this.uuid += 1; 3891 target.id = "dp" + this.uuid; 3892 } 3893 inst = this._newInst($(target), inline); 3894 inst.settings = $.extend({}, settings || {}); 3895 if (nodeName === "input") { 3896 this._connectDatepicker(target, inst); 3897 } else if (inline) { 3898 this._inlineDatepicker(target, inst); 3899 } 3900 }, 3901 3902 /* Create a new instance object. */ 3903 _newInst: function(target, inline) { 3904 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars 3905 return {id: id, input: target, // associated target 3906 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection 3907 drawMonth: 0, drawYear: 0, // month being drawn 3908 inline: inline, // is datepicker inline or not 3909 dpDiv: (!inline ? this.dpDiv : // presentation div 3910 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))}; 3911 }, 3912 3913 /* Attach the date picker to an input field. */ 3914 _connectDatepicker: function(target, inst) { 3915 var input = $(target); 3916 inst.append = $([]); 3917 inst.trigger = $([]); 3918 if (input.hasClass(this.markerClassName)) { 3919 return; 3920 } 3921 this._attachments(input, inst); 3922 input.addClass(this.markerClassName).keydown(this._doKeyDown). 3923 keypress(this._doKeyPress).keyup(this._doKeyUp); 3924 this._autoSize(inst); 3925 $.data(target, "datepicker", inst); 3926 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665) 3927 if( inst.settings.disabled ) { 3928 this._disableDatepicker( target ); 3929 } 3930 }, 3931 3932 /* Make attachments based on settings. */ 3933 _attachments: function(input, inst) { 3934 var showOn, buttonText, buttonImage, 3935 appendText = this._get(inst, "appendText"), 3936 isRTL = this._get(inst, "isRTL"); 3937 3938 if (inst.append) { 3939 inst.append.remove(); 3940 } 3941 if (appendText) { 3942 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>"); 3943 input[isRTL ? "before" : "after"](inst.append); 3944 } 3945 3946 input.unbind("focus", this._showDatepicker); 3947 3948 if (inst.trigger) { 3949 inst.trigger.remove(); 3950 } 3951 3952 showOn = this._get(inst, "showOn"); 3953 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field 3954 input.focus(this._showDatepicker); 3955 } 3956 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked 3957 buttonText = this._get(inst, "buttonText"); 3958 buttonImage = this._get(inst, "buttonImage"); 3959 inst.trigger = $(this._get(inst, "buttonImageOnly") ? 3960 $("<img/>").addClass(this._triggerClass). 3961 attr({ src: buttonImage, alt: buttonText, title: buttonText }) : 3962 $("<button type='button'></button>").addClass(this._triggerClass). 3963 html(!buttonImage ? buttonText : $("<img/>").attr( 3964 { src:buttonImage, alt:buttonText, title:buttonText }))); 3965 input[isRTL ? "before" : "after"](inst.trigger); 3966 inst.trigger.click(function() { 3967 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) { 3968 $.datepicker._hideDatepicker(); 3969 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) { 3970 $.datepicker._hideDatepicker(); 3971 $.datepicker._showDatepicker(input[0]); 3972 } else { 3973 $.datepicker._showDatepicker(input[0]); 3974 } 3975 return false; 3976 }); 3977 } 3978 }, 3979 3980 /* Apply the maximum length for the date format. */ 3981 _autoSize: function(inst) { 3982 if (this._get(inst, "autoSize") && !inst.inline) { 3983 var findMax, max, maxI, i, 3984 date = new Date(2009, 12 - 1, 20), // Ensure double digits 3985 dateFormat = this._get(inst, "dateFormat"); 3986 3987 if (dateFormat.match(/[DM]/)) { 3988 findMax = function(names) { 3989 max = 0; 3990 maxI = 0; 3991 for (i = 0; i < names.length; i++) { 3992 if (names[i].length > max) { 3993 max = names[i].length; 3994 maxI = i; 3995 } 3996 } 3997 return maxI; 3998 }; 3999 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ? 4000 "monthNames" : "monthNamesShort")))); 4001 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ? 4002 "dayNames" : "dayNamesShort"))) + 20 - date.getDay()); 4003 } 4004 inst.input.attr("size", this._formatDate(inst, date).length); 4005 } 4006 }, 4007 4008 /* Attach an inline date picker to a div. */ 4009 _inlineDatepicker: function(target, inst) { 4010 var divSpan = $(target); 4011 if (divSpan.hasClass(this.markerClassName)) { 4012 return; 4013 } 4014 divSpan.addClass(this.markerClassName).append(inst.dpDiv); 4015 $.data(target, "datepicker", inst); 4016 this._setDate(inst, this._getDefaultDate(inst), true); 4017 this._updateDatepicker(inst); 4018 this._updateAlternate(inst); 4019 //If disabled option is true, disable the datepicker before showing it (see ticket #5665) 4020 if( inst.settings.disabled ) { 4021 this._disableDatepicker( target ); 4022 } 4023 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements 4024 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height 4025 inst.dpDiv.css( "display", "block" ); 4026 }, 4027 4028 /* Pop-up the date picker in a "dialog" box. 4029 * @param input element - ignored 4030 * @param date string or Date - the initial date to display 4031 * @param onSelect function - the function to call when a date is selected 4032 * @param settings object - update the dialog date picker instance's settings (anonymous object) 4033 * @param pos int[2] - coordinates for the dialog's position within the screen or 4034 * event - with x/y coordinates or 4035 * leave empty for default (screen centre) 4036 * @return the manager object 4037 */ 4038 _dialogDatepicker: function(input, date, onSelect, settings, pos) { 4039 var id, browserWidth, browserHeight, scrollX, scrollY, 4040 inst = this._dialogInst; // internal instance 4041 4042 if (!inst) { 4043 this.uuid += 1; 4044 id = "dp" + this.uuid; 4045 this._dialogInput = $("<input type='text' id='" + id + 4046 "' style='position: absolute; top: -100px; width: 0px;'/>"); 4047 this._dialogInput.keydown(this._doKeyDown); 4048 $("body").append(this._dialogInput); 4049 inst = this._dialogInst = this._newInst(this._dialogInput, false); 4050 inst.settings = {}; 4051 $.data(this._dialogInput[0], "datepicker", inst); 4052 } 4053 datepicker_extendRemove(inst.settings, settings || {}); 4054 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date); 4055 this._dialogInput.val(date); 4056 4057 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null); 4058 if (!this._pos) { 4059 browserWidth = document.documentElement.clientWidth; 4060 browserHeight = document.documentElement.clientHeight; 4061 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft; 4062 scrollY = document.documentElement.scrollTop || document.body.scrollTop; 4063 this._pos = // should use actual width/height below 4064 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY]; 4065 } 4066 4067 // move input on screen for focus, but hidden behind dialog 4068 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px"); 4069 inst.settings.onSelect = onSelect; 4070 this._inDialog = true; 4071 this.dpDiv.addClass(this._dialogClass); 4072 this._showDatepicker(this._dialogInput[0]); 4073 if ($.blockUI) { 4074 $.blockUI(this.dpDiv); 4075 } 4076 $.data(this._dialogInput[0], "datepicker", inst); 4077 return this; 4078 }, 4079 4080 /* Detach a datepicker from its control. 4081 * @param target element - the target input field or division or span 4082 */ 4083 _destroyDatepicker: function(target) { 4084 var nodeName, 4085 $target = $(target), 4086 inst = $.data(target, "datepicker"); 4087 4088 if (!$target.hasClass(this.markerClassName)) { 4089 return; 4090 } 4091 4092 nodeName = target.nodeName.toLowerCase(); 4093 $.removeData(target, "datepicker"); 4094 if (nodeName === "input") { 4095 inst.append.remove(); 4096 inst.trigger.remove(); 4097 $target.removeClass(this.markerClassName). 4098 unbind("focus", this._showDatepicker). 4099 unbind("keydown", this._doKeyDown). 4100 unbind("keypress", this._doKeyPress). 4101 unbind("keyup", this._doKeyUp); 4102 } else if (nodeName === "div" || nodeName === "span") { 4103 $target.removeClass(this.markerClassName).empty(); 4104 } 4105 }, 4106 4107 /* Enable the date picker to a jQuery selection. 4108 * @param target element - the target input field or division or span 4109 */ 4110 _enableDatepicker: function(target) { 4111 var nodeName, inline, 4112 $target = $(target), 4113 inst = $.data(target, "datepicker"); 4114 4115 if (!$target.hasClass(this.markerClassName)) { 4116 return; 4117 } 4118 4119 nodeName = target.nodeName.toLowerCase(); 4120 if (nodeName === "input") { 4121 target.disabled = false; 4122 inst.trigger.filter("button"). 4123 each(function() { this.disabled = false; }).end(). 4124 filter("img").css({opacity: "1.0", cursor: ""}); 4125 } else if (nodeName === "div" || nodeName === "span") { 4126 inline = $target.children("." + this._inlineClass); 4127 inline.children().removeClass("ui-state-disabled"); 4128 inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). 4129 prop("disabled", false); 4130 } 4131 this._disabledInputs = $.map(this._disabledInputs, 4132 function(value) { return (value === target ? null : value); }); // delete entry 4133 }, 4134 4135 /* Disable the date picker to a jQuery selection. 4136 * @param target element - the target input field or division or span 4137 */ 4138 _disableDatepicker: function(target) { 4139 var nodeName, inline, 4140 $target = $(target), 4141 inst = $.data(target, "datepicker"); 4142 4143 if (!$target.hasClass(this.markerClassName)) { 4144 return; 4145 } 4146 4147 nodeName = target.nodeName.toLowerCase(); 4148 if (nodeName === "input") { 4149 target.disabled = true; 4150 inst.trigger.filter("button"). 4151 each(function() { this.disabled = true; }).end(). 4152 filter("img").css({opacity: "0.5", cursor: "default"}); 4153 } else if (nodeName === "div" || nodeName === "span") { 4154 inline = $target.children("." + this._inlineClass); 4155 inline.children().addClass("ui-state-disabled"); 4156 inline.find("select.ui-datepicker-month, select.ui-datepicker-year"). 4157 prop("disabled", true); 4158 } 4159 this._disabledInputs = $.map(this._disabledInputs, 4160 function(value) { return (value === target ? null : value); }); // delete entry 4161 this._disabledInputs[this._disabledInputs.length] = target; 4162 }, 4163 4164 /* Is the first field in a jQuery collection disabled as a datepicker? 4165 * @param target element - the target input field or division or span 4166 * @return boolean - true if disabled, false if enabled 4167 */ 4168 _isDisabledDatepicker: function(target) { 4169 if (!target) { 4170 return false; 4171 } 4172 for (var i = 0; i < this._disabledInputs.length; i++) { 4173 if (this._disabledInputs[i] === target) { 4174 return true; 4175 } 4176 } 4177 return false; 4178 }, 4179 4180 /* Retrieve the instance data for the target control. 4181 * @param target element - the target input field or division or span 4182 * @return object - the associated instance data 4183 * @throws error if a jQuery problem getting data 4184 */ 4185 _getInst: function(target) { 4186 try { 4187 return $.data(target, "datepicker"); 4188 } 4189 catch (err) { 4190 throw "Missing instance data for this datepicker"; 4191 } 4192 }, 4193 4194 /* Update or retrieve the settings for a date picker attached to an input field or division. 4195 * @param target element - the target input field or division or span 4196 * @param name object - the new settings to update or 4197 * string - the name of the setting to change or retrieve, 4198 * when retrieving also "all" for all instance settings or 4199 * "defaults" for all global defaults 4200 * @param value any - the new value for the setting 4201 * (omit if above is an object or to retrieve a value) 4202 */ 4203 _optionDatepicker: function(target, name, value) { 4204 var settings, date, minDate, maxDate, 4205 inst = this._getInst(target); 4206 4207 if (arguments.length === 2 && typeof name === "string") { 4208 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) : 4209 (inst ? (name === "all" ? $.extend({}, inst.settings) : 4210 this._get(inst, name)) : null)); 4211 } 4212 4213 settings = name || {}; 4214 if (typeof name === "string") { 4215 settings = {}; 4216 settings[name] = value; 4217 } 4218 4219 if (inst) { 4220 if (this._curInst === inst) { 4221 this._hideDatepicker(); 4222 } 4223 4224 date = this._getDateDatepicker(target, true); 4225 minDate = this._getMinMaxDate(inst, "min"); 4226 maxDate = this._getMinMaxDate(inst, "max"); 4227 datepicker_extendRemove(inst.settings, settings); 4228 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided 4229 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) { 4230 inst.settings.minDate = this._formatDate(inst, minDate); 4231 } 4232 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) { 4233 inst.settings.maxDate = this._formatDate(inst, maxDate); 4234 } 4235 if ( "disabled" in settings ) { 4236 if ( settings.disabled ) { 4237 this._disableDatepicker(target); 4238 } else { 4239 this._enableDatepicker(target); 4240 } 4241 } 4242 this._attachments($(target), inst); 4243 this._autoSize(inst); 4244 this._setDate(inst, date); 4245 this._updateAlternate(inst); 4246 this._updateDatepicker(inst); 4247 } 4248 }, 4249 4250 // change method deprecated 4251 _changeDatepicker: function(target, name, value) { 4252 this._optionDatepicker(target, name, value); 4253 }, 4254 4255 /* Redraw the date picker attached to an input field or division. 4256 * @param target element - the target input field or division or span 4257 */ 4258 _refreshDatepicker: function(target) { 4259 var inst = this._getInst(target); 4260 if (inst) { 4261 this._updateDatepicker(inst); 4262 } 4263 }, 4264 4265 /* Set the dates for a jQuery selection. 4266 * @param target element - the target input field or division or span 4267 * @param date Date - the new date 4268 */ 4269 _setDateDatepicker: function(target, date) { 4270 var inst = this._getInst(target); 4271 if (inst) { 4272 this._setDate(inst, date); 4273 this._updateDatepicker(inst); 4274 this._updateAlternate(inst); 4275 } 4276 }, 4277 4278 /* Get the date(s) for the first entry in a jQuery selection. 4279 * @param target element - the target input field or division or span 4280 * @param noDefault boolean - true if no default date is to be used 4281 * @return Date - the current date 4282 */ 4283 _getDateDatepicker: function(target, noDefault) { 4284 var inst = this._getInst(target); 4285 if (inst && !inst.inline) { 4286 this._setDateFromField(inst, noDefault); 4287 } 4288 return (inst ? this._getDate(inst) : null); 4289 }, 4290 4291 /* Handle keystrokes. */ 4292 _doKeyDown: function(event) { 4293 var onSelect, dateStr, sel, 4294 inst = $.datepicker._getInst(event.target), 4295 handled = true, 4296 isRTL = inst.dpDiv.is(".ui-datepicker-rtl"); 4297 4298 inst._keyEvent = true; 4299 if ($.datepicker._datepickerShowing) { 4300 switch (event.keyCode) { 4301 case 9: $.datepicker._hideDatepicker(); 4302 handled = false; 4303 break; // hide on tab out 4304 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." + 4305 $.datepicker._currentClass + ")", inst.dpDiv); 4306 if (sel[0]) { 4307 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]); 4308 } 4309 4310 onSelect = $.datepicker._get(inst, "onSelect"); 4311 if (onSelect) { 4312 dateStr = $.datepicker._formatDate(inst); 4313 4314 // trigger custom callback 4315 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); 4316 } else { 4317 $.datepicker._hideDatepicker(); 4318 } 4319 4320 return false; // don't submit the form 4321 case 27: $.datepicker._hideDatepicker(); 4322 break; // hide on escape 4323 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4324 -$.datepicker._get(inst, "stepBigMonths") : 4325 -$.datepicker._get(inst, "stepMonths")), "M"); 4326 break; // previous month/year on page up/+ ctrl 4327 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4328 +$.datepicker._get(inst, "stepBigMonths") : 4329 +$.datepicker._get(inst, "stepMonths")), "M"); 4330 break; // next month/year on page down/+ ctrl 4331 case 35: if (event.ctrlKey || event.metaKey) { 4332 $.datepicker._clearDate(event.target); 4333 } 4334 handled = event.ctrlKey || event.metaKey; 4335 break; // clear on ctrl or command +end 4336 case 36: if (event.ctrlKey || event.metaKey) { 4337 $.datepicker._gotoToday(event.target); 4338 } 4339 handled = event.ctrlKey || event.metaKey; 4340 break; // current on ctrl or command +home 4341 case 37: if (event.ctrlKey || event.metaKey) { 4342 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D"); 4343 } 4344 handled = event.ctrlKey || event.metaKey; 4345 // -1 day on ctrl or command +left 4346 if (event.originalEvent.altKey) { 4347 $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4348 -$.datepicker._get(inst, "stepBigMonths") : 4349 -$.datepicker._get(inst, "stepMonths")), "M"); 4350 } 4351 // next month/year on alt +left on Mac 4352 break; 4353 case 38: if (event.ctrlKey || event.metaKey) { 4354 $.datepicker._adjustDate(event.target, -7, "D"); 4355 } 4356 handled = event.ctrlKey || event.metaKey; 4357 break; // -1 week on ctrl or command +up 4358 case 39: if (event.ctrlKey || event.metaKey) { 4359 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D"); 4360 } 4361 handled = event.ctrlKey || event.metaKey; 4362 // +1 day on ctrl or command +right 4363 if (event.originalEvent.altKey) { 4364 $.datepicker._adjustDate(event.target, (event.ctrlKey ? 4365 +$.datepicker._get(inst, "stepBigMonths") : 4366 +$.datepicker._get(inst, "stepMonths")), "M"); 4367 } 4368 // next month/year on alt +right 4369 break; 4370 case 40: if (event.ctrlKey || event.metaKey) { 4371 $.datepicker._adjustDate(event.target, +7, "D"); 4372 } 4373 handled = event.ctrlKey || event.metaKey; 4374 break; // +1 week on ctrl or command +down 4375 default: handled = false; 4376 } 4377 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home 4378 $.datepicker._showDatepicker(this); 4379 } else { 4380 handled = false; 4381 } 4382 4383 if (handled) { 4384 event.preventDefault(); 4385 event.stopPropagation(); 4386 } 4387 }, 4388 4389 /* Filter entered characters - based on date format. */ 4390 _doKeyPress: function(event) { 4391 var chars, chr, 4392 inst = $.datepicker._getInst(event.target); 4393 4394 if ($.datepicker._get(inst, "constrainInput")) { 4395 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat")); 4396 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode); 4397 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1); 4398 } 4399 }, 4400 4401 /* Synchronise manual entry and field/alternate field. */ 4402 _doKeyUp: function(event) { 4403 var date, 4404 inst = $.datepicker._getInst(event.target); 4405 4406 if (inst.input.val() !== inst.lastVal) { 4407 try { 4408 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), 4409 (inst.input ? inst.input.val() : null), 4410 $.datepicker._getFormatConfig(inst)); 4411 4412 if (date) { // only if valid 4413 $.datepicker._setDateFromField(inst); 4414 $.datepicker._updateAlternate(inst); 4415 $.datepicker._updateDatepicker(inst); 4416 } 4417 } 4418 catch (err) { 4419 } 4420 } 4421 return true; 4422 }, 4423 4424 /* Pop-up the date picker for a given input field. 4425 * If false returned from beforeShow event handler do not show. 4426 * @param input element - the input field attached to the date picker or 4427 * event - if triggered by focus 4428 */ 4429 _showDatepicker: function(input) { 4430 input = input.target || input; 4431 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger 4432 input = $("input", input.parentNode)[0]; 4433 } 4434 4435 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here 4436 return; 4437 } 4438 4439 var inst, beforeShow, beforeShowSettings, isFixed, 4440 offset, showAnim, duration; 4441 4442 inst = $.datepicker._getInst(input); 4443 if ($.datepicker._curInst && $.datepicker._curInst !== inst) { 4444 $.datepicker._curInst.dpDiv.stop(true, true); 4445 if ( inst && $.datepicker._datepickerShowing ) { 4446 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] ); 4447 } 4448 } 4449 4450 beforeShow = $.datepicker._get(inst, "beforeShow"); 4451 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {}; 4452 if(beforeShowSettings === false){ 4453 return; 4454 } 4455 datepicker_extendRemove(inst.settings, beforeShowSettings); 4456 4457 inst.lastVal = null; 4458 $.datepicker._lastInput = input; 4459 $.datepicker._setDateFromField(inst); 4460 4461 if ($.datepicker._inDialog) { // hide cursor 4462 input.value = ""; 4463 } 4464 if (!$.datepicker._pos) { // position below input 4465 $.datepicker._pos = $.datepicker._findPos(input); 4466 $.datepicker._pos[1] += input.offsetHeight; // add the height 4467 } 4468 4469 isFixed = false; 4470 $(input).parents().each(function() { 4471 isFixed |= $(this).css("position") === "fixed"; 4472 return !isFixed; 4473 }); 4474 4475 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]}; 4476 $.datepicker._pos = null; 4477 //to avoid flashes on Firefox 4478 inst.dpDiv.empty(); 4479 // determine sizing offscreen 4480 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"}); 4481 $.datepicker._updateDatepicker(inst); 4482 // fix width for dynamic number of date pickers 4483 // and adjust position before showing 4484 offset = $.datepicker._checkOffset(inst, offset, isFixed); 4485 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ? 4486 "static" : (isFixed ? "fixed" : "absolute")), display: "none", 4487 left: offset.left + "px", top: offset.top + "px"}); 4488 4489 if (!inst.inline) { 4490 showAnim = $.datepicker._get(inst, "showAnim"); 4491 duration = $.datepicker._get(inst, "duration"); 4492 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 ); 4493 $.datepicker._datepickerShowing = true; 4494 4495 if ( $.effects && $.effects.effect[ showAnim ] ) { 4496 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration); 4497 } else { 4498 inst.dpDiv[showAnim || "show"](showAnim ? duration : null); 4499 } 4500 4501 if ( $.datepicker._shouldFocusInput( inst ) ) { 4502 inst.input.focus(); 4503 } 4504 4505 $.datepicker._curInst = inst; 4506 } 4507 }, 4508 4509 /* Generate the date picker content. */ 4510 _updateDatepicker: function(inst) { 4511 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043) 4512 datepicker_instActive = inst; // for delegate hover events 4513 inst.dpDiv.empty().append(this._generateHTML(inst)); 4514 this._attachHandlers(inst); 4515 4516 var origyearshtml, 4517 numMonths = this._getNumberOfMonths(inst), 4518 cols = numMonths[1], 4519 width = 17, 4520 activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" ); 4521 4522 if ( activeCell.length > 0 ) { 4523 datepicker_handleMouseover.apply( activeCell.get( 0 ) ); 4524 } 4525 4526 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""); 4527 if (cols > 1) { 4528 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em"); 4529 } 4530 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") + 4531 "Class"]("ui-datepicker-multi"); 4532 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") + 4533 "Class"]("ui-datepicker-rtl"); 4534 4535 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) { 4536 inst.input.focus(); 4537 } 4538 4539 // deffered render of the years select (to avoid flashes on Firefox) 4540 if( inst.yearshtml ){ 4541 origyearshtml = inst.yearshtml; 4542 setTimeout(function(){ 4543 //assure that inst.yearshtml didn't change. 4544 if( origyearshtml === inst.yearshtml && inst.yearshtml ){ 4545 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml); 4546 } 4547 origyearshtml = inst.yearshtml = null; 4548 }, 0); 4549 } 4550 }, 4551 4552 // #6694 - don't focus the input if it's already focused 4553 // this breaks the change event in IE 4554 // Support: IE and jQuery <1.9 4555 _shouldFocusInput: function( inst ) { 4556 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" ); 4557 }, 4558 4559 /* Check positioning to remain on screen. */ 4560 _checkOffset: function(inst, offset, isFixed) { 4561 var dpWidth = inst.dpDiv.outerWidth(), 4562 dpHeight = inst.dpDiv.outerHeight(), 4563 inputWidth = inst.input ? inst.input.outerWidth() : 0, 4564 inputHeight = inst.input ? inst.input.outerHeight() : 0, 4565 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()), 4566 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop()); 4567 4568 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0); 4569 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0; 4570 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0; 4571 4572 // now check if datepicker is showing outside window viewport - move to a better place if so. 4573 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ? 4574 Math.abs(offset.left + dpWidth - viewWidth) : 0); 4575 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ? 4576 Math.abs(dpHeight + inputHeight) : 0); 4577 4578 return offset; 4579 }, 4580 4581 /* Find an object's position on the screen. */ 4582 _findPos: function(obj) { 4583 var position, 4584 inst = this._getInst(obj), 4585 isRTL = this._get(inst, "isRTL"); 4586 4587 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) { 4588 obj = obj[isRTL ? "previousSibling" : "nextSibling"]; 4589 } 4590 4591 position = $(obj).offset(); 4592 return [position.left, position.top]; 4593 }, 4594 4595 /* Hide the date picker from view. 4596 * @param input element - the input field attached to the date picker 4597 */ 4598 _hideDatepicker: function(input) { 4599 var showAnim, duration, postProcess, onClose, 4600 inst = this._curInst; 4601 4602 if (!inst || (input && inst !== $.data(input, "datepicker"))) { 4603 return; 4604 } 4605 4606 if (this._datepickerShowing) { 4607 showAnim = this._get(inst, "showAnim"); 4608 duration = this._get(inst, "duration"); 4609 postProcess = function() { 4610 $.datepicker._tidyDialog(inst); 4611 }; 4612 4613 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed 4614 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) { 4615 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess); 4616 } else { 4617 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" : 4618 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess); 4619 } 4620 4621 if (!showAnim) { 4622 postProcess(); 4623 } 4624 this._datepickerShowing = false; 4625 4626 onClose = this._get(inst, "onClose"); 4627 if (onClose) { 4628 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]); 4629 } 4630 4631 this._lastInput = null; 4632 if (this._inDialog) { 4633 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" }); 4634 if ($.blockUI) { 4635 $.unblockUI(); 4636 $("body").append(this.dpDiv); 4637 } 4638 } 4639 this._inDialog = false; 4640 } 4641 }, 4642 4643 /* Tidy up after a dialog display. */ 4644 _tidyDialog: function(inst) { 4645 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar"); 4646 }, 4647 4648 /* Close date picker if clicked elsewhere. */ 4649 _checkExternalClick: function(event) { 4650 if (!$.datepicker._curInst) { 4651 return; 4652 } 4653 4654 var $target = $(event.target), 4655 inst = $.datepicker._getInst($target[0]); 4656 4657 if ( ( ( $target[0].id !== $.datepicker._mainDivId && 4658 $target.parents("#" + $.datepicker._mainDivId).length === 0 && 4659 !$target.hasClass($.datepicker.markerClassName) && 4660 !$target.closest("." + $.datepicker._triggerClass).length && 4661 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) || 4662 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) { 4663 $.datepicker._hideDatepicker(); 4664 } 4665 }, 4666 4667 /* Adjust one of the date sub-fields. */ 4668 _adjustDate: function(id, offset, period) { 4669 var target = $(id), 4670 inst = this._getInst(target[0]); 4671 4672 if (this._isDisabledDatepicker(target[0])) { 4673 return; 4674 } 4675 this._adjustInstDate(inst, offset + 4676 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning 4677 period); 4678 this._updateDatepicker(inst); 4679 }, 4680 4681 /* Action for current link. */ 4682 _gotoToday: function(id) { 4683 var date, 4684 target = $(id), 4685 inst = this._getInst(target[0]); 4686 4687 if (this._get(inst, "gotoCurrent") && inst.currentDay) { 4688 inst.selectedDay = inst.currentDay; 4689 inst.drawMonth = inst.selectedMonth = inst.currentMonth; 4690 inst.drawYear = inst.selectedYear = inst.currentYear; 4691 } else { 4692 date = new Date(); 4693 inst.selectedDay = date.getDate(); 4694 inst.drawMonth = inst.selectedMonth = date.getMonth(); 4695 inst.drawYear = inst.selectedYear = date.getFullYear(); 4696 } 4697 this._notifyChange(inst); 4698 this._adjustDate(target); 4699 }, 4700 4701 /* Action for selecting a new month/year. */ 4702 _selectMonthYear: function(id, select, period) { 4703 var target = $(id), 4704 inst = this._getInst(target[0]); 4705 4706 inst["selected" + (period === "M" ? "Month" : "Year")] = 4707 inst["draw" + (period === "M" ? "Month" : "Year")] = 4708 parseInt(select.options[select.selectedIndex].value,10); 4709 4710 this._notifyChange(inst); 4711 this._adjustDate(target); 4712 }, 4713 4714 /* Action for selecting a day. */ 4715 _selectDay: function(id, month, year, td) { 4716 var inst, 4717 target = $(id); 4718 4719 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) { 4720 return; 4721 } 4722 4723 inst = this._getInst(target[0]); 4724 inst.selectedDay = inst.currentDay = $("a", td).html(); 4725 inst.selectedMonth = inst.currentMonth = month; 4726 inst.selectedYear = inst.currentYear = year; 4727 this._selectDate(id, this._formatDate(inst, 4728 inst.currentDay, inst.currentMonth, inst.currentYear)); 4729 }, 4730 4731 /* Erase the input field and hide the date picker. */ 4732 _clearDate: function(id) { 4733 var target = $(id); 4734 this._selectDate(target, ""); 4735 }, 4736 4737 /* Update the input field with the selected date. */ 4738 _selectDate: function(id, dateStr) { 4739 var onSelect, 4740 target = $(id), 4741 inst = this._getInst(target[0]); 4742 4743 dateStr = (dateStr != null ? dateStr : this._formatDate(inst)); 4744 if (inst.input) { 4745 inst.input.val(dateStr); 4746 } 4747 this._updateAlternate(inst); 4748 4749 onSelect = this._get(inst, "onSelect"); 4750 if (onSelect) { 4751 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback 4752 } else if (inst.input) { 4753 inst.input.trigger("change"); // fire the change event 4754 } 4755 4756 if (inst.inline){ 4757 this._updateDatepicker(inst); 4758 } else { 4759 this._hideDatepicker(); 4760 this._lastInput = inst.input[0]; 4761 if (typeof(inst.input[0]) !== "object") { 4762 inst.input.focus(); // restore focus 4763 } 4764 this._lastInput = null; 4765 } 4766 }, 4767 4768 /* Update any alternate field to synchronise with the main field. */ 4769 _updateAlternate: function(inst) { 4770 var altFormat, date, dateStr, 4771 altField = this._get(inst, "altField"); 4772 4773 if (altField) { // update alternate field too 4774 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat"); 4775 date = this._getDate(inst); 4776 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst)); 4777 $(altField).each(function() { $(this).val(dateStr); }); 4778 } 4779 }, 4780 4781 /* Set as beforeShowDay function to prevent selection of weekends. 4782 * @param date Date - the date to customise 4783 * @return [boolean, string] - is this date selectable?, what is its CSS class? 4784 */ 4785 noWeekends: function(date) { 4786 var day = date.getDay(); 4787 return [(day > 0 && day < 6), ""]; 4788 }, 4789 4790 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition. 4791 * @param date Date - the date to get the week for 4792 * @return number - the number of the week within the year that contains this date 4793 */ 4794 iso8601Week: function(date) { 4795 var time, 4796 checkDate = new Date(date.getTime()); 4797 4798 // Find Thursday of this week starting on Monday 4799 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7)); 4800 4801 time = checkDate.getTime(); 4802 checkDate.setMonth(0); // Compare with Jan 1 4803 checkDate.setDate(1); 4804 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1; 4805 }, 4806 4807 /* Parse a string value into a date object. 4808 * See formatDate below for the possible formats. 4809 * 4810 * @param format string - the expected format of the date 4811 * @param value string - the date in the above format 4812 * @param settings Object - attributes include: 4813 * shortYearCutoff number - the cutoff year for determining the century (optional) 4814 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 4815 * dayNames string[7] - names of the days from Sunday (optional) 4816 * monthNamesShort string[12] - abbreviated names of the months (optional) 4817 * monthNames string[12] - names of the months (optional) 4818 * @return Date - the extracted date value or null if value is blank 4819 */ 4820 parseDate: function (format, value, settings) { 4821 if (format == null || value == null) { 4822 throw "Invalid arguments"; 4823 } 4824 4825 value = (typeof value === "object" ? value.toString() : value + ""); 4826 if (value === "") { 4827 return null; 4828 } 4829 4830 var iFormat, dim, extra, 4831 iValue = 0, 4832 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff, 4833 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp : 4834 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)), 4835 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, 4836 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, 4837 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, 4838 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, 4839 year = -1, 4840 month = -1, 4841 day = -1, 4842 doy = -1, 4843 literal = false, 4844 date, 4845 // Check whether a format character is doubled 4846 lookAhead = function(match) { 4847 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); 4848 if (matches) { 4849 iFormat++; 4850 } 4851 return matches; 4852 }, 4853 // Extract a number from the string value 4854 getNumber = function(match) { 4855 var isDoubled = lookAhead(match), 4856 size = (match === "@" ? 14 : (match === "!" ? 20 : 4857 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))), 4858 minSize = (match === "y" ? size : 1), 4859 digits = new RegExp("^\\d{" + minSize + "," + size + "}"), 4860 num = value.substring(iValue).match(digits); 4861 if (!num) { 4862 throw "Missing number at position " + iValue; 4863 } 4864 iValue += num[0].length; 4865 return parseInt(num[0], 10); 4866 }, 4867 // Extract a name from the string value and convert to an index 4868 getName = function(match, shortNames, longNames) { 4869 var index = -1, 4870 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) { 4871 return [ [k, v] ]; 4872 }).sort(function (a, b) { 4873 return -(a[1].length - b[1].length); 4874 }); 4875 4876 $.each(names, function (i, pair) { 4877 var name = pair[1]; 4878 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) { 4879 index = pair[0]; 4880 iValue += name.length; 4881 return false; 4882 } 4883 }); 4884 if (index !== -1) { 4885 return index + 1; 4886 } else { 4887 throw "Unknown name at position " + iValue; 4888 } 4889 }, 4890 // Confirm that a literal character matches the string value 4891 checkLiteral = function() { 4892 if (value.charAt(iValue) !== format.charAt(iFormat)) { 4893 throw "Unexpected literal at position " + iValue; 4894 } 4895 iValue++; 4896 }; 4897 4898 for (iFormat = 0; iFormat < format.length; iFormat++) { 4899 if (literal) { 4900 if (format.charAt(iFormat) === "'" && !lookAhead("'")) { 4901 literal = false; 4902 } else { 4903 checkLiteral(); 4904 } 4905 } else { 4906 switch (format.charAt(iFormat)) { 4907 case "d": 4908 day = getNumber("d"); 4909 break; 4910 case "D": 4911 getName("D", dayNamesShort, dayNames); 4912 break; 4913 case "o": 4914 doy = getNumber("o"); 4915 break; 4916 case "m": 4917 month = getNumber("m"); 4918 break; 4919 case "M": 4920 month = getName("M", monthNamesShort, monthNames); 4921 break; 4922 case "y": 4923 year = getNumber("y"); 4924 break; 4925 case "@": 4926 date = new Date(getNumber("@")); 4927 year = date.getFullYear(); 4928 month = date.getMonth() + 1; 4929 day = date.getDate(); 4930 break; 4931 case "!": 4932 date = new Date((getNumber("!") - this._ticksTo1970) / 10000); 4933 year = date.getFullYear(); 4934 month = date.getMonth() + 1; 4935 day = date.getDate(); 4936 break; 4937 case "'": 4938 if (lookAhead("'")){ 4939 checkLiteral(); 4940 } else { 4941 literal = true; 4942 } 4943 break; 4944 default: 4945 checkLiteral(); 4946 } 4947 } 4948 } 4949 4950 if (iValue < value.length){ 4951 extra = value.substr(iValue); 4952 if (!/^\s+/.test(extra)) { 4953 throw "Extra/unparsed characters found in date: " + extra; 4954 } 4955 } 4956 4957 if (year === -1) { 4958 year = new Date().getFullYear(); 4959 } else if (year < 100) { 4960 year += new Date().getFullYear() - new Date().getFullYear() % 100 + 4961 (year <= shortYearCutoff ? 0 : -100); 4962 } 4963 4964 if (doy > -1) { 4965 month = 1; 4966 day = doy; 4967 do { 4968 dim = this._getDaysInMonth(year, month - 1); 4969 if (day <= dim) { 4970 break; 4971 } 4972 month++; 4973 day -= dim; 4974 } while (true); 4975 } 4976 4977 date = this._daylightSavingAdjust(new Date(year, month - 1, day)); 4978 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { 4979 throw "Invalid date"; // E.g. 31/02/00 4980 } 4981 return date; 4982 }, 4983 4984 /* Standard date formats. */ 4985 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601) 4986 COOKIE: "D, dd M yy", 4987 ISO_8601: "yy-mm-dd", 4988 RFC_822: "D, d M y", 4989 RFC_850: "DD, dd-M-y", 4990 RFC_1036: "D, d M y", 4991 RFC_1123: "D, d M yy", 4992 RFC_2822: "D, d M yy", 4993 RSS: "D, d M y", // RFC 822 4994 TICKS: "!", 4995 TIMESTAMP: "@", 4996 W3C: "yy-mm-dd", // ISO 8601 4997 4998 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) + 4999 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000), 5000 5001 /* Format a date object into a string value. 5002 * The format can be combinations of the following: 5003 * d - day of month (no leading zero) 5004 * dd - day of month (two digit) 5005 * o - day of year (no leading zeros) 5006 * oo - day of year (three digit) 5007 * D - day name short 5008 * DD - day name long 5009 * m - month of year (no leading zero) 5010 * mm - month of year (two digit) 5011 * M - month name short 5012 * MM - month name long 5013 * y - year (two digit) 5014 * yy - year (four digit) 5015 * @ - Unix timestamp (ms since 01/01/1970) 5016 * ! - Windows ticks (100ns since 01/01/0001) 5017 * "..." - literal text 5018 * '' - single quote 5019 * 5020 * @param format string - the desired format of the date 5021 * @param date Date - the date value to format 5022 * @param settings Object - attributes include: 5023 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional) 5024 * dayNames string[7] - names of the days from Sunday (optional) 5025 * monthNamesShort string[12] - abbreviated names of the months (optional) 5026 * monthNames string[12] - names of the months (optional) 5027 * @return string - the date in the above format 5028 */ 5029 formatDate: function (format, date, settings) { 5030 if (!date) { 5031 return ""; 5032 } 5033 5034 var iFormat, 5035 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort, 5036 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames, 5037 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort, 5038 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames, 5039 // Check whether a format character is doubled 5040 lookAhead = function(match) { 5041 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); 5042 if (matches) { 5043 iFormat++; 5044 } 5045 return matches; 5046 }, 5047 // Format a number, with leading zero if necessary 5048 formatNumber = function(match, value, len) { 5049 var num = "" + value; 5050 if (lookAhead(match)) { 5051 while (num.length < len) { 5052 num = "0" + num; 5053 } 5054 } 5055 return num; 5056 }, 5057 // Format a name, short or long as requested 5058 formatName = function(match, value, shortNames, longNames) { 5059 return (lookAhead(match) ? longNames[value] : shortNames[value]); 5060 }, 5061 output = "", 5062 literal = false; 5063 5064 if (date) { 5065 for (iFormat = 0; iFormat < format.length; iFormat++) { 5066 if (literal) { 5067 if (format.charAt(iFormat) === "'" && !lookAhead("'")) { 5068 literal = false; 5069 } else { 5070 output += format.charAt(iFormat); 5071 } 5072 } else { 5073 switch (format.charAt(iFormat)) { 5074 case "d": 5075 output += formatNumber("d", date.getDate(), 2); 5076 break; 5077 case "D": 5078 output += formatName("D", date.getDay(), dayNamesShort, dayNames); 5079 break; 5080 case "o": 5081 output += formatNumber("o", 5082 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3); 5083 break; 5084 case "m": 5085 output += formatNumber("m", date.getMonth() + 1, 2); 5086 break; 5087 case "M": 5088 output += formatName("M", date.getMonth(), monthNamesShort, monthNames); 5089 break; 5090 case "y": 5091 output += (lookAhead("y") ? date.getFullYear() : 5092 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100); 5093 break; 5094 case "@": 5095 output += date.getTime(); 5096 break; 5097 case "!": 5098 output += date.getTime() * 10000 + this._ticksTo1970; 5099 break; 5100 case "'": 5101 if (lookAhead("'")) { 5102 output += "'"; 5103 } else { 5104 literal = true; 5105 } 5106 break; 5107 default: 5108 output += format.charAt(iFormat); 5109 } 5110 } 5111 } 5112 } 5113 return output; 5114 }, 5115 5116 /* Extract all possible characters from the date format. */ 5117 _possibleChars: function (format) { 5118 var iFormat, 5119 chars = "", 5120 literal = false, 5121 // Check whether a format character is doubled 5122 lookAhead = function(match) { 5123 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match); 5124 if (matches) { 5125 iFormat++; 5126 } 5127 return matches; 5128 }; 5129 5130 for (iFormat = 0; iFormat < format.length; iFormat++) { 5131 if (literal) { 5132 if (format.charAt(iFormat) === "'" && !lookAhead("'")) { 5133 literal = false; 5134 } else { 5135 chars += format.charAt(iFormat); 5136 } 5137 } else { 5138 switch (format.charAt(iFormat)) { 5139 case "d": case "m": case "y": case "@": 5140 chars += "0123456789"; 5141 break; 5142 case "D": case "M": 5143 return null; // Accept anything 5144 case "'": 5145 if (lookAhead("'")) { 5146 chars += "'"; 5147 } else { 5148 literal = true; 5149 } 5150 break; 5151 default: 5152 chars += format.charAt(iFormat); 5153 } 5154 } 5155 } 5156 return chars; 5157 }, 5158 5159 /* Get a setting value, defaulting if necessary. */ 5160 _get: function(inst, name) { 5161 return inst.settings[name] !== undefined ? 5162 inst.settings[name] : this._defaults[name]; 5163 }, 5164 5165 /* Parse existing date and initialise date picker. */ 5166 _setDateFromField: function(inst, noDefault) { 5167 if (inst.input.val() === inst.lastVal) { 5168 return; 5169 } 5170 5171 var dateFormat = this._get(inst, "dateFormat"), 5172 dates = inst.lastVal = inst.input ? inst.input.val() : null, 5173 defaultDate = this._getDefaultDate(inst), 5174 date = defaultDate, 5175 settings = this._getFormatConfig(inst); 5176 5177 try { 5178 date = this.parseDate(dateFormat, dates, settings) || defaultDate; 5179 } catch (event) { 5180 dates = (noDefault ? "" : dates); 5181 } 5182 inst.selectedDay = date.getDate(); 5183 inst.drawMonth = inst.selectedMonth = date.getMonth(); 5184 inst.drawYear = inst.selectedYear = date.getFullYear(); 5185 inst.currentDay = (dates ? date.getDate() : 0); 5186 inst.currentMonth = (dates ? date.getMonth() : 0); 5187 inst.currentYear = (dates ? date.getFullYear() : 0); 5188 this._adjustInstDate(inst); 5189 }, 5190 5191 /* Retrieve the default date shown on opening. */ 5192 _getDefaultDate: function(inst) { 5193 return this._restrictMinMax(inst, 5194 this._determineDate(inst, this._get(inst, "defaultDate"), new Date())); 5195 }, 5196 5197 /* A date may be specified as an exact value or a relative one. */ 5198 _determineDate: function(inst, date, defaultDate) { 5199 var offsetNumeric = function(offset) { 5200 var date = new Date(); 5201 date.setDate(date.getDate() + offset); 5202 return date; 5203 }, 5204 offsetString = function(offset) { 5205 try { 5206 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"), 5207 offset, $.datepicker._getFormatConfig(inst)); 5208 } 5209 catch (e) { 5210 // Ignore 5211 } 5212 5213 var date = (offset.toLowerCase().match(/^c/) ? 5214 $.datepicker._getDate(inst) : null) || new Date(), 5215 year = date.getFullYear(), 5216 month = date.getMonth(), 5217 day = date.getDate(), 5218 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g, 5219 matches = pattern.exec(offset); 5220 5221 while (matches) { 5222 switch (matches[2] || "d") { 5223 case "d" : case "D" : 5224 day += parseInt(matches[1],10); break; 5225 case "w" : case "W" : 5226 day += parseInt(matches[1],10) * 7; break; 5227 case "m" : case "M" : 5228 month += parseInt(matches[1],10); 5229 day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); 5230 break; 5231 case "y": case "Y" : 5232 year += parseInt(matches[1],10); 5233 day = Math.min(day, $.datepicker._getDaysInMonth(year, month)); 5234 break; 5235 } 5236 matches = pattern.exec(offset); 5237 } 5238 return new Date(year, month, day); 5239 }, 5240 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) : 5241 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime())))); 5242 5243 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate); 5244 if (newDate) { 5245 newDate.setHours(0); 5246 newDate.setMinutes(0); 5247 newDate.setSeconds(0); 5248 newDate.setMilliseconds(0); 5249 } 5250 return this._daylightSavingAdjust(newDate); 5251 }, 5252 5253 /* Handle switch to/from daylight saving. 5254 * Hours may be non-zero on daylight saving cut-over: 5255 * > 12 when midnight changeover, but then cannot generate 5256 * midnight datetime, so jump to 1AM, otherwise reset. 5257 * @param date (Date) the date to check 5258 * @return (Date) the corrected date 5259 */ 5260 _daylightSavingAdjust: function(date) { 5261 if (!date) { 5262 return null; 5263 } 5264 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0); 5265 return date; 5266 }, 5267 5268 /* Set the date(s) directly. */ 5269 _setDate: function(inst, date, noChange) { 5270 var clear = !date, 5271 origMonth = inst.selectedMonth, 5272 origYear = inst.selectedYear, 5273 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date())); 5274 5275 inst.selectedDay = inst.currentDay = newDate.getDate(); 5276 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth(); 5277 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear(); 5278 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) { 5279 this._notifyChange(inst); 5280 } 5281 this._adjustInstDate(inst); 5282 if (inst.input) { 5283 inst.input.val(clear ? "" : this._formatDate(inst)); 5284 } 5285 }, 5286 5287 /* Retrieve the date(s) directly. */ 5288 _getDate: function(inst) { 5289 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null : 5290 this._daylightSavingAdjust(new Date( 5291 inst.currentYear, inst.currentMonth, inst.currentDay))); 5292 return startDate; 5293 }, 5294 5295 /* Attach the onxxx handlers. These are declared statically so 5296 * they work with static code transformers like Caja. 5297 */ 5298 _attachHandlers: function(inst) { 5299 var stepMonths = this._get(inst, "stepMonths"), 5300 id = "#" + inst.id.replace( /\\\\/g, "\\" ); 5301 inst.dpDiv.find("[data-handler]").map(function () { 5302 var handler = { 5303 prev: function () { 5304 $.datepicker._adjustDate(id, -stepMonths, "M"); 5305 }, 5306 next: function () { 5307 $.datepicker._adjustDate(id, +stepMonths, "M"); 5308 }, 5309 hide: function () { 5310 $.datepicker._hideDatepicker(); 5311 }, 5312 today: function () { 5313 $.datepicker._gotoToday(id); 5314 }, 5315 selectDay: function () { 5316 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this); 5317 return false; 5318 }, 5319 selectMonth: function () { 5320 $.datepicker._selectMonthYear(id, this, "M"); 5321 return false; 5322 }, 5323 selectYear: function () { 5324 $.datepicker._selectMonthYear(id, this, "Y"); 5325 return false; 5326 } 5327 }; 5328 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]); 5329 }); 5330 }, 5331 5332 /* Generate the HTML for the current state of the date picker. */ 5333 _generateHTML: function(inst) { 5334 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate, 5335 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin, 5336 monthNames, monthNamesShort, beforeShowDay, showOtherMonths, 5337 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate, 5338 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows, 5339 printDate, dRow, tbody, daySettings, otherMonth, unselectable, 5340 tempDate = new Date(), 5341 today = this._daylightSavingAdjust( 5342 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time 5343 isRTL = this._get(inst, "isRTL"), 5344 showButtonPanel = this._get(inst, "showButtonPanel"), 5345 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"), 5346 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"), 5347 numMonths = this._getNumberOfMonths(inst), 5348 showCurrentAtPos = this._get(inst, "showCurrentAtPos"), 5349 stepMonths = this._get(inst, "stepMonths"), 5350 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1), 5351 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) : 5352 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))), 5353 minDate = this._getMinMaxDate(inst, "min"), 5354 maxDate = this._getMinMaxDate(inst, "max"), 5355 drawMonth = inst.drawMonth - showCurrentAtPos, 5356 drawYear = inst.drawYear; 5357 5358 if (drawMonth < 0) { 5359 drawMonth += 12; 5360 drawYear--; 5361 } 5362 if (maxDate) { 5363 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(), 5364 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate())); 5365 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw); 5366 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) { 5367 drawMonth--; 5368 if (drawMonth < 0) { 5369 drawMonth = 11; 5370 drawYear--; 5371 } 5372 } 5373 } 5374 inst.drawMonth = drawMonth; 5375 inst.drawYear = drawYear; 5376 5377 prevText = this._get(inst, "prevText"); 5378 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText, 5379 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)), 5380 this._getFormatConfig(inst))); 5381 5382 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ? 5383 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" + 5384 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" : 5385 (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>")); 5386 5387 nextText = this._get(inst, "nextText"); 5388 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText, 5389 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)), 5390 this._getFormatConfig(inst))); 5391 5392 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ? 5393 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" + 5394 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" : 5395 (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>")); 5396 5397 currentText = this._get(inst, "currentText"); 5398 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today); 5399 currentText = (!navigationAsDateFormat ? currentText : 5400 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst))); 5401 5402 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'>" + 5403 this._get(inst, "closeText") + "</button>" : ""); 5404 5405 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") + 5406 (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'" + 5407 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : ""; 5408 5409 firstDay = parseInt(this._get(inst, "firstDay"),10); 5410 firstDay = (isNaN(firstDay) ? 0 : firstDay); 5411 5412 showWeek = this._get(inst, "showWeek"); 5413 dayNames = this._get(inst, "dayNames"); 5414 dayNamesMin = this._get(inst, "dayNamesMin"); 5415 monthNames = this._get(inst, "monthNames"); 5416 monthNamesShort = this._get(inst, "monthNamesShort"); 5417 beforeShowDay = this._get(inst, "beforeShowDay"); 5418 showOtherMonths = this._get(inst, "showOtherMonths"); 5419 selectOtherMonths = this._get(inst, "selectOtherMonths"); 5420 defaultDate = this._getDefaultDate(inst); 5421 html = ""; 5422 dow; 5423 for (row = 0; row < numMonths[0]; row++) { 5424 group = ""; 5425 this.maxRows = 4; 5426 for (col = 0; col < numMonths[1]; col++) { 5427 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay)); 5428 cornerClass = " ui-corner-all"; 5429 calender = ""; 5430 if (isMultiMonth) { 5431 calender += "<div class='ui-datepicker-group"; 5432 if (numMonths[1] > 1) { 5433 switch (col) { 5434 case 0: calender += " ui-datepicker-group-first"; 5435 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break; 5436 case numMonths[1]-1: calender += " ui-datepicker-group-last"; 5437 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break; 5438 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break; 5439 } 5440 } 5441 calender += "'>"; 5442 } 5443 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" + 5444 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") + 5445 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") + 5446 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate, 5447 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers 5448 "</div><table class='ui-datepicker-calendar'><thead>" + 5449 "<tr>"; 5450 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : ""); 5451 for (dow = 0; dow < 7; dow++) { // days of the week 5452 day = (dow + firstDay) % 7; 5453 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" + 5454 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>"; 5455 } 5456 calender += thead + "</tr></thead><tbody>"; 5457 daysInMonth = this._getDaysInMonth(drawYear, drawMonth); 5458 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) { 5459 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth); 5460 } 5461 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7; 5462 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate 5463 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043) 5464 this.maxRows = numRows; 5465 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays)); 5466 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows 5467 calender += "<tr>"; 5468 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" + 5469 this._get(inst, "calculateWeek")(printDate) + "</td>"); 5470 for (dow = 0; dow < 7; dow++) { // create date picker days 5471 daySettings = (beforeShowDay ? 5472 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]); 5473 otherMonth = (printDate.getMonth() !== drawMonth); 5474 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] || 5475 (minDate && printDate < minDate) || (maxDate && printDate > maxDate); 5476 tbody += "<td class='" + 5477 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends 5478 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months 5479 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key 5480 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ? 5481 // or defaultDate is current printedDate and defaultDate is selectedDate 5482 " " + this._dayOverClass : "") + // highlight selected day 5483 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days 5484 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates 5485 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day 5486 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different) 5487 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "'") + "'" : "") + // cell title 5488 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions 5489 (otherMonth && !showOtherMonths ? " " : // display for other months 5490 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" + 5491 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") + 5492 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day 5493 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months 5494 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date 5495 printDate.setDate(printDate.getDate() + 1); 5496 printDate = this._daylightSavingAdjust(printDate); 5497 } 5498 calender += tbody + "</tr>"; 5499 } 5500 drawMonth++; 5501 if (drawMonth > 11) { 5502 drawMonth = 0; 5503 drawYear++; 5504 } 5505 calender += "</tbody></table>" + (isMultiMonth ? "</div>" + 5506 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : ""); 5507 group += calender; 5508 } 5509 html += group; 5510 } 5511 html += buttonPanel; 5512 inst._keyEvent = false; 5513 return html; 5514 }, 5515 5516 /* Generate the month and year header. */ 5517 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate, 5518 secondary, monthNames, monthNamesShort) { 5519 5520 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear, 5521 changeMonth = this._get(inst, "changeMonth"), 5522 changeYear = this._get(inst, "changeYear"), 5523 showMonthAfterYear = this._get(inst, "showMonthAfterYear"), 5524 html = "<div class='ui-datepicker-title'>", 5525 monthHtml = ""; 5526 5527 // month selection 5528 if (secondary || !changeMonth) { 5529 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>"; 5530 } else { 5531 inMinYear = (minDate && minDate.getFullYear() === drawYear); 5532 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear); 5533 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>"; 5534 for ( month = 0; month < 12; month++) { 5535 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) { 5536 monthHtml += "<option value='" + month + "'" + 5537 (month === drawMonth ? " selected='selected'" : "") + 5538 ">" + monthNamesShort[month] + "</option>"; 5539 } 5540 } 5541 monthHtml += "</select>"; 5542 } 5543 5544 if (!showMonthAfterYear) { 5545 html += monthHtml + (secondary || !(changeMonth && changeYear) ? " " : ""); 5546 } 5547 5548 // year selection 5549 if ( !inst.yearshtml ) { 5550 inst.yearshtml = ""; 5551 if (secondary || !changeYear) { 5552 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>"; 5553 } else { 5554 // determine range of years to display 5555 years = this._get(inst, "yearRange").split(":"); 5556 thisYear = new Date().getFullYear(); 5557 determineYear = function(value) { 5558 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) : 5559 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) : 5560 parseInt(value, 10))); 5561 return (isNaN(year) ? thisYear : year); 5562 }; 5563 year = determineYear(years[0]); 5564 endYear = Math.max(year, determineYear(years[1] || "")); 5565 year = (minDate ? Math.max(year, minDate.getFullYear()) : year); 5566 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear); 5567 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>"; 5568 for (; year <= endYear; year++) { 5569 inst.yearshtml += "<option value='" + year + "'" + 5570 (year === drawYear ? " selected='selected'" : "") + 5571 ">" + year + "</option>"; 5572 } 5573 inst.yearshtml += "</select>"; 5574 5575 html += inst.yearshtml; 5576 inst.yearshtml = null; 5577 } 5578 } 5579 5580 html += this._get(inst, "yearSuffix"); 5581 if (showMonthAfterYear) { 5582 html += (secondary || !(changeMonth && changeYear) ? " " : "") + monthHtml; 5583 } 5584 html += "</div>"; // Close datepicker_header 5585 return html; 5586 }, 5587 5588 /* Adjust one of the date sub-fields. */ 5589 _adjustInstDate: function(inst, offset, period) { 5590 var year = inst.drawYear + (period === "Y" ? offset : 0), 5591 month = inst.drawMonth + (period === "M" ? offset : 0), 5592 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0), 5593 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day))); 5594 5595 inst.selectedDay = date.getDate(); 5596 inst.drawMonth = inst.selectedMonth = date.getMonth(); 5597 inst.drawYear = inst.selectedYear = date.getFullYear(); 5598 if (period === "M" || period === "Y") { 5599 this._notifyChange(inst); 5600 } 5601 }, 5602 5603 /* Ensure a date is within any min/max bounds. */ 5604 _restrictMinMax: function(inst, date) { 5605 var minDate = this._getMinMaxDate(inst, "min"), 5606 maxDate = this._getMinMaxDate(inst, "max"), 5607 newDate = (minDate && date < minDate ? minDate : date); 5608 return (maxDate && newDate > maxDate ? maxDate : newDate); 5609 }, 5610 5611 /* Notify change of month/year. */ 5612 _notifyChange: function(inst) { 5613 var onChange = this._get(inst, "onChangeMonthYear"); 5614 if (onChange) { 5615 onChange.apply((inst.input ? inst.input[0] : null), 5616 [inst.selectedYear, inst.selectedMonth + 1, inst]); 5617 } 5618 }, 5619 5620 /* Determine the number of months to show. */ 5621 _getNumberOfMonths: function(inst) { 5622 var numMonths = this._get(inst, "numberOfMonths"); 5623 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths)); 5624 }, 5625 5626 /* Determine the current maximum date - ensure no time components are set. */ 5627 _getMinMaxDate: function(inst, minMax) { 5628 return this._determineDate(inst, this._get(inst, minMax + "Date"), null); 5629 }, 5630 5631 /* Find the number of days in a given month. */ 5632 _getDaysInMonth: function(year, month) { 5633 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate(); 5634 }, 5635 5636 /* Find the day of the week of the first of a month. */ 5637 _getFirstDayOfMonth: function(year, month) { 5638 return new Date(year, month, 1).getDay(); 5639 }, 5640 5641 /* Determines if we should allow a "next/prev" month display change. */ 5642 _canAdjustMonth: function(inst, offset, curYear, curMonth) { 5643 var numMonths = this._getNumberOfMonths(inst), 5644 date = this._daylightSavingAdjust(new Date(curYear, 5645 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1)); 5646 5647 if (offset < 0) { 5648 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth())); 5649 } 5650 return this._isInRange(inst, date); 5651 }, 5652 5653 /* Is the given date in the accepted range? */ 5654 _isInRange: function(inst, date) { 5655 var yearSplit, currentYear, 5656 minDate = this._getMinMaxDate(inst, "min"), 5657 maxDate = this._getMinMaxDate(inst, "max"), 5658 minYear = null, 5659 maxYear = null, 5660 years = this._get(inst, "yearRange"); 5661 if (years){ 5662 yearSplit = years.split(":"); 5663 currentYear = new Date().getFullYear(); 5664 minYear = parseInt(yearSplit[0], 10); 5665 maxYear = parseInt(yearSplit[1], 10); 5666 if ( yearSplit[0].match(/[+\-].*/) ) { 5667 minYear += currentYear; 5668 } 5669 if ( yearSplit[1].match(/[+\-].*/) ) { 5670 maxYear += currentYear; 5671 } 5672 } 5673 5674 return ((!minDate || date.getTime() >= minDate.getTime()) && 5675 (!maxDate || date.getTime() <= maxDate.getTime()) && 5676 (!minYear || date.getFullYear() >= minYear) && 5677 (!maxYear || date.getFullYear() <= maxYear)); 5678 }, 5679 5680 /* Provide the configuration settings for formatting/parsing. */ 5681 _getFormatConfig: function(inst) { 5682 var shortYearCutoff = this._get(inst, "shortYearCutoff"); 5683 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff : 5684 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10)); 5685 return {shortYearCutoff: shortYearCutoff, 5686 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"), 5687 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")}; 5688 }, 5689 5690 /* Format the given date for display. */ 5691 _formatDate: function(inst, day, month, year) { 5692 if (!day) { 5693 inst.currentDay = inst.selectedDay; 5694 inst.currentMonth = inst.selectedMonth; 5695 inst.currentYear = inst.selectedYear; 5696 } 5697 var date = (day ? (typeof day === "object" ? day : 5698 this._daylightSavingAdjust(new Date(year, month, day))) : 5699 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay))); 5700 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst)); 5701 } 5702 }); 5703 5704 /* 5705 * Bind hover events for datepicker elements. 5706 * Done via delegate so the binding only occurs once in the lifetime of the parent div. 5707 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker. 5708 */ 5709 function datepicker_bindHover(dpDiv) { 5710 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a"; 5711 return dpDiv.delegate(selector, "mouseout", function() { 5712 $(this).removeClass("ui-state-hover"); 5713 if (this.className.indexOf("ui-datepicker-prev") !== -1) { 5714 $(this).removeClass("ui-datepicker-prev-hover"); 5715 } 5716 if (this.className.indexOf("ui-datepicker-next") !== -1) { 5717 $(this).removeClass("ui-datepicker-next-hover"); 5718 } 5719 }) 5720 .delegate( selector, "mouseover", datepicker_handleMouseover ); 5721 } 5722 5723 function datepicker_handleMouseover() { 5724 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) { 5725 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"); 5726 $(this).addClass("ui-state-hover"); 5727 if (this.className.indexOf("ui-datepicker-prev") !== -1) { 5728 $(this).addClass("ui-datepicker-prev-hover"); 5729 } 5730 if (this.className.indexOf("ui-datepicker-next") !== -1) { 5731 $(this).addClass("ui-datepicker-next-hover"); 5732 } 5733 } 5734 } 5735 5736 /* jQuery extend now ignores nulls! */ 5737 function datepicker_extendRemove(target, props) { 5738 $.extend(target, props); 5739 for (var name in props) { 5740 if (props[name] == null) { 5741 target[name] = props[name]; 5742 } 5743 } 5744 return target; 5745 } 5746 5747 /* Invoke the datepicker functionality. 5748 @param options string - a command, optionally followed by additional parameters or 5749 Object - settings for attaching new datepicker functionality 5750 @return jQuery object */ 5751 $.fn.datepicker = function(options){ 5752 5753 /* Verify an empty collection wasn't passed - Fixes #6976 */ 5754 if ( !this.length ) { 5755 return this; 5756 } 5757 5758 /* Initialise the date picker. */ 5759 if (!$.datepicker.initialized) { 5760 $(document).mousedown($.datepicker._checkExternalClick); 5761 $.datepicker.initialized = true; 5762 } 5763 5764 /* Append datepicker main container to body if not exist. */ 5765 if ($("#"+$.datepicker._mainDivId).length === 0) { 5766 $("body").append($.datepicker.dpDiv); 5767 } 5768 5769 var otherArgs = Array.prototype.slice.call(arguments, 1); 5770 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) { 5771 return $.datepicker["_" + options + "Datepicker"]. 5772 apply($.datepicker, [this[0]].concat(otherArgs)); 5773 } 5774 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") { 5775 return $.datepicker["_" + options + "Datepicker"]. 5776 apply($.datepicker, [this[0]].concat(otherArgs)); 5777 } 5778 return this.each(function() { 5779 typeof options === "string" ? 5780 $.datepicker["_" + options + "Datepicker"]. 5781 apply($.datepicker, [this].concat(otherArgs)) : 5782 $.datepicker._attachDatepicker(this, options); 5783 }); 5784 }; 5785 5786 $.datepicker = new Datepicker(); // singleton instance 5787 $.datepicker.initialized = false; 5788 $.datepicker.uuid = new Date().getTime(); 5789 $.datepicker.version = "1.11.1"; 5790 5791 var datepicker = $.datepicker; 5792 5793 5794 /*! 5795 * jQuery UI Draggable 1.11.1 5796 * http://jqueryui.com 5797 * 5798 * Copyright 2014 jQuery Foundation and other contributors 5799 * Released under the MIT license. 5800 * http://jquery.org/license 5801 * 5802 * http://api.jqueryui.com/draggable/ 5803 */ 5804 5805 5806 $.widget("ui.draggable", $.ui.mouse, { 5807 version: "1.11.1", 5808 widgetEventPrefix: "drag", 5809 options: { 5810 addClasses: true, 5811 appendTo: "parent", 5812 axis: false, 5813 connectToSortable: false, 5814 containment: false, 5815 cursor: "auto", 5816 cursorAt: false, 5817 grid: false, 5818 handle: false, 5819 helper: "original", 5820 iframeFix: false, 5821 opacity: false, 5822 refreshPositions: false, 5823 revert: false, 5824 revertDuration: 500, 5825 scope: "default", 5826 scroll: true, 5827 scrollSensitivity: 20, 5828 scrollSpeed: 20, 5829 snap: false, 5830 snapMode: "both", 5831 snapTolerance: 20, 5832 stack: false, 5833 zIndex: false, 5834 5835 // callbacks 5836 drag: null, 5837 start: null, 5838 stop: null 5839 }, 5840 _create: function() { 5841 5842 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { 5843 this.element[0].style.position = "relative"; 5844 } 5845 if (this.options.addClasses){ 5846 this.element.addClass("ui-draggable"); 5847 } 5848 if (this.options.disabled){ 5849 this.element.addClass("ui-draggable-disabled"); 5850 } 5851 this._setHandleClassName(); 5852 5853 this._mouseInit(); 5854 }, 5855 5856 _setOption: function( key, value ) { 5857 this._super( key, value ); 5858 if ( key === "handle" ) { 5859 this._removeHandleClassName(); 5860 this._setHandleClassName(); 5861 } 5862 }, 5863 5864 _destroy: function() { 5865 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) { 5866 this.destroyOnClear = true; 5867 return; 5868 } 5869 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); 5870 this._removeHandleClassName(); 5871 this._mouseDestroy(); 5872 }, 5873 5874 _mouseCapture: function(event) { 5875 5876 var document = this.document[ 0 ], 5877 o = this.options; 5878 5879 // support: IE9 5880 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 5881 try { 5882 // Support: IE9+ 5883 // If the <body> is blurred, IE will switch windows, see #9520 5884 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) { 5885 // Blur any element that currently has focus, see #4261 5886 $( document.activeElement ).blur(); 5887 } 5888 } catch ( error ) {} 5889 5890 // among others, prevent a drag on a resizable-handle 5891 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { 5892 return false; 5893 } 5894 5895 //Quit if we're not on a valid handle 5896 this.handle = this._getHandle(event); 5897 if (!this.handle) { 5898 return false; 5899 } 5900 5901 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { 5902 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>") 5903 .css({ 5904 width: this.offsetWidth + "px", height: this.offsetHeight + "px", 5905 position: "absolute", opacity: "0.001", zIndex: 1000 5906 }) 5907 .css($(this).offset()) 5908 .appendTo("body"); 5909 }); 5910 5911 return true; 5912 5913 }, 5914 5915 _mouseStart: function(event) { 5916 5917 var o = this.options; 5918 5919 //Create and append the visible helper 5920 this.helper = this._createHelper(event); 5921 5922 this.helper.addClass("ui-draggable-dragging"); 5923 5924 //Cache the helper size 5925 this._cacheHelperProportions(); 5926 5927 //If ddmanager is used for droppables, set the global draggable 5928 if ($.ui.ddmanager) { 5929 $.ui.ddmanager.current = this; 5930 } 5931 5932 /* 5933 * - Position generation - 5934 * This block generates everything position related - it's the core of draggables. 5935 */ 5936 5937 //Cache the margins of the original element 5938 this._cacheMargins(); 5939 5940 //Store the helper's css position 5941 this.cssPosition = this.helper.css( "position" ); 5942 this.scrollParent = this.helper.scrollParent( true ); 5943 this.offsetParent = this.helper.offsetParent(); 5944 this.offsetParentCssPosition = this.offsetParent.css( "position" ); 5945 5946 //The element's absolute position on the page minus margins 5947 this.offset = this.positionAbs = this.element.offset(); 5948 this.offset = { 5949 top: this.offset.top - this.margins.top, 5950 left: this.offset.left - this.margins.left 5951 }; 5952 5953 //Reset scroll cache 5954 this.offset.scroll = false; 5955 5956 $.extend(this.offset, { 5957 click: { //Where the click happened, relative to the element 5958 left: event.pageX - this.offset.left, 5959 top: event.pageY - this.offset.top 5960 }, 5961 parent: this._getParentOffset(), 5962 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper 5963 }); 5964 5965 //Generate the original position 5966 this.originalPosition = this.position = this._generatePosition( event, false ); 5967 this.originalPageX = event.pageX; 5968 this.originalPageY = event.pageY; 5969 5970 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 5971 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); 5972 5973 //Set a containment if given in the options 5974 this._setContainment(); 5975 5976 //Trigger event + callbacks 5977 if (this._trigger("start", event) === false) { 5978 this._clear(); 5979 return false; 5980 } 5981 5982 //Recache the helper size 5983 this._cacheHelperProportions(); 5984 5985 //Prepare the droppable offsets 5986 if ($.ui.ddmanager && !o.dropBehaviour) { 5987 $.ui.ddmanager.prepareOffsets(this, event); 5988 } 5989 5990 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position 5991 5992 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) 5993 if ( $.ui.ddmanager ) { 5994 $.ui.ddmanager.dragStart(this, event); 5995 } 5996 5997 return true; 5998 }, 5999 6000 _mouseDrag: function(event, noPropagation) { 6001 // reset any necessary cached properties (see #5009) 6002 if ( this.offsetParentCssPosition === "fixed" ) { 6003 this.offset.parent = this._getParentOffset(); 6004 } 6005 6006 //Compute the helpers position 6007 this.position = this._generatePosition( event, true ); 6008 this.positionAbs = this._convertPositionTo("absolute"); 6009 6010 //Call plugins and callbacks and use the resulting position if something is returned 6011 if (!noPropagation) { 6012 var ui = this._uiHash(); 6013 if (this._trigger("drag", event, ui) === false) { 6014 this._mouseUp({}); 6015 return false; 6016 } 6017 this.position = ui.position; 6018 } 6019 6020 this.helper[ 0 ].style.left = this.position.left + "px"; 6021 this.helper[ 0 ].style.top = this.position.top + "px"; 6022 6023 if ($.ui.ddmanager) { 6024 $.ui.ddmanager.drag(this, event); 6025 } 6026 6027 return false; 6028 }, 6029 6030 _mouseStop: function(event) { 6031 6032 //If we are using droppables, inform the manager about the drop 6033 var that = this, 6034 dropped = false; 6035 if ($.ui.ddmanager && !this.options.dropBehaviour) { 6036 dropped = $.ui.ddmanager.drop(this, event); 6037 } 6038 6039 //if a drop comes from outside (a sortable) 6040 if (this.dropped) { 6041 dropped = this.dropped; 6042 this.dropped = false; 6043 } 6044 6045 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))) { 6046 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { 6047 if (that._trigger("stop", event) !== false) { 6048 that._clear(); 6049 } 6050 }); 6051 } else { 6052 if (this._trigger("stop", event) !== false) { 6053 this._clear(); 6054 } 6055 } 6056 6057 return false; 6058 }, 6059 6060 _mouseUp: function(event) { 6061 //Remove frame helpers 6062 $("div.ui-draggable-iframeFix").each(function() { 6063 this.parentNode.removeChild(this); 6064 }); 6065 6066 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) 6067 if ( $.ui.ddmanager ) { 6068 $.ui.ddmanager.dragStop(this, event); 6069 } 6070 6071 // The interaction is over; whether or not the click resulted in a drag, focus the element 6072 this.element.focus(); 6073 6074 return $.ui.mouse.prototype._mouseUp.call(this, event); 6075 }, 6076 6077 cancel: function() { 6078 6079 if (this.helper.is(".ui-draggable-dragging")) { 6080 this._mouseUp({}); 6081 } else { 6082 this._clear(); 6083 } 6084 6085 return this; 6086 6087 }, 6088 6089 _getHandle: function(event) { 6090 return this.options.handle ? 6091 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : 6092 true; 6093 }, 6094 6095 _setHandleClassName: function() { 6096 this.handleElement = this.options.handle ? 6097 this.element.find( this.options.handle ) : this.element; 6098 this.handleElement.addClass( "ui-draggable-handle" ); 6099 }, 6100 6101 _removeHandleClassName: function() { 6102 this.handleElement.removeClass( "ui-draggable-handle" ); 6103 }, 6104 6105 _createHelper: function(event) { 6106 6107 var o = this.options, 6108 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[ 0 ], [ event ])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); 6109 6110 if (!helper.parents("body").length) { 6111 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); 6112 } 6113 6114 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { 6115 helper.css("position", "absolute"); 6116 } 6117 6118 return helper; 6119 6120 }, 6121 6122 _adjustOffsetFromHelper: function(obj) { 6123 if (typeof obj === "string") { 6124 obj = obj.split(" "); 6125 } 6126 if ($.isArray(obj)) { 6127 obj = { left: +obj[0], top: +obj[1] || 0 }; 6128 } 6129 if ("left" in obj) { 6130 this.offset.click.left = obj.left + this.margins.left; 6131 } 6132 if ("right" in obj) { 6133 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 6134 } 6135 if ("top" in obj) { 6136 this.offset.click.top = obj.top + this.margins.top; 6137 } 6138 if ("bottom" in obj) { 6139 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 6140 } 6141 }, 6142 6143 _isRootNode: function( element ) { 6144 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ]; 6145 }, 6146 6147 _getParentOffset: function() { 6148 6149 //Get the offsetParent and cache its position 6150 var po = this.offsetParent.offset(), 6151 document = this.document[ 0 ]; 6152 6153 // This is a special case where we need to modify a offset calculated on start, since the following happened: 6154 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent 6155 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that 6156 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag 6157 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { 6158 po.left += this.scrollParent.scrollLeft(); 6159 po.top += this.scrollParent.scrollTop(); 6160 } 6161 6162 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) { 6163 po = { top: 0, left: 0 }; 6164 } 6165 6166 return { 6167 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0), 6168 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0) 6169 }; 6170 6171 }, 6172 6173 _getRelativeOffset: function() { 6174 if ( this.cssPosition !== "relative" ) { 6175 return { top: 0, left: 0 }; 6176 } 6177 6178 var p = this.element.position(), 6179 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 6180 6181 return { 6182 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ), 6183 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 ) 6184 }; 6185 6186 }, 6187 6188 _cacheMargins: function() { 6189 this.margins = { 6190 left: (parseInt(this.element.css("marginLeft"), 10) || 0), 6191 top: (parseInt(this.element.css("marginTop"), 10) || 0), 6192 right: (parseInt(this.element.css("marginRight"), 10) || 0), 6193 bottom: (parseInt(this.element.css("marginBottom"), 10) || 0) 6194 }; 6195 }, 6196 6197 _cacheHelperProportions: function() { 6198 this.helperProportions = { 6199 width: this.helper.outerWidth(), 6200 height: this.helper.outerHeight() 6201 }; 6202 }, 6203 6204 _setContainment: function() { 6205 6206 var over, c, ce, 6207 o = this.options, 6208 document = this.document[ 0 ]; 6209 6210 this.relativeContainer = null; 6211 6212 if ( !o.containment ) { 6213 this.containment = null; 6214 return; 6215 } 6216 6217 if ( o.containment === "window" ) { 6218 this.containment = [ 6219 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, 6220 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, 6221 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, 6222 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top 6223 ]; 6224 return; 6225 } 6226 6227 if ( o.containment === "document") { 6228 this.containment = [ 6229 0, 6230 0, 6231 $( document ).width() - this.helperProportions.width - this.margins.left, 6232 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top 6233 ]; 6234 return; 6235 } 6236 6237 if ( o.containment.constructor === Array ) { 6238 this.containment = o.containment; 6239 return; 6240 } 6241 6242 if ( o.containment === "parent" ) { 6243 o.containment = this.helper[ 0 ].parentNode; 6244 } 6245 6246 c = $( o.containment ); 6247 ce = c[ 0 ]; 6248 6249 if ( !ce ) { 6250 return; 6251 } 6252 6253 over = c.css( "overflow" ) !== "hidden"; 6254 6255 this.containment = [ 6256 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), 6257 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ), 6258 ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right, 6259 ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom 6260 ]; 6261 this.relativeContainer = c; 6262 }, 6263 6264 _convertPositionTo: function(d, pos) { 6265 6266 if (!pos) { 6267 pos = this.position; 6268 } 6269 6270 var mod = d === "absolute" ? 1 : -1, 6271 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ); 6272 6273 return { 6274 top: ( 6275 pos.top + // The absolute mouse position 6276 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 6277 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) 6278 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod) 6279 ), 6280 left: ( 6281 pos.left + // The absolute mouse position 6282 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 6283 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) 6284 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod) 6285 ) 6286 }; 6287 6288 }, 6289 6290 _generatePosition: function( event, constrainPosition ) { 6291 6292 var containment, co, top, left, 6293 o = this.options, 6294 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ), 6295 pageX = event.pageX, 6296 pageY = event.pageY; 6297 6298 // Cache the scroll 6299 if ( !scrollIsRootNode || !this.offset.scroll ) { 6300 this.offset.scroll = { 6301 top: this.scrollParent.scrollTop(), 6302 left: this.scrollParent.scrollLeft() 6303 }; 6304 } 6305 6306 /* 6307 * - Position constraining - 6308 * Constrain the position to a mix of grid, containment. 6309 */ 6310 6311 // If we are not dragging yet, we won't check for options 6312 if ( constrainPosition ) { 6313 if ( this.containment ) { 6314 if ( this.relativeContainer ){ 6315 co = this.relativeContainer.offset(); 6316 containment = [ 6317 this.containment[ 0 ] + co.left, 6318 this.containment[ 1 ] + co.top, 6319 this.containment[ 2 ] + co.left, 6320 this.containment[ 3 ] + co.top 6321 ]; 6322 } else { 6323 containment = this.containment; 6324 } 6325 6326 if (event.pageX - this.offset.click.left < containment[0]) { 6327 pageX = containment[0] + this.offset.click.left; 6328 } 6329 if (event.pageY - this.offset.click.top < containment[1]) { 6330 pageY = containment[1] + this.offset.click.top; 6331 } 6332 if (event.pageX - this.offset.click.left > containment[2]) { 6333 pageX = containment[2] + this.offset.click.left; 6334 } 6335 if (event.pageY - this.offset.click.top > containment[3]) { 6336 pageY = containment[3] + this.offset.click.top; 6337 } 6338 } 6339 6340 if (o.grid) { 6341 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) 6342 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; 6343 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; 6344 6345 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; 6346 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; 6347 } 6348 6349 if ( o.axis === "y" ) { 6350 pageX = this.originalPageX; 6351 } 6352 6353 if ( o.axis === "x" ) { 6354 pageY = this.originalPageY; 6355 } 6356 } 6357 6358 return { 6359 top: ( 6360 pageY - // The absolute mouse position 6361 this.offset.click.top - // Click offset (relative to the element) 6362 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent 6363 this.offset.parent.top + // The offsetParent's offset without borders (offset + border) 6364 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) 6365 ), 6366 left: ( 6367 pageX - // The absolute mouse position 6368 this.offset.click.left - // Click offset (relative to the element) 6369 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent 6370 this.offset.parent.left + // The offsetParent's offset without borders (offset + border) 6371 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) 6372 ) 6373 }; 6374 6375 }, 6376 6377 _clear: function() { 6378 this.helper.removeClass("ui-draggable-dragging"); 6379 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { 6380 this.helper.remove(); 6381 } 6382 this.helper = null; 6383 this.cancelHelperRemoval = false; 6384 if ( this.destroyOnClear ) { 6385 this.destroy(); 6386 } 6387 }, 6388 6389 // From now on bulk stuff - mainly helpers 6390 6391 _trigger: function(type, event, ui) { 6392 ui = ui || this._uiHash(); 6393 $.ui.plugin.call( this, type, [ event, ui, this ], true ); 6394 //The absolute position has to be recalculated after plugins 6395 if (type === "drag") { 6396 this.positionAbs = this._convertPositionTo("absolute"); 6397 } 6398 return $.Widget.prototype._trigger.call(this, type, event, ui); 6399 }, 6400 6401 plugins: {}, 6402 6403 _uiHash: function() { 6404 return { 6405 helper: this.helper, 6406 position: this.position, 6407 originalPosition: this.originalPosition, 6408 offset: this.positionAbs 6409 }; 6410 } 6411 6412 }); 6413 6414 $.ui.plugin.add("draggable", "connectToSortable", { 6415 start: function( event, ui, inst ) { 6416 6417 var o = inst.options, 6418 uiSortable = $.extend({}, ui, { item: inst.element }); 6419 inst.sortables = []; 6420 $(o.connectToSortable).each(function() { 6421 var sortable = $( this ).sortable( "instance" ); 6422 if (sortable && !sortable.options.disabled) { 6423 inst.sortables.push({ 6424 instance: sortable, 6425 shouldRevert: sortable.options.revert 6426 }); 6427 sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). 6428 sortable._trigger("activate", event, uiSortable); 6429 } 6430 }); 6431 6432 }, 6433 stop: function( event, ui, inst ) { 6434 6435 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper 6436 var uiSortable = $.extend( {}, ui, { 6437 item: inst.element 6438 }); 6439 6440 $.each(inst.sortables, function() { 6441 if (this.instance.isOver) { 6442 6443 this.instance.isOver = 0; 6444 6445 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance 6446 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) 6447 6448 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" 6449 if (this.shouldRevert) { 6450 this.instance.options.revert = this.shouldRevert; 6451 } 6452 6453 //Trigger the stop of the sortable 6454 this.instance._mouseStop(event); 6455 6456 this.instance.options.helper = this.instance.options._helper; 6457 6458 //If the helper has been the original item, restore properties in the sortable 6459 if (inst.options.helper === "original") { 6460 this.instance.currentItem.css({ top: "auto", left: "auto" }); 6461 } 6462 6463 } else { 6464 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance 6465 this.instance._trigger("deactivate", event, uiSortable); 6466 } 6467 6468 }); 6469 6470 }, 6471 drag: function( event, ui, inst ) { 6472 6473 var that = this; 6474 6475 $.each(inst.sortables, function() { 6476 6477 var innermostIntersecting = false, 6478 thisSortable = this; 6479 6480 //Copy over some variables to allow calling the sortable's native _intersectsWith 6481 this.instance.positionAbs = inst.positionAbs; 6482 this.instance.helperProportions = inst.helperProportions; 6483 this.instance.offset.click = inst.offset.click; 6484 6485 if (this.instance._intersectsWith(this.instance.containerCache)) { 6486 innermostIntersecting = true; 6487 $.each(inst.sortables, function() { 6488 this.instance.positionAbs = inst.positionAbs; 6489 this.instance.helperProportions = inst.helperProportions; 6490 this.instance.offset.click = inst.offset.click; 6491 if (this !== thisSortable && 6492 this.instance._intersectsWith(this.instance.containerCache) && 6493 $.contains(thisSortable.instance.element[0], this.instance.element[0]) 6494 ) { 6495 innermostIntersecting = false; 6496 } 6497 return innermostIntersecting; 6498 }); 6499 } 6500 6501 if (innermostIntersecting) { 6502 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once 6503 if (!this.instance.isOver) { 6504 6505 this.instance.isOver = 1; 6506 //Now we fake the start of dragging for the sortable instance, 6507 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem 6508 //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) 6509 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); 6510 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it 6511 this.instance.options.helper = function() { return ui.helper[0]; }; 6512 6513 event.target = this.instance.currentItem[0]; 6514 this.instance._mouseCapture(event, true); 6515 this.instance._mouseStart(event, true, true); 6516 6517 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes 6518 this.instance.offset.click.top = inst.offset.click.top; 6519 this.instance.offset.click.left = inst.offset.click.left; 6520 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; 6521 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; 6522 6523 inst._trigger("toSortable", event); 6524 inst.dropped = this.instance.element; //draggable revert needs that 6525 //hack so receive/update callbacks work (mostly) 6526 inst.currentItem = inst.element; 6527 this.instance.fromOutside = inst; 6528 6529 } 6530 6531 //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable 6532 if (this.instance.currentItem) { 6533 this.instance._mouseDrag(event); 6534 } 6535 6536 } else { 6537 6538 //If it doesn't intersect with the sortable, and it intersected before, 6539 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval 6540 if (this.instance.isOver) { 6541 6542 this.instance.isOver = 0; 6543 this.instance.cancelHelperRemoval = true; 6544 6545 //Prevent reverting on this forced stop 6546 this.instance.options.revert = false; 6547 6548 // The out event needs to be triggered independently 6549 this.instance._trigger("out", event, this.instance._uiHash(this.instance)); 6550 6551 this.instance._mouseStop(event, true); 6552 this.instance.options.helper = this.instance.options._helper; 6553 6554 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size 6555 this.instance.currentItem.remove(); 6556 if (this.instance.placeholder) { 6557 this.instance.placeholder.remove(); 6558 } 6559 6560 inst._trigger("fromSortable", event); 6561 inst.dropped = false; //draggable revert needs that 6562 } 6563 6564 } 6565 6566 }); 6567 6568 } 6569 }); 6570 6571 $.ui.plugin.add("draggable", "cursor", { 6572 start: function( event, ui, instance ) { 6573 var t = $( "body" ), 6574 o = instance.options; 6575 6576 if (t.css("cursor")) { 6577 o._cursor = t.css("cursor"); 6578 } 6579 t.css("cursor", o.cursor); 6580 }, 6581 stop: function( event, ui, instance ) { 6582 var o = instance.options; 6583 if (o._cursor) { 6584 $("body").css("cursor", o._cursor); 6585 } 6586 } 6587 }); 6588 6589 $.ui.plugin.add("draggable", "opacity", { 6590 start: function( event, ui, instance ) { 6591 var t = $( ui.helper ), 6592 o = instance.options; 6593 if (t.css("opacity")) { 6594 o._opacity = t.css("opacity"); 6595 } 6596 t.css("opacity", o.opacity); 6597 }, 6598 stop: function( event, ui, instance ) { 6599 var o = instance.options; 6600 if (o._opacity) { 6601 $(ui.helper).css("opacity", o._opacity); 6602 } 6603 } 6604 }); 6605 6606 $.ui.plugin.add("draggable", "scroll", { 6607 start: function( event, ui, i ) { 6608 if ( !i.scrollParentNotHidden ) { 6609 i.scrollParentNotHidden = i.helper.scrollParent( false ); 6610 } 6611 6612 if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) { 6613 i.overflowOffset = i.scrollParentNotHidden.offset(); 6614 } 6615 }, 6616 drag: function( event, ui, i ) { 6617 6618 var o = i.options, 6619 scrolled = false, 6620 scrollParent = i.scrollParentNotHidden[ 0 ], 6621 document = i.document[ 0 ]; 6622 6623 if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) { 6624 if ( !o.axis || o.axis !== "x" ) { 6625 if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) { 6626 scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed; 6627 } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) { 6628 scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed; 6629 } 6630 } 6631 6632 if ( !o.axis || o.axis !== "y" ) { 6633 if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) { 6634 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed; 6635 } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) { 6636 scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed; 6637 } 6638 } 6639 6640 } else { 6641 6642 if (!o.axis || o.axis !== "x") { 6643 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) { 6644 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 6645 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { 6646 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 6647 } 6648 } 6649 6650 if (!o.axis || o.axis !== "y") { 6651 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { 6652 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 6653 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { 6654 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 6655 } 6656 } 6657 6658 } 6659 6660 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { 6661 $.ui.ddmanager.prepareOffsets(i, event); 6662 } 6663 6664 } 6665 }); 6666 6667 $.ui.plugin.add("draggable", "snap", { 6668 start: function( event, ui, i ) { 6669 6670 var o = i.options; 6671 6672 i.snapElements = []; 6673 6674 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { 6675 var $t = $(this), 6676 $o = $t.offset(); 6677 if (this !== i.element[0]) { 6678 i.snapElements.push({ 6679 item: this, 6680 width: $t.outerWidth(), height: $t.outerHeight(), 6681 top: $o.top, left: $o.left 6682 }); 6683 } 6684 }); 6685 6686 }, 6687 drag: function( event, ui, inst ) { 6688 6689 var ts, bs, ls, rs, l, r, t, b, i, first, 6690 o = inst.options, 6691 d = o.snapTolerance, 6692 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, 6693 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; 6694 6695 for (i = inst.snapElements.length - 1; i >= 0; i--){ 6696 6697 l = inst.snapElements[i].left; 6698 r = l + inst.snapElements[i].width; 6699 t = inst.snapElements[i].top; 6700 b = t + inst.snapElements[i].height; 6701 6702 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { 6703 if (inst.snapElements[i].snapping) { 6704 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); 6705 } 6706 inst.snapElements[i].snapping = false; 6707 continue; 6708 } 6709 6710 if (o.snapMode !== "inner") { 6711 ts = Math.abs(t - y2) <= d; 6712 bs = Math.abs(b - y1) <= d; 6713 ls = Math.abs(l - x2) <= d; 6714 rs = Math.abs(r - x1) <= d; 6715 if (ts) { 6716 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; 6717 } 6718 if (bs) { 6719 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; 6720 } 6721 if (ls) { 6722 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; 6723 } 6724 if (rs) { 6725 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; 6726 } 6727 } 6728 6729 first = (ts || bs || ls || rs); 6730 6731 if (o.snapMode !== "outer") { 6732 ts = Math.abs(t - y1) <= d; 6733 bs = Math.abs(b - y2) <= d; 6734 ls = Math.abs(l - x1) <= d; 6735 rs = Math.abs(r - x2) <= d; 6736 if (ts) { 6737 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; 6738 } 6739 if (bs) { 6740 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; 6741 } 6742 if (ls) { 6743 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; 6744 } 6745 if (rs) { 6746 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; 6747 } 6748 } 6749 6750 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { 6751 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); 6752 } 6753 inst.snapElements[i].snapping = (ts || bs || ls || rs || first); 6754 6755 } 6756 6757 } 6758 }); 6759 6760 $.ui.plugin.add("draggable", "stack", { 6761 start: function( event, ui, instance ) { 6762 var min, 6763 o = instance.options, 6764 group = $.makeArray($(o.stack)).sort(function(a, b) { 6765 return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0); 6766 }); 6767 6768 if (!group.length) { return; } 6769 6770 min = parseInt($(group[0]).css("zIndex"), 10) || 0; 6771 $(group).each(function(i) { 6772 $(this).css("zIndex", min + i); 6773 }); 6774 this.css("zIndex", (min + group.length)); 6775 } 6776 }); 6777 6778 $.ui.plugin.add("draggable", "zIndex", { 6779 start: function( event, ui, instance ) { 6780 var t = $( ui.helper ), 6781 o = instance.options; 6782 6783 if (t.css("zIndex")) { 6784 o._zIndex = t.css("zIndex"); 6785 } 6786 t.css("zIndex", o.zIndex); 6787 }, 6788 stop: function( event, ui, instance ) { 6789 var o = instance.options; 6790 6791 if (o._zIndex) { 6792 $(ui.helper).css("zIndex", o._zIndex); 6793 } 6794 } 6795 }); 6796 6797 var draggable = $.ui.draggable; 6798 6799 6800 /*! 6801 * jQuery UI Resizable 1.11.1 6802 * http://jqueryui.com 6803 * 6804 * Copyright 2014 jQuery Foundation and other contributors 6805 * Released under the MIT license. 6806 * http://jquery.org/license 6807 * 6808 * http://api.jqueryui.com/resizable/ 6809 */ 6810 6811 6812 $.widget("ui.resizable", $.ui.mouse, { 6813 version: "1.11.1", 6814 widgetEventPrefix: "resize", 6815 options: { 6816 alsoResize: false, 6817 animate: false, 6818 animateDuration: "slow", 6819 animateEasing: "swing", 6820 aspectRatio: false, 6821 autoHide: false, 6822 containment: false, 6823 ghost: false, 6824 grid: false, 6825 handles: "e,s,se", 6826 helper: false, 6827 maxHeight: null, 6828 maxWidth: null, 6829 minHeight: 10, 6830 minWidth: 10, 6831 // See #7960 6832 zIndex: 90, 6833 6834 // callbacks 6835 resize: null, 6836 start: null, 6837 stop: null 6838 }, 6839 6840 _num: function( value ) { 6841 return parseInt( value, 10 ) || 0; 6842 }, 6843 6844 _isNumber: function( value ) { 6845 return !isNaN( parseInt( value, 10 ) ); 6846 }, 6847 6848 _hasScroll: function( el, a ) { 6849 6850 if ( $( el ).css( "overflow" ) === "hidden") { 6851 return false; 6852 } 6853 6854 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", 6855 has = false; 6856 6857 if ( el[ scroll ] > 0 ) { 6858 return true; 6859 } 6860 6861 // TODO: determine which cases actually cause this to happen 6862 // if the element doesn't have the scroll set, see if it's possible to 6863 // set the scroll 6864 el[ scroll ] = 1; 6865 has = ( el[ scroll ] > 0 ); 6866 el[ scroll ] = 0; 6867 return has; 6868 }, 6869 6870 _create: function() { 6871 6872 var n, i, handle, axis, hname, 6873 that = this, 6874 o = this.options; 6875 this.element.addClass("ui-resizable"); 6876 6877 $.extend(this, { 6878 _aspectRatio: !!(o.aspectRatio), 6879 aspectRatio: o.aspectRatio, 6880 originalElement: this.element, 6881 _proportionallyResizeElements: [], 6882 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null 6883 }); 6884 6885 // Wrap the element if it cannot hold child nodes 6886 if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { 6887 6888 this.element.wrap( 6889 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({ 6890 position: this.element.css("position"), 6891 width: this.element.outerWidth(), 6892 height: this.element.outerHeight(), 6893 top: this.element.css("top"), 6894 left: this.element.css("left") 6895 }) 6896 ); 6897 6898 this.element = this.element.parent().data( 6899 "ui-resizable", this.element.resizable( "instance" ) 6900 ); 6901 6902 this.elementIsWrapper = true; 6903 6904 this.element.css({ 6905 marginLeft: this.originalElement.css("marginLeft"), 6906 marginTop: this.originalElement.css("marginTop"), 6907 marginRight: this.originalElement.css("marginRight"), 6908 marginBottom: this.originalElement.css("marginBottom") 6909 }); 6910 this.originalElement.css({ 6911 marginLeft: 0, 6912 marginTop: 0, 6913 marginRight: 0, 6914 marginBottom: 0 6915 }); 6916 // support: Safari 6917 // Prevent Safari textarea resize 6918 this.originalResizeStyle = this.originalElement.css("resize"); 6919 this.originalElement.css("resize", "none"); 6920 6921 this._proportionallyResizeElements.push( this.originalElement.css({ 6922 position: "static", 6923 zoom: 1, 6924 display: "block" 6925 }) ); 6926 6927 // support: IE9 6928 // avoid IE jump (hard set the margin) 6929 this.originalElement.css({ margin: this.originalElement.css("margin") }); 6930 6931 this._proportionallyResize(); 6932 } 6933 6934 this.handles = o.handles || 6935 ( !$(".ui-resizable-handle", this.element).length ? 6936 "e,s,se" : { 6937 n: ".ui-resizable-n", 6938 e: ".ui-resizable-e", 6939 s: ".ui-resizable-s", 6940 w: ".ui-resizable-w", 6941 se: ".ui-resizable-se", 6942 sw: ".ui-resizable-sw", 6943 ne: ".ui-resizable-ne", 6944 nw: ".ui-resizable-nw" 6945 } ); 6946 6947 if (this.handles.constructor === String) { 6948 6949 if ( this.handles === "all") { 6950 this.handles = "n,e,s,w,se,sw,ne,nw"; 6951 } 6952 6953 n = this.handles.split(","); 6954 this.handles = {}; 6955 6956 for (i = 0; i < n.length; i++) { 6957 6958 handle = $.trim(n[i]); 6959 hname = "ui-resizable-" + handle; 6960 axis = $("<div class='ui-resizable-handle " + hname + "'></div>"); 6961 6962 axis.css({ zIndex: o.zIndex }); 6963 6964 // TODO : What's going on here? 6965 if ("se" === handle) { 6966 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); 6967 } 6968 6969 this.handles[handle] = ".ui-resizable-" + handle; 6970 this.element.append(axis); 6971 } 6972 6973 } 6974 6975 this._renderAxis = function(target) { 6976 6977 var i, axis, padPos, padWrapper; 6978 6979 target = target || this.element; 6980 6981 for (i in this.handles) { 6982 6983 if (this.handles[i].constructor === String) { 6984 this.handles[i] = this.element.children( this.handles[ i ] ).first().show(); 6985 } 6986 6987 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { 6988 6989 axis = $(this.handles[i], this.element); 6990 6991 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); 6992 6993 padPos = [ "padding", 6994 /ne|nw|n/.test(i) ? "Top" : 6995 /se|sw|s/.test(i) ? "Bottom" : 6996 /^e$/.test(i) ? "Right" : "Left" ].join(""); 6997 6998 target.css(padPos, padWrapper); 6999 7000 this._proportionallyResize(); 7001 7002 } 7003 7004 // TODO: What's that good for? There's not anything to be executed left 7005 if (!$(this.handles[i]).length) { 7006 continue; 7007 } 7008 } 7009 }; 7010 7011 // TODO: make renderAxis a prototype function 7012 this._renderAxis(this.element); 7013 7014 this._handles = $(".ui-resizable-handle", this.element) 7015 .disableSelection(); 7016 7017 this._handles.mouseover(function() { 7018 if (!that.resizing) { 7019 if (this.className) { 7020 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); 7021 } 7022 that.axis = axis && axis[1] ? axis[1] : "se"; 7023 } 7024 }); 7025 7026 if (o.autoHide) { 7027 this._handles.hide(); 7028 $(this.element) 7029 .addClass("ui-resizable-autohide") 7030 .mouseenter(function() { 7031 if (o.disabled) { 7032 return; 7033 } 7034 $(this).removeClass("ui-resizable-autohide"); 7035 that._handles.show(); 7036 }) 7037 .mouseleave(function() { 7038 if (o.disabled) { 7039 return; 7040 } 7041 if (!that.resizing) { 7042 $(this).addClass("ui-resizable-autohide"); 7043 that._handles.hide(); 7044 } 7045 }); 7046 } 7047 7048 this._mouseInit(); 7049 7050 }, 7051 7052 _destroy: function() { 7053 7054 this._mouseDestroy(); 7055 7056 var wrapper, 7057 _destroy = function(exp) { 7058 $(exp) 7059 .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") 7060 .removeData("resizable") 7061 .removeData("ui-resizable") 7062 .unbind(".resizable") 7063 .find(".ui-resizable-handle") 7064 .remove(); 7065 }; 7066 7067 // TODO: Unwrap at same DOM position 7068 if (this.elementIsWrapper) { 7069 _destroy(this.element); 7070 wrapper = this.element; 7071 this.originalElement.css({ 7072 position: wrapper.css("position"), 7073 width: wrapper.outerWidth(), 7074 height: wrapper.outerHeight(), 7075 top: wrapper.css("top"), 7076 left: wrapper.css("left") 7077 }).insertAfter( wrapper ); 7078 wrapper.remove(); 7079 } 7080 7081 this.originalElement.css("resize", this.originalResizeStyle); 7082 _destroy(this.originalElement); 7083 7084 return this; 7085 }, 7086 7087 _mouseCapture: function(event) { 7088 var i, handle, 7089 capture = false; 7090 7091 for (i in this.handles) { 7092 handle = $(this.handles[i])[0]; 7093 if (handle === event.target || $.contains(handle, event.target)) { 7094 capture = true; 7095 } 7096 } 7097 7098 return !this.options.disabled && capture; 7099 }, 7100 7101 _mouseStart: function(event) { 7102 7103 var curleft, curtop, cursor, 7104 o = this.options, 7105 el = this.element; 7106 7107 this.resizing = true; 7108 7109 this._renderProxy(); 7110 7111 curleft = this._num(this.helper.css("left")); 7112 curtop = this._num(this.helper.css("top")); 7113 7114 if (o.containment) { 7115 curleft += $(o.containment).scrollLeft() || 0; 7116 curtop += $(o.containment).scrollTop() || 0; 7117 } 7118 7119 this.offset = this.helper.offset(); 7120 this.position = { left: curleft, top: curtop }; 7121 7122 this.size = this._helper ? { 7123 width: this.helper.width(), 7124 height: this.helper.height() 7125 } : { 7126 width: el.width(), 7127 height: el.height() 7128 }; 7129 7130 this.originalSize = this._helper ? { 7131 width: el.outerWidth(), 7132 height: el.outerHeight() 7133 } : { 7134 width: el.width(), 7135 height: el.height() 7136 }; 7137 7138 this.sizeDiff = { 7139 width: el.outerWidth() - el.width(), 7140 height: el.outerHeight() - el.height() 7141 }; 7142 7143 this.originalPosition = { left: curleft, top: curtop }; 7144 this.originalMousePosition = { left: event.pageX, top: event.pageY }; 7145 7146 this.aspectRatio = (typeof o.aspectRatio === "number") ? 7147 o.aspectRatio : 7148 ((this.originalSize.width / this.originalSize.height) || 1); 7149 7150 cursor = $(".ui-resizable-" + this.axis).css("cursor"); 7151 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); 7152 7153 el.addClass("ui-resizable-resizing"); 7154 this._propagate("start", event); 7155 return true; 7156 }, 7157 7158 _mouseDrag: function(event) { 7159 7160 var data, props, 7161 smp = this.originalMousePosition, 7162 a = this.axis, 7163 dx = (event.pageX - smp.left) || 0, 7164 dy = (event.pageY - smp.top) || 0, 7165 trigger = this._change[a]; 7166 7167 this._updatePrevProperties(); 7168 7169 if (!trigger) { 7170 return false; 7171 } 7172 7173 data = trigger.apply(this, [ event, dx, dy ]); 7174 7175 this._updateVirtualBoundaries(event.shiftKey); 7176 if (this._aspectRatio || event.shiftKey) { 7177 data = this._updateRatio(data, event); 7178 } 7179 7180 data = this._respectSize(data, event); 7181 7182 this._updateCache(data); 7183 7184 this._propagate("resize", event); 7185 7186 props = this._applyChanges(); 7187 7188 if ( !this._helper && this._proportionallyResizeElements.length ) { 7189 this._proportionallyResize(); 7190 } 7191 7192 if ( !$.isEmptyObject( props ) ) { 7193 this._updatePrevProperties(); 7194 this._trigger( "resize", event, this.ui() ); 7195 this._applyChanges(); 7196 } 7197 7198 return false; 7199 }, 7200 7201 _mouseStop: function(event) { 7202 7203 this.resizing = false; 7204 var pr, ista, soffseth, soffsetw, s, left, top, 7205 o = this.options, that = this; 7206 7207 if (this._helper) { 7208 7209 pr = this._proportionallyResizeElements; 7210 ista = pr.length && (/textarea/i).test(pr[0].nodeName); 7211 soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height; 7212 soffsetw = ista ? 0 : that.sizeDiff.width; 7213 7214 s = { 7215 width: (that.helper.width() - soffsetw), 7216 height: (that.helper.height() - soffseth) 7217 }; 7218 left = (parseInt(that.element.css("left"), 10) + 7219 (that.position.left - that.originalPosition.left)) || null; 7220 top = (parseInt(that.element.css("top"), 10) + 7221 (that.position.top - that.originalPosition.top)) || null; 7222 7223 if (!o.animate) { 7224 this.element.css($.extend(s, { top: top, left: left })); 7225 } 7226 7227 that.helper.height(that.size.height); 7228 that.helper.width(that.size.width); 7229 7230 if (this._helper && !o.animate) { 7231 this._proportionallyResize(); 7232 } 7233 } 7234 7235 $("body").css("cursor", "auto"); 7236 7237 this.element.removeClass("ui-resizable-resizing"); 7238 7239 this._propagate("stop", event); 7240 7241 if (this._helper) { 7242 this.helper.remove(); 7243 } 7244 7245 return false; 7246 7247 }, 7248 7249 _updatePrevProperties: function() { 7250 this.prevPosition = { 7251 top: this.position.top, 7252 left: this.position.left 7253 }; 7254 this.prevSize = { 7255 width: this.size.width, 7256 height: this.size.height 7257 }; 7258 }, 7259 7260 _applyChanges: function() { 7261 var props = {}; 7262 7263 if ( this.position.top !== this.prevPosition.top ) { 7264 props.top = this.position.top + "px"; 7265 } 7266 if ( this.position.left !== this.prevPosition.left ) { 7267 props.left = this.position.left + "px"; 7268 } 7269 if ( this.size.width !== this.prevSize.width ) { 7270 props.width = this.size.width + "px"; 7271 } 7272 if ( this.size.height !== this.prevSize.height ) { 7273 props.height = this.size.height + "px"; 7274 } 7275 7276 this.helper.css( props ); 7277 7278 return props; 7279 }, 7280 7281 _updateVirtualBoundaries: function(forceAspectRatio) { 7282 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, 7283 o = this.options; 7284 7285 b = { 7286 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0, 7287 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity, 7288 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0, 7289 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity 7290 }; 7291 7292 if (this._aspectRatio || forceAspectRatio) { 7293 pMinWidth = b.minHeight * this.aspectRatio; 7294 pMinHeight = b.minWidth / this.aspectRatio; 7295 pMaxWidth = b.maxHeight * this.aspectRatio; 7296 pMaxHeight = b.maxWidth / this.aspectRatio; 7297 7298 if (pMinWidth > b.minWidth) { 7299 b.minWidth = pMinWidth; 7300 } 7301 if (pMinHeight > b.minHeight) { 7302 b.minHeight = pMinHeight; 7303 } 7304 if (pMaxWidth < b.maxWidth) { 7305 b.maxWidth = pMaxWidth; 7306 } 7307 if (pMaxHeight < b.maxHeight) { 7308 b.maxHeight = pMaxHeight; 7309 } 7310 } 7311 this._vBoundaries = b; 7312 }, 7313 7314 _updateCache: function(data) { 7315 this.offset = this.helper.offset(); 7316 if (this._isNumber(data.left)) { 7317 this.position.left = data.left; 7318 } 7319 if (this._isNumber(data.top)) { 7320 this.position.top = data.top; 7321 } 7322 if (this._isNumber(data.height)) { 7323 this.size.height = data.height; 7324 } 7325 if (this._isNumber(data.width)) { 7326 this.size.width = data.width; 7327 } 7328 }, 7329 7330 _updateRatio: function( data ) { 7331 7332 var cpos = this.position, 7333 csize = this.size, 7334 a = this.axis; 7335 7336 if (this._isNumber(data.height)) { 7337 data.width = (data.height * this.aspectRatio); 7338 } else if (this._isNumber(data.width)) { 7339 data.height = (data.width / this.aspectRatio); 7340 } 7341 7342 if (a === "sw") { 7343 data.left = cpos.left + (csize.width - data.width); 7344 data.top = null; 7345 } 7346 if (a === "nw") { 7347 data.top = cpos.top + (csize.height - data.height); 7348 data.left = cpos.left + (csize.width - data.width); 7349 } 7350 7351 return data; 7352 }, 7353 7354 _respectSize: function( data ) { 7355 7356 var o = this._vBoundaries, 7357 a = this.axis, 7358 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), 7359 ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), 7360 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width), 7361 isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height), 7362 dw = this.originalPosition.left + this.originalSize.width, 7363 dh = this.position.top + this.size.height, 7364 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); 7365 if (isminw) { 7366 data.width = o.minWidth; 7367 } 7368 if (isminh) { 7369 data.height = o.minHeight; 7370 } 7371 if (ismaxw) { 7372 data.width = o.maxWidth; 7373 } 7374 if (ismaxh) { 7375 data.height = o.maxHeight; 7376 } 7377 7378 if (isminw && cw) { 7379 data.left = dw - o.minWidth; 7380 } 7381 if (ismaxw && cw) { 7382 data.left = dw - o.maxWidth; 7383 } 7384 if (isminh && ch) { 7385 data.top = dh - o.minHeight; 7386 } 7387 if (ismaxh && ch) { 7388 data.top = dh - o.maxHeight; 7389 } 7390 7391 // Fixing jump error on top/left - bug #2330 7392 if (!data.width && !data.height && !data.left && data.top) { 7393 data.top = null; 7394 } else if (!data.width && !data.height && !data.top && data.left) { 7395 data.left = null; 7396 } 7397 7398 return data; 7399 }, 7400 7401 _getPaddingPlusBorderDimensions: function( element ) { 7402 var i = 0, 7403 widths = [], 7404 borders = [ 7405 element.css( "borderTopWidth" ), 7406 element.css( "borderRightWidth" ), 7407 element.css( "borderBottomWidth" ), 7408 element.css( "borderLeftWidth" ) 7409 ], 7410 paddings = [ 7411 element.css( "paddingTop" ), 7412 element.css( "paddingRight" ), 7413 element.css( "paddingBottom" ), 7414 element.css( "paddingLeft" ) 7415 ]; 7416 7417 for ( ; i < 4; i++ ) { 7418 widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 ); 7419 widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 ); 7420 } 7421 7422 return { 7423 height: widths[ 0 ] + widths[ 2 ], 7424 width: widths[ 1 ] + widths[ 3 ] 7425 }; 7426 }, 7427 7428 _proportionallyResize: function() { 7429 7430 if (!this._proportionallyResizeElements.length) { 7431 return; 7432 } 7433 7434 var prel, 7435 i = 0, 7436 element = this.helper || this.element; 7437 7438 for ( ; i < this._proportionallyResizeElements.length; i++) { 7439 7440 prel = this._proportionallyResizeElements[i]; 7441 7442 // TODO: Seems like a bug to cache this.outerDimensions 7443 // considering that we are in a loop. 7444 if (!this.outerDimensions) { 7445 this.outerDimensions = this._getPaddingPlusBorderDimensions( prel ); 7446 } 7447 7448 prel.css({ 7449 height: (element.height() - this.outerDimensions.height) || 0, 7450 width: (element.width() - this.outerDimensions.width) || 0 7451 }); 7452 7453 } 7454 7455 }, 7456 7457 _renderProxy: function() { 7458 7459 var el = this.element, o = this.options; 7460 this.elementOffset = el.offset(); 7461 7462 if (this._helper) { 7463 7464 this.helper = this.helper || $("<div style='overflow:hidden;'></div>"); 7465 7466 this.helper.addClass(this._helper).css({ 7467 width: this.element.outerWidth() - 1, 7468 height: this.element.outerHeight() - 1, 7469 position: "absolute", 7470 left: this.elementOffset.left + "px", 7471 top: this.elementOffset.top + "px", 7472 zIndex: ++o.zIndex //TODO: Don't modify option 7473 }); 7474 7475 this.helper 7476 .appendTo("body") 7477 .disableSelection(); 7478 7479 } else { 7480 this.helper = this.element; 7481 } 7482 7483 }, 7484 7485 _change: { 7486 e: function(event, dx) { 7487 return { width: this.originalSize.width + dx }; 7488 }, 7489 w: function(event, dx) { 7490 var cs = this.originalSize, sp = this.originalPosition; 7491 return { left: sp.left + dx, width: cs.width - dx }; 7492 }, 7493 n: function(event, dx, dy) { 7494 var cs = this.originalSize, sp = this.originalPosition; 7495 return { top: sp.top + dy, height: cs.height - dy }; 7496 }, 7497 s: function(event, dx, dy) { 7498 return { height: this.originalSize.height + dy }; 7499 }, 7500 se: function(event, dx, dy) { 7501 return $.extend(this._change.s.apply(this, arguments), 7502 this._change.e.apply(this, [ event, dx, dy ])); 7503 }, 7504 sw: function(event, dx, dy) { 7505 return $.extend(this._change.s.apply(this, arguments), 7506 this._change.w.apply(this, [ event, dx, dy ])); 7507 }, 7508 ne: function(event, dx, dy) { 7509 return $.extend(this._change.n.apply(this, arguments), 7510 this._change.e.apply(this, [ event, dx, dy ])); 7511 }, 7512 nw: function(event, dx, dy) { 7513 return $.extend(this._change.n.apply(this, arguments), 7514 this._change.w.apply(this, [ event, dx, dy ])); 7515 } 7516 }, 7517 7518 _propagate: function(n, event) { 7519 $.ui.plugin.call(this, n, [ event, this.ui() ]); 7520 (n !== "resize" && this._trigger(n, event, this.ui())); 7521 }, 7522 7523 plugins: {}, 7524 7525 ui: function() { 7526 return { 7527 originalElement: this.originalElement, 7528 element: this.element, 7529 helper: this.helper, 7530 position: this.position, 7531 size: this.size, 7532 originalSize: this.originalSize, 7533 originalPosition: this.originalPosition 7534 }; 7535 } 7536 7537 }); 7538 7539 /* 7540 * Resizable Extensions 7541 */ 7542 7543 $.ui.plugin.add("resizable", "animate", { 7544 7545 stop: function( event ) { 7546 var that = $(this).resizable( "instance" ), 7547 o = that.options, 7548 pr = that._proportionallyResizeElements, 7549 ista = pr.length && (/textarea/i).test(pr[0].nodeName), 7550 soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height, 7551 soffsetw = ista ? 0 : that.sizeDiff.width, 7552 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, 7553 left = (parseInt(that.element.css("left"), 10) + 7554 (that.position.left - that.originalPosition.left)) || null, 7555 top = (parseInt(that.element.css("top"), 10) + 7556 (that.position.top - that.originalPosition.top)) || null; 7557 7558 that.element.animate( 7559 $.extend(style, top && left ? { top: top, left: left } : {}), { 7560 duration: o.animateDuration, 7561 easing: o.animateEasing, 7562 step: function() { 7563 7564 var data = { 7565 width: parseInt(that.element.css("width"), 10), 7566 height: parseInt(that.element.css("height"), 10), 7567 top: parseInt(that.element.css("top"), 10), 7568 left: parseInt(that.element.css("left"), 10) 7569 }; 7570 7571 if (pr && pr.length) { 7572 $(pr[0]).css({ width: data.width, height: data.height }); 7573 } 7574 7575 // propagating resize, and updating values for each animation step 7576 that._updateCache(data); 7577 that._propagate("resize", event); 7578 7579 } 7580 } 7581 ); 7582 } 7583 7584 }); 7585 7586 $.ui.plugin.add( "resizable", "containment", { 7587 7588 start: function() { 7589 var element, p, co, ch, cw, width, height, 7590 that = $( this ).resizable( "instance" ), 7591 o = that.options, 7592 el = that.element, 7593 oc = o.containment, 7594 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc; 7595 7596 if ( !ce ) { 7597 return; 7598 } 7599 7600 that.containerElement = $( ce ); 7601 7602 if ( /document/.test( oc ) || oc === document ) { 7603 that.containerOffset = { 7604 left: 0, 7605 top: 0 7606 }; 7607 that.containerPosition = { 7608 left: 0, 7609 top: 0 7610 }; 7611 7612 that.parentData = { 7613 element: $( document ), 7614 left: 0, 7615 top: 0, 7616 width: $( document ).width(), 7617 height: $( document ).height() || document.body.parentNode.scrollHeight 7618 }; 7619 } else { 7620 element = $( ce ); 7621 p = []; 7622 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) { 7623 p[ i ] = that._num( element.css( "padding" + name ) ); 7624 }); 7625 7626 that.containerOffset = element.offset(); 7627 that.containerPosition = element.position(); 7628 that.containerSize = { 7629 height: ( element.innerHeight() - p[ 3 ] ), 7630 width: ( element.innerWidth() - p[ 1 ] ) 7631 }; 7632 7633 co = that.containerOffset; 7634 ch = that.containerSize.height; 7635 cw = that.containerSize.width; 7636 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw ); 7637 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ; 7638 7639 that.parentData = { 7640 element: ce, 7641 left: co.left, 7642 top: co.top, 7643 width: width, 7644 height: height 7645 }; 7646 } 7647 }, 7648 7649 resize: function( event ) { 7650 var woset, hoset, isParent, isOffsetRelative, 7651 that = $( this ).resizable( "instance" ), 7652 o = that.options, 7653 co = that.containerOffset, 7654 cp = that.position, 7655 pRatio = that._aspectRatio || event.shiftKey, 7656 cop = { 7657 top: 0, 7658 left: 0 7659 }, 7660 ce = that.containerElement, 7661 continueResize = true; 7662 7663 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) { 7664 cop = co; 7665 } 7666 7667 if ( cp.left < ( that._helper ? co.left : 0 ) ) { 7668 that.size.width = that.size.width + 7669 ( that._helper ? 7670 ( that.position.left - co.left ) : 7671 ( that.position.left - cop.left ) ); 7672 7673 if ( pRatio ) { 7674 that.size.height = that.size.width / that.aspectRatio; 7675 continueResize = false; 7676 } 7677 that.position.left = o.helper ? co.left : 0; 7678 } 7679 7680 if ( cp.top < ( that._helper ? co.top : 0 ) ) { 7681 that.size.height = that.size.height + 7682 ( that._helper ? 7683 ( that.position.top - co.top ) : 7684 that.position.top ); 7685 7686 if ( pRatio ) { 7687 that.size.width = that.size.height * that.aspectRatio; 7688 continueResize = false; 7689 } 7690 that.position.top = that._helper ? co.top : 0; 7691 } 7692 7693 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 ); 7694 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) ); 7695 7696 if ( isParent && isOffsetRelative ) { 7697 that.offset.left = that.parentData.left + that.position.left; 7698 that.offset.top = that.parentData.top + that.position.top; 7699 } else { 7700 that.offset.left = that.element.offset().left; 7701 that.offset.top = that.element.offset().top; 7702 } 7703 7704 woset = Math.abs( that.sizeDiff.width + 7705 (that._helper ? 7706 that.offset.left - cop.left : 7707 (that.offset.left - co.left)) ); 7708 7709 hoset = Math.abs( that.sizeDiff.height + 7710 (that._helper ? 7711 that.offset.top - cop.top : 7712 (that.offset.top - co.top)) ); 7713 7714 if ( woset + that.size.width >= that.parentData.width ) { 7715 that.size.width = that.parentData.width - woset; 7716 if ( pRatio ) { 7717 that.size.height = that.size.width / that.aspectRatio; 7718 continueResize = false; 7719 } 7720 } 7721 7722 if ( hoset + that.size.height >= that.parentData.height ) { 7723 that.size.height = that.parentData.height - hoset; 7724 if ( pRatio ) { 7725 that.size.width = that.size.height * that.aspectRatio; 7726 continueResize = false; 7727 } 7728 } 7729 7730 if ( !continueResize ){ 7731 that.position.left = that.prevPosition.left; 7732 that.position.top = that.prevPosition.top; 7733 that.size.width = that.prevSize.width; 7734 that.size.height = that.prevSize.height; 7735 } 7736 }, 7737 7738 stop: function() { 7739 var that = $( this ).resizable( "instance" ), 7740 o = that.options, 7741 co = that.containerOffset, 7742 cop = that.containerPosition, 7743 ce = that.containerElement, 7744 helper = $( that.helper ), 7745 ho = helper.offset(), 7746 w = helper.outerWidth() - that.sizeDiff.width, 7747 h = helper.outerHeight() - that.sizeDiff.height; 7748 7749 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) { 7750 $( this ).css({ 7751 left: ho.left - cop.left - co.left, 7752 width: w, 7753 height: h 7754 }); 7755 } 7756 7757 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) { 7758 $( this ).css({ 7759 left: ho.left - cop.left - co.left, 7760 width: w, 7761 height: h 7762 }); 7763 } 7764 } 7765 }); 7766 7767 $.ui.plugin.add("resizable", "alsoResize", { 7768 7769 start: function() { 7770 var that = $(this).resizable( "instance" ), 7771 o = that.options, 7772 _store = function(exp) { 7773 $(exp).each(function() { 7774 var el = $(this); 7775 el.data("ui-resizable-alsoresize", { 7776 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), 7777 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) 7778 }); 7779 }); 7780 }; 7781 7782 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { 7783 if (o.alsoResize.length) { 7784 o.alsoResize = o.alsoResize[0]; 7785 _store(o.alsoResize); 7786 } else { 7787 $.each(o.alsoResize, function(exp) { 7788 _store(exp); 7789 }); 7790 } 7791 } else { 7792 _store(o.alsoResize); 7793 } 7794 }, 7795 7796 resize: function(event, ui) { 7797 var that = $(this).resizable( "instance" ), 7798 o = that.options, 7799 os = that.originalSize, 7800 op = that.originalPosition, 7801 delta = { 7802 height: (that.size.height - os.height) || 0, 7803 width: (that.size.width - os.width) || 0, 7804 top: (that.position.top - op.top) || 0, 7805 left: (that.position.left - op.left) || 0 7806 }, 7807 7808 _alsoResize = function(exp, c) { 7809 $(exp).each(function() { 7810 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, 7811 css = c && c.length ? 7812 c : 7813 el.parents(ui.originalElement[0]).length ? 7814 [ "width", "height" ] : 7815 [ "width", "height", "top", "left" ]; 7816 7817 $.each(css, function(i, prop) { 7818 var sum = (start[prop] || 0) + (delta[prop] || 0); 7819 if (sum && sum >= 0) { 7820 style[prop] = sum || null; 7821 } 7822 }); 7823 7824 el.css(style); 7825 }); 7826 }; 7827 7828 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { 7829 $.each(o.alsoResize, function(exp, c) { 7830 _alsoResize(exp, c); 7831 }); 7832 } else { 7833 _alsoResize(o.alsoResize); 7834 } 7835 }, 7836 7837 stop: function() { 7838 $(this).removeData("resizable-alsoresize"); 7839 } 7840 }); 7841 7842 $.ui.plugin.add("resizable", "ghost", { 7843 7844 start: function() { 7845 7846 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size; 7847 7848 that.ghost = that.originalElement.clone(); 7849 that.ghost 7850 .css({ 7851 opacity: 0.25, 7852 display: "block", 7853 position: "relative", 7854 height: cs.height, 7855 width: cs.width, 7856 margin: 0, 7857 left: 0, 7858 top: 0 7859 }) 7860 .addClass("ui-resizable-ghost") 7861 .addClass(typeof o.ghost === "string" ? o.ghost : ""); 7862 7863 that.ghost.appendTo(that.helper); 7864 7865 }, 7866 7867 resize: function() { 7868 var that = $(this).resizable( "instance" ); 7869 if (that.ghost) { 7870 that.ghost.css({ 7871 position: "relative", 7872 height: that.size.height, 7873 width: that.size.width 7874 }); 7875 } 7876 }, 7877 7878 stop: function() { 7879 var that = $(this).resizable( "instance" ); 7880 if (that.ghost && that.helper) { 7881 that.helper.get(0).removeChild(that.ghost.get(0)); 7882 } 7883 } 7884 7885 }); 7886 7887 $.ui.plugin.add("resizable", "grid", { 7888 7889 resize: function() { 7890 var outerDimensions, 7891 that = $(this).resizable( "instance" ), 7892 o = that.options, 7893 cs = that.size, 7894 os = that.originalSize, 7895 op = that.originalPosition, 7896 a = that.axis, 7897 grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid, 7898 gridX = (grid[0] || 1), 7899 gridY = (grid[1] || 1), 7900 ox = Math.round((cs.width - os.width) / gridX) * gridX, 7901 oy = Math.round((cs.height - os.height) / gridY) * gridY, 7902 newWidth = os.width + ox, 7903 newHeight = os.height + oy, 7904 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), 7905 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), 7906 isMinWidth = o.minWidth && (o.minWidth > newWidth), 7907 isMinHeight = o.minHeight && (o.minHeight > newHeight); 7908 7909 o.grid = grid; 7910 7911 if (isMinWidth) { 7912 newWidth += gridX; 7913 } 7914 if (isMinHeight) { 7915 newHeight += gridY; 7916 } 7917 if (isMaxWidth) { 7918 newWidth -= gridX; 7919 } 7920 if (isMaxHeight) { 7921 newHeight -= gridY; 7922 } 7923 7924 if (/^(se|s|e)$/.test(a)) { 7925 that.size.width = newWidth; 7926 that.size.height = newHeight; 7927 } else if (/^(ne)$/.test(a)) { 7928 that.size.width = newWidth; 7929 that.size.height = newHeight; 7930 that.position.top = op.top - oy; 7931 } else if (/^(sw)$/.test(a)) { 7932 that.size.width = newWidth; 7933 that.size.height = newHeight; 7934 that.position.left = op.left - ox; 7935 } else { 7936 if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) { 7937 outerDimensions = that._getPaddingPlusBorderDimensions( this ); 7938 } 7939 7940 if ( newHeight - gridY > 0 ) { 7941 that.size.height = newHeight; 7942 that.position.top = op.top - oy; 7943 } else { 7944 newHeight = gridY - outerDimensions.height; 7945 that.size.height = newHeight; 7946 that.position.top = op.top + os.height - newHeight; 7947 } 7948 if ( newWidth - gridX > 0 ) { 7949 that.size.width = newWidth; 7950 that.position.left = op.left - ox; 7951 } else { 7952 newWidth = gridY - outerDimensions.height; 7953 that.size.width = newWidth; 7954 that.position.left = op.left + os.width - newWidth; 7955 } 7956 } 7957 } 7958 7959 }); 7960 7961 var resizable = $.ui.resizable; 7962 7963 7964 /*! 7965 * jQuery UI Dialog 1.11.1 7966 * http://jqueryui.com 7967 * 7968 * Copyright 2014 jQuery Foundation and other contributors 7969 * Released under the MIT license. 7970 * http://jquery.org/license 7971 * 7972 * http://api.jqueryui.com/dialog/ 7973 */ 7974 7975 7976 var dialog = $.widget( "ui.dialog", { 7977 version: "1.11.1", 7978 options: { 7979 appendTo: "body", 7980 autoOpen: true, 7981 buttons: [], 7982 closeOnEscape: true, 7983 closeText: "Close", 7984 dialogClass: "", 7985 draggable: true, 7986 hide: null, 7987 height: "auto", 7988 maxHeight: null, 7989 maxWidth: null, 7990 minHeight: 150, 7991 minWidth: 150, 7992 modal: false, 7993 position: { 7994 my: "center", 7995 at: "center", 7996 of: window, 7997 collision: "fit", 7998 // Ensure the titlebar is always visible 7999 using: function( pos ) { 8000 var topOffset = $( this ).css( pos ).offset().top; 8001 if ( topOffset < 0 ) { 8002 $( this ).css( "top", pos.top - topOffset ); 8003 } 8004 } 8005 }, 8006 resizable: true, 8007 show: null, 8008 title: null, 8009 width: 300, 8010 8011 // callbacks 8012 beforeClose: null, 8013 close: null, 8014 drag: null, 8015 dragStart: null, 8016 dragStop: null, 8017 focus: null, 8018 open: null, 8019 resize: null, 8020 resizeStart: null, 8021 resizeStop: null 8022 }, 8023 8024 sizeRelatedOptions: { 8025 buttons: true, 8026 height: true, 8027 maxHeight: true, 8028 maxWidth: true, 8029 minHeight: true, 8030 minWidth: true, 8031 width: true 8032 }, 8033 8034 resizableRelatedOptions: { 8035 maxHeight: true, 8036 maxWidth: true, 8037 minHeight: true, 8038 minWidth: true 8039 }, 8040 8041 _create: function() { 8042 this.originalCss = { 8043 display: this.element[ 0 ].style.display, 8044 width: this.element[ 0 ].style.width, 8045 minHeight: this.element[ 0 ].style.minHeight, 8046 maxHeight: this.element[ 0 ].style.maxHeight, 8047 height: this.element[ 0 ].style.height 8048 }; 8049 this.originalPosition = { 8050 parent: this.element.parent(), 8051 index: this.element.parent().children().index( this.element ) 8052 }; 8053 this.originalTitle = this.element.attr( "title" ); 8054 this.options.title = this.options.title || this.originalTitle; 8055 8056 this._createWrapper(); 8057 8058 this.element 8059 .show() 8060 .removeAttr( "title" ) 8061 .addClass( "ui-dialog-content ui-widget-content" ) 8062 .appendTo( this.uiDialog ); 8063 8064 this._createTitlebar(); 8065 this._createButtonPane(); 8066 8067 if ( this.options.draggable && $.fn.draggable ) { 8068 this._makeDraggable(); 8069 } 8070 if ( this.options.resizable && $.fn.resizable ) { 8071 this._makeResizable(); 8072 } 8073 8074 this._isOpen = false; 8075 8076 this._trackFocus(); 8077 }, 8078 8079 _init: function() { 8080 if ( this.options.autoOpen ) { 8081 this.open(); 8082 } 8083 }, 8084 8085 _appendTo: function() { 8086 var element = this.options.appendTo; 8087 if ( element && (element.jquery || element.nodeType) ) { 8088 return $( element ); 8089 } 8090 return this.document.find( element || "body" ).eq( 0 ); 8091 }, 8092 8093 _destroy: function() { 8094 var next, 8095 originalPosition = this.originalPosition; 8096 8097 this._destroyOverlay(); 8098 8099 this.element 8100 .removeUniqueId() 8101 .removeClass( "ui-dialog-content ui-widget-content" ) 8102 .css( this.originalCss ) 8103 // Without detaching first, the following becomes really slow 8104 .detach(); 8105 8106 this.uiDialog.stop( true, true ).remove(); 8107 8108 if ( this.originalTitle ) { 8109 this.element.attr( "title", this.originalTitle ); 8110 } 8111 8112 next = originalPosition.parent.children().eq( originalPosition.index ); 8113 // Don't try to place the dialog next to itself (#8613) 8114 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) { 8115 next.before( this.element ); 8116 } else { 8117 originalPosition.parent.append( this.element ); 8118 } 8119 }, 8120 8121 widget: function() { 8122 return this.uiDialog; 8123 }, 8124 8125 disable: $.noop, 8126 enable: $.noop, 8127 8128 close: function( event ) { 8129 var activeElement, 8130 that = this; 8131 8132 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) { 8133 return; 8134 } 8135 8136 this._isOpen = false; 8137 this._focusedElement = null; 8138 this._destroyOverlay(); 8139 this._untrackInstance(); 8140 8141 if ( !this.opener.filter( ":focusable" ).focus().length ) { 8142 8143 // support: IE9 8144 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe> 8145 try { 8146 activeElement = this.document[ 0 ].activeElement; 8147 8148 // Support: IE9, IE10 8149 // If the <body> is blurred, IE will switch windows, see #4520 8150 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) { 8151 8152 // Hiding a focused element doesn't trigger blur in WebKit 8153 // so in case we have nothing to focus on, explicitly blur the active element 8154 // https://bugs.webkit.org/show_bug.cgi?id=47182 8155 $( activeElement ).blur(); 8156 } 8157 } catch ( error ) {} 8158 } 8159 8160 this._hide( this.uiDialog, this.options.hide, function() { 8161 that._trigger( "close", event ); 8162 }); 8163 }, 8164 8165 isOpen: function() { 8166 return this._isOpen; 8167 }, 8168 8169 moveToTop: function() { 8170 this._moveToTop(); 8171 }, 8172 8173 _moveToTop: function( event, silent ) { 8174 var moved = false, 8175 zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() { 8176 return +$( this ).css( "z-index" ); 8177 }).get(), 8178 zIndexMax = Math.max.apply( null, zIndicies ); 8179 8180 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) { 8181 this.uiDialog.css( "z-index", zIndexMax + 1 ); 8182 moved = true; 8183 } 8184 8185 if ( moved && !silent ) { 8186 this._trigger( "focus", event ); 8187 } 8188 return moved; 8189 }, 8190 8191 open: function() { 8192 var that = this; 8193 if ( this._isOpen ) { 8194 if ( this._moveToTop() ) { 8195 this._focusTabbable(); 8196 } 8197 return; 8198 } 8199 8200 this._isOpen = true; 8201 this.opener = $( this.document[ 0 ].activeElement ); 8202 8203 this._size(); 8204 this._position(); 8205 this._createOverlay(); 8206 this._moveToTop( null, true ); 8207 8208 // Ensure the overlay is moved to the top with the dialog, but only when 8209 // opening. The overlay shouldn't move after the dialog is open so that 8210 // modeless dialogs opened after the modal dialog stack properly. 8211 if ( this.overlay ) { 8212 this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 ); 8213 } 8214 8215 this._show( this.uiDialog, this.options.show, function() { 8216 that._focusTabbable(); 8217 that._trigger( "focus" ); 8218 }); 8219 8220 // Track the dialog immediately upon openening in case a focus event 8221 // somehow occurs outside of the dialog before an element inside the 8222 // dialog is focused (#10152) 8223 this._makeFocusTarget(); 8224 8225 this._trigger( "open" ); 8226 }, 8227 8228 _focusTabbable: function() { 8229 // Set focus to the first match: 8230 // 1. An element that was focused previously 8231 // 2. First element inside the dialog matching [autofocus] 8232 // 3. Tabbable element inside the content element 8233 // 4. Tabbable element inside the buttonpane 8234 // 5. The close button 8235 // 6. The dialog itself 8236 var hasFocus = this._focusedElement; 8237 if ( !hasFocus ) { 8238 hasFocus = this.element.find( "[autofocus]" ); 8239 } 8240 if ( !hasFocus.length ) { 8241 hasFocus = this.element.find( ":tabbable" ); 8242 } 8243 if ( !hasFocus.length ) { 8244 hasFocus = this.uiDialogButtonPane.find( ":tabbable" ); 8245 } 8246 if ( !hasFocus.length ) { 8247 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" ); 8248 } 8249 if ( !hasFocus.length ) { 8250 hasFocus = this.uiDialog; 8251 } 8252 hasFocus.eq( 0 ).focus(); 8253 }, 8254 8255 _keepFocus: function( event ) { 8256 function checkFocus() { 8257 var activeElement = this.document[0].activeElement, 8258 isActive = this.uiDialog[0] === activeElement || 8259 $.contains( this.uiDialog[0], activeElement ); 8260 if ( !isActive ) { 8261 this._focusTabbable(); 8262 } 8263 } 8264 event.preventDefault(); 8265 checkFocus.call( this ); 8266 // support: IE 8267 // IE <= 8 doesn't prevent moving focus even with event.preventDefault() 8268 // so we check again later 8269 this._delay( checkFocus ); 8270 }, 8271 8272 _createWrapper: function() { 8273 this.uiDialog = $("<div>") 8274 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " + 8275 this.options.dialogClass ) 8276 .hide() 8277 .attr({ 8278 // Setting tabIndex makes the div focusable 8279 tabIndex: -1, 8280 role: "dialog" 8281 }) 8282 .appendTo( this._appendTo() ); 8283 8284 this._on( this.uiDialog, { 8285 keydown: function( event ) { 8286 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode && 8287 event.keyCode === $.ui.keyCode.ESCAPE ) { 8288 event.preventDefault(); 8289 this.close( event ); 8290 return; 8291 } 8292 8293 // prevent tabbing out of dialogs 8294 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) { 8295 return; 8296 } 8297 var tabbables = this.uiDialog.find( ":tabbable" ), 8298 first = tabbables.filter( ":first" ), 8299 last = tabbables.filter( ":last" ); 8300 8301 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) { 8302 this._delay(function() { 8303 first.focus(); 8304 }); 8305 event.preventDefault(); 8306 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) { 8307 this._delay(function() { 8308 last.focus(); 8309 }); 8310 event.preventDefault(); 8311 } 8312 }, 8313 mousedown: function( event ) { 8314 if ( this._moveToTop( event ) ) { 8315 this._focusTabbable(); 8316 } 8317 } 8318 }); 8319 8320 // We assume that any existing aria-describedby attribute means 8321 // that the dialog content is marked up properly 8322 // otherwise we brute force the content as the description 8323 if ( !this.element.find( "[aria-describedby]" ).length ) { 8324 this.uiDialog.attr({ 8325 "aria-describedby": this.element.uniqueId().attr( "id" ) 8326 }); 8327 } 8328 }, 8329 8330 _createTitlebar: function() { 8331 var uiDialogTitle; 8332 8333 this.uiDialogTitlebar = $( "<div>" ) 8334 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" ) 8335 .prependTo( this.uiDialog ); 8336 this._on( this.uiDialogTitlebar, { 8337 mousedown: function( event ) { 8338 // Don't prevent click on close button (#8838) 8339 // Focusing a dialog that is partially scrolled out of view 8340 // causes the browser to scroll it into view, preventing the click event 8341 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) { 8342 // Dialog isn't getting focus when dragging (#8063) 8343 this.uiDialog.focus(); 8344 } 8345 } 8346 }); 8347 8348 // support: IE 8349 // Use type="button" to prevent enter keypresses in textboxes from closing the 8350 // dialog in IE (#9312) 8351 this.uiDialogTitlebarClose = $( "<button type='button'></button>" ) 8352 .button({ 8353 label: this.options.closeText, 8354 icons: { 8355 primary: "ui-icon-closethick" 8356 }, 8357 text: false 8358 }) 8359 .addClass( "ui-dialog-titlebar-close" ) 8360 .appendTo( this.uiDialogTitlebar ); 8361 this._on( this.uiDialogTitlebarClose, { 8362 click: function( event ) { 8363 event.preventDefault(); 8364 this.close( event ); 8365 } 8366 }); 8367 8368 uiDialogTitle = $( "<span>" ) 8369 .uniqueId() 8370 .addClass( "ui-dialog-title" ) 8371 .prependTo( this.uiDialogTitlebar ); 8372 this._title( uiDialogTitle ); 8373 8374 this.uiDialog.attr({ 8375 "aria-labelledby": uiDialogTitle.attr( "id" ) 8376 }); 8377 }, 8378 8379 _title: function( title ) { 8380 if ( !this.options.title ) { 8381 title.html( " " ); 8382 } 8383 title.text( this.options.title ); 8384 }, 8385 8386 _createButtonPane: function() { 8387 this.uiDialogButtonPane = $( "<div>" ) 8388 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" ); 8389 8390 this.uiButtonSet = $( "<div>" ) 8391 .addClass( "ui-dialog-buttonset" ) 8392 .appendTo( this.uiDialogButtonPane ); 8393 8394 this._createButtons(); 8395 }, 8396 8397 _createButtons: function() { 8398 var that = this, 8399 buttons = this.options.buttons; 8400 8401 // if we already have a button pane, remove it 8402 this.uiDialogButtonPane.remove(); 8403 this.uiButtonSet.empty(); 8404 8405 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) { 8406 this.uiDialog.removeClass( "ui-dialog-buttons" ); 8407 return; 8408 } 8409 8410 $.each( buttons, function( name, props ) { 8411 var click, buttonOptions; 8412 props = $.isFunction( props ) ? 8413 { click: props, text: name } : 8414 props; 8415 // Default to a non-submitting button 8416 props = $.extend( { type: "button" }, props ); 8417 // Change the context for the click callback to be the main element 8418 click = props.click; 8419 props.click = function() { 8420 click.apply( that.element[ 0 ], arguments ); 8421 }; 8422 buttonOptions = { 8423 icons: props.icons, 8424 text: props.showText 8425 }; 8426 delete props.icons; 8427 delete props.showText; 8428 $( "<button></button>", props ) 8429 .button( buttonOptions ) 8430 .appendTo( that.uiButtonSet ); 8431 }); 8432 this.uiDialog.addClass( "ui-dialog-buttons" ); 8433 this.uiDialogButtonPane.appendTo( this.uiDialog ); 8434 }, 8435 8436 _makeDraggable: function() { 8437 var that = this, 8438 options = this.options; 8439 8440 function filteredUi( ui ) { 8441 return { 8442 position: ui.position, 8443 offset: ui.offset 8444 }; 8445 } 8446 8447 this.uiDialog.draggable({ 8448 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", 8449 handle: ".ui-dialog-titlebar", 8450 containment: "document", 8451 start: function( event, ui ) { 8452 $( this ).addClass( "ui-dialog-dragging" ); 8453 that._blockFrames(); 8454 that._trigger( "dragStart", event, filteredUi( ui ) ); 8455 }, 8456 drag: function( event, ui ) { 8457 that._trigger( "drag", event, filteredUi( ui ) ); 8458 }, 8459 stop: function( event, ui ) { 8460 var left = ui.offset.left - that.document.scrollLeft(), 8461 top = ui.offset.top - that.document.scrollTop(); 8462 8463 options.position = { 8464 my: "left top", 8465 at: "left" + (left >= 0 ? "+" : "") + left + " " + 8466 "top" + (top >= 0 ? "+" : "") + top, 8467 of: that.window 8468 }; 8469 $( this ).removeClass( "ui-dialog-dragging" ); 8470 that._unblockFrames(); 8471 that._trigger( "dragStop", event, filteredUi( ui ) ); 8472 } 8473 }); 8474 }, 8475 8476 _makeResizable: function() { 8477 var that = this, 8478 options = this.options, 8479 handles = options.resizable, 8480 // .ui-resizable has position: relative defined in the stylesheet 8481 // but dialogs have to use absolute or fixed positioning 8482 position = this.uiDialog.css("position"), 8483 resizeHandles = typeof handles === "string" ? 8484 handles : 8485 "n,e,s,w,se,sw,ne,nw"; 8486 8487 function filteredUi( ui ) { 8488 return { 8489 originalPosition: ui.originalPosition, 8490 originalSize: ui.originalSize, 8491 position: ui.position, 8492 size: ui.size 8493 }; 8494 } 8495 8496 this.uiDialog.resizable({ 8497 cancel: ".ui-dialog-content", 8498 containment: "document", 8499 alsoResize: this.element, 8500 maxWidth: options.maxWidth, 8501 maxHeight: options.maxHeight, 8502 minWidth: options.minWidth, 8503 minHeight: this._minHeight(), 8504 handles: resizeHandles, 8505 start: function( event, ui ) { 8506 $( this ).addClass( "ui-dialog-resizing" ); 8507 that._blockFrames(); 8508 that._trigger( "resizeStart", event, filteredUi( ui ) ); 8509 }, 8510 resize: function( event, ui ) { 8511 that._trigger( "resize", event, filteredUi( ui ) ); 8512 }, 8513 stop: function( event, ui ) { 8514 var offset = that.uiDialog.offset(), 8515 left = offset.left - that.document.scrollLeft(), 8516 top = offset.top - that.document.scrollTop(); 8517 8518 options.height = that.uiDialog.height(); 8519 options.width = that.uiDialog.width(); 8520 options.position = { 8521 my: "left top", 8522 at: "left" + (left >= 0 ? "+" : "") + left + " " + 8523 "top" + (top >= 0 ? "+" : "") + top, 8524 of: that.window 8525 }; 8526 $( this ).removeClass( "ui-dialog-resizing" ); 8527 that._unblockFrames(); 8528 that._trigger( "resizeStop", event, filteredUi( ui ) ); 8529 } 8530 }) 8531 .css( "position", position ); 8532 }, 8533 8534 _trackFocus: function() { 8535 this._on( this.widget(), { 8536 focusin: function( event ) { 8537 this._makeFocusTarget(); 8538 this._focusedElement = $( event.target ); 8539 } 8540 }); 8541 }, 8542 8543 _makeFocusTarget: function() { 8544 this._untrackInstance(); 8545 this._trackingInstances().unshift( this ); 8546 }, 8547 8548 _untrackInstance: function() { 8549 var instances = this._trackingInstances(), 8550 exists = $.inArray( this, instances ); 8551 if ( exists !== -1 ) { 8552 instances.splice( exists, 1 ); 8553 } 8554 }, 8555 8556 _trackingInstances: function() { 8557 var instances = this.document.data( "ui-dialog-instances" ); 8558 if ( !instances ) { 8559 instances = []; 8560 this.document.data( "ui-dialog-instances", instances ); 8561 } 8562 return instances; 8563 }, 8564 8565 _minHeight: function() { 8566 var options = this.options; 8567 8568 return options.height === "auto" ? 8569 options.minHeight : 8570 Math.min( options.minHeight, options.height ); 8571 }, 8572 8573 _position: function() { 8574 // Need to show the dialog to get the actual offset in the position plugin 8575 var isVisible = this.uiDialog.is( ":visible" ); 8576 if ( !isVisible ) { 8577 this.uiDialog.show(); 8578 } 8579 this.uiDialog.position( this.options.position ); 8580 if ( !isVisible ) { 8581 this.uiDialog.hide(); 8582 } 8583 }, 8584 8585 _setOptions: function( options ) { 8586 var that = this, 8587 resize = false, 8588 resizableOptions = {}; 8589 8590 $.each( options, function( key, value ) { 8591 that._setOption( key, value ); 8592 8593 if ( key in that.sizeRelatedOptions ) { 8594 resize = true; 8595 } 8596 if ( key in that.resizableRelatedOptions ) { 8597 resizableOptions[ key ] = value; 8598 } 8599 }); 8600 8601 if ( resize ) { 8602 this._size(); 8603 this._position(); 8604 } 8605 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 8606 this.uiDialog.resizable( "option", resizableOptions ); 8607 } 8608 }, 8609 8610 _setOption: function( key, value ) { 8611 var isDraggable, isResizable, 8612 uiDialog = this.uiDialog; 8613 8614 if ( key === "dialogClass" ) { 8615 uiDialog 8616 .removeClass( this.options.dialogClass ) 8617 .addClass( value ); 8618 } 8619 8620 if ( key === "disabled" ) { 8621 return; 8622 } 8623 8624 this._super( key, value ); 8625 8626 if ( key === "appendTo" ) { 8627 this.uiDialog.appendTo( this._appendTo() ); 8628 } 8629 8630 if ( key === "buttons" ) { 8631 this._createButtons(); 8632 } 8633 8634 if ( key === "closeText" ) { 8635 this.uiDialogTitlebarClose.button({ 8636 // Ensure that we always pass a string 8637 label: "" + value 8638 }); 8639 } 8640 8641 if ( key === "draggable" ) { 8642 isDraggable = uiDialog.is( ":data(ui-draggable)" ); 8643 if ( isDraggable && !value ) { 8644 uiDialog.draggable( "destroy" ); 8645 } 8646 8647 if ( !isDraggable && value ) { 8648 this._makeDraggable(); 8649 } 8650 } 8651 8652 if ( key === "position" ) { 8653 this._position(); 8654 } 8655 8656 if ( key === "resizable" ) { 8657 // currently resizable, becoming non-resizable 8658 isResizable = uiDialog.is( ":data(ui-resizable)" ); 8659 if ( isResizable && !value ) { 8660 uiDialog.resizable( "destroy" ); 8661 } 8662 8663 // currently resizable, changing handles 8664 if ( isResizable && typeof value === "string" ) { 8665 uiDialog.resizable( "option", "handles", value ); 8666 } 8667 8668 // currently non-resizable, becoming resizable 8669 if ( !isResizable && value !== false ) { 8670 this._makeResizable(); 8671 } 8672 } 8673 8674 if ( key === "title" ) { 8675 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); 8676 } 8677 }, 8678 8679 _size: function() { 8680 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content 8681 // divs will both have width and height set, so we need to reset them 8682 var nonContentHeight, minContentHeight, maxContentHeight, 8683 options = this.options; 8684 8685 // Reset content sizing 8686 this.element.show().css({ 8687 width: "auto", 8688 minHeight: 0, 8689 maxHeight: "none", 8690 height: 0 8691 }); 8692 8693 if ( options.minWidth > options.width ) { 8694 options.width = options.minWidth; 8695 } 8696 8697 // reset wrapper sizing 8698 // determine the height of all the non-content elements 8699 nonContentHeight = this.uiDialog.css({ 8700 height: "auto", 8701 width: options.width 8702 }) 8703 .outerHeight(); 8704 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); 8705 maxContentHeight = typeof options.maxHeight === "number" ? 8706 Math.max( 0, options.maxHeight - nonContentHeight ) : 8707 "none"; 8708 8709 if ( options.height === "auto" ) { 8710 this.element.css({ 8711 minHeight: minContentHeight, 8712 maxHeight: maxContentHeight, 8713 height: "auto" 8714 }); 8715 } else { 8716 this.element.height( Math.max( 0, options.height - nonContentHeight ) ); 8717 } 8718 8719 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { 8720 this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); 8721 } 8722 }, 8723 8724 _blockFrames: function() { 8725 this.iframeBlocks = this.document.find( "iframe" ).map(function() { 8726 var iframe = $( this ); 8727 8728 return $( "<div>" ) 8729 .css({ 8730 position: "absolute", 8731 width: iframe.outerWidth(), 8732 height: iframe.outerHeight() 8733 }) 8734 .appendTo( iframe.parent() ) 8735 .offset( iframe.offset() )[0]; 8736 }); 8737 }, 8738 8739 _unblockFrames: function() { 8740 if ( this.iframeBlocks ) { 8741 this.iframeBlocks.remove(); 8742 delete this.iframeBlocks; 8743 } 8744 }, 8745 8746 _allowInteraction: function( event ) { 8747 if ( $( event.target ).closest( ".ui-dialog" ).length ) { 8748 return true; 8749 } 8750 8751 // TODO: Remove hack when datepicker implements 8752 // the .ui-front logic (#8989) 8753 return !!$( event.target ).closest( ".ui-datepicker" ).length; 8754 }, 8755 8756 _createOverlay: function() { 8757 if ( !this.options.modal ) { 8758 return; 8759 } 8760 8761 // We use a delay in case the overlay is created from an 8762 // event that we're going to be cancelling (#2804) 8763 var isOpening = true; 8764 this._delay(function() { 8765 isOpening = false; 8766 }); 8767 8768 if ( !this.document.data( "ui-dialog-overlays" ) ) { 8769 8770 // Prevent use of anchors and inputs 8771 // Using _on() for an event handler shared across many instances is 8772 // safe because the dialogs stack and must be closed in reverse order 8773 this._on( this.document, { 8774 focusin: function( event ) { 8775 if ( isOpening ) { 8776 return; 8777 } 8778 8779 if ( !this._allowInteraction( event ) ) { 8780 event.preventDefault(); 8781 this._trackingInstances()[ 0 ]._focusTabbable(); 8782 } 8783 } 8784 }); 8785 } 8786 8787 this.overlay = $( "<div>" ) 8788 .addClass( "ui-widget-overlay ui-front" ) 8789 .appendTo( this._appendTo() ); 8790 this._on( this.overlay, { 8791 mousedown: "_keepFocus" 8792 }); 8793 this.document.data( "ui-dialog-overlays", 8794 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 ); 8795 }, 8796 8797 _destroyOverlay: function() { 8798 if ( !this.options.modal ) { 8799 return; 8800 } 8801 8802 if ( this.overlay ) { 8803 var overlays = this.document.data( "ui-dialog-overlays" ) - 1; 8804 8805 if ( !overlays ) { 8806 this.document 8807 .unbind( "focusin" ) 8808 .removeData( "ui-dialog-overlays" ); 8809 } else { 8810 this.document.data( "ui-dialog-overlays", overlays ); 8811 } 8812 8813 this.overlay.remove(); 8814 this.overlay = null; 8815 } 8816 } 8817 }); 8818 8819 8820 /*! 8821 * jQuery UI Droppable 1.11.1 8822 * http://jqueryui.com 8823 * 8824 * Copyright 2014 jQuery Foundation and other contributors 8825 * Released under the MIT license. 8826 * http://jquery.org/license 8827 * 8828 * http://api.jqueryui.com/droppable/ 8829 */ 8830 8831 8832 $.widget( "ui.droppable", { 8833 version: "1.11.1", 8834 widgetEventPrefix: "drop", 8835 options: { 8836 accept: "*", 8837 activeClass: false, 8838 addClasses: true, 8839 greedy: false, 8840 hoverClass: false, 8841 scope: "default", 8842 tolerance: "intersect", 8843 8844 // callbacks 8845 activate: null, 8846 deactivate: null, 8847 drop: null, 8848 out: null, 8849 over: null 8850 }, 8851 _create: function() { 8852 8853 var proportions, 8854 o = this.options, 8855 accept = o.accept; 8856 8857 this.isover = false; 8858 this.isout = true; 8859 8860 this.accept = $.isFunction( accept ) ? accept : function( d ) { 8861 return d.is( accept ); 8862 }; 8863 8864 this.proportions = function( /* valueToWrite */ ) { 8865 if ( arguments.length ) { 8866 // Store the droppable's proportions 8867 proportions = arguments[ 0 ]; 8868 } else { 8869 // Retrieve or derive the droppable's proportions 8870 return proportions ? 8871 proportions : 8872 proportions = { 8873 width: this.element[ 0 ].offsetWidth, 8874 height: this.element[ 0 ].offsetHeight 8875 }; 8876 } 8877 }; 8878 8879 this._addToManager( o.scope ); 8880 8881 o.addClasses && this.element.addClass( "ui-droppable" ); 8882 8883 }, 8884 8885 _addToManager: function( scope ) { 8886 // Add the reference and positions to the manager 8887 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; 8888 $.ui.ddmanager.droppables[ scope ].push( this ); 8889 }, 8890 8891 _splice: function( drop ) { 8892 var i = 0; 8893 for ( ; i < drop.length; i++ ) { 8894 if ( drop[ i ] === this ) { 8895 drop.splice( i, 1 ); 8896 } 8897 } 8898 }, 8899 8900 _destroy: function() { 8901 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 8902 8903 this._splice( drop ); 8904 8905 this.element.removeClass( "ui-droppable ui-droppable-disabled" ); 8906 }, 8907 8908 _setOption: function( key, value ) { 8909 8910 if ( key === "accept" ) { 8911 this.accept = $.isFunction( value ) ? value : function( d ) { 8912 return d.is( value ); 8913 }; 8914 } else if ( key === "scope" ) { 8915 var drop = $.ui.ddmanager.droppables[ this.options.scope ]; 8916 8917 this._splice( drop ); 8918 this._addToManager( value ); 8919 } 8920 8921 this._super( key, value ); 8922 }, 8923 8924 _activate: function( event ) { 8925 var draggable = $.ui.ddmanager.current; 8926 if ( this.options.activeClass ) { 8927 this.element.addClass( this.options.activeClass ); 8928 } 8929 if ( draggable ){ 8930 this._trigger( "activate", event, this.ui( draggable ) ); 8931 } 8932 }, 8933 8934 _deactivate: function( event ) { 8935 var draggable = $.ui.ddmanager.current; 8936 if ( this.options.activeClass ) { 8937 this.element.removeClass( this.options.activeClass ); 8938 } 8939 if ( draggable ){ 8940 this._trigger( "deactivate", event, this.ui( draggable ) ); 8941 } 8942 }, 8943 8944 _over: function( event ) { 8945 8946 var draggable = $.ui.ddmanager.current; 8947 8948 // Bail if draggable and droppable are same element 8949 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { 8950 return; 8951 } 8952 8953 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 8954 if ( this.options.hoverClass ) { 8955 this.element.addClass( this.options.hoverClass ); 8956 } 8957 this._trigger( "over", event, this.ui( draggable ) ); 8958 } 8959 8960 }, 8961 8962 _out: function( event ) { 8963 8964 var draggable = $.ui.ddmanager.current; 8965 8966 // Bail if draggable and droppable are same element 8967 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { 8968 return; 8969 } 8970 8971 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 8972 if ( this.options.hoverClass ) { 8973 this.element.removeClass( this.options.hoverClass ); 8974 } 8975 this._trigger( "out", event, this.ui( draggable ) ); 8976 } 8977 8978 }, 8979 8980 _drop: function( event, custom ) { 8981 8982 var draggable = custom || $.ui.ddmanager.current, 8983 childrenIntersection = false; 8984 8985 // Bail if draggable and droppable are same element 8986 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) { 8987 return false; 8988 } 8989 8990 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() { 8991 var inst = $( this ).droppable( "instance" ); 8992 if ( 8993 inst.options.greedy && 8994 !inst.options.disabled && 8995 inst.options.scope === draggable.options.scope && 8996 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) && 8997 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event ) 8998 ) { childrenIntersection = true; return false; } 8999 }); 9000 if ( childrenIntersection ) { 9001 return false; 9002 } 9003 9004 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 9005 if ( this.options.activeClass ) { 9006 this.element.removeClass( this.options.activeClass ); 9007 } 9008 if ( this.options.hoverClass ) { 9009 this.element.removeClass( this.options.hoverClass ); 9010 } 9011 this._trigger( "drop", event, this.ui( draggable ) ); 9012 return this.element; 9013 } 9014 9015 return false; 9016 9017 }, 9018 9019 ui: function( c ) { 9020 return { 9021 draggable: ( c.currentItem || c.element ), 9022 helper: c.helper, 9023 position: c.position, 9024 offset: c.positionAbs 9025 }; 9026 } 9027 9028 }); 9029 9030 $.ui.intersect = (function() { 9031 function isOverAxis( x, reference, size ) { 9032 return ( x >= reference ) && ( x < ( reference + size ) ); 9033 } 9034 9035 return function( draggable, droppable, toleranceMode, event ) { 9036 9037 if ( !droppable.offset ) { 9038 return false; 9039 } 9040 9041 var x1 = ( draggable.positionAbs || draggable.position.absolute ).left, 9042 y1 = ( draggable.positionAbs || draggable.position.absolute ).top, 9043 x2 = x1 + draggable.helperProportions.width, 9044 y2 = y1 + draggable.helperProportions.height, 9045 l = droppable.offset.left, 9046 t = droppable.offset.top, 9047 r = l + droppable.proportions().width, 9048 b = t + droppable.proportions().height; 9049 9050 switch ( toleranceMode ) { 9051 case "fit": 9052 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); 9053 case "intersect": 9054 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half 9055 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half 9056 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half 9057 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half 9058 case "pointer": 9059 return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width ); 9060 case "touch": 9061 return ( 9062 ( y1 >= t && y1 <= b ) || // Top edge touching 9063 ( y2 >= t && y2 <= b ) || // Bottom edge touching 9064 ( y1 < t && y2 > b ) // Surrounded vertically 9065 ) && ( 9066 ( x1 >= l && x1 <= r ) || // Left edge touching 9067 ( x2 >= l && x2 <= r ) || // Right edge touching 9068 ( x1 < l && x2 > r ) // Surrounded horizontally 9069 ); 9070 default: 9071 return false; 9072 } 9073 }; 9074 })(); 9075 9076 /* 9077 This manager tracks offsets of draggables and droppables 9078 */ 9079 $.ui.ddmanager = { 9080 current: null, 9081 droppables: { "default": [] }, 9082 prepareOffsets: function( t, event ) { 9083 9084 var i, j, 9085 m = $.ui.ddmanager.droppables[ t.options.scope ] || [], 9086 type = event ? event.type : null, // workaround for #2317 9087 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); 9088 9089 droppablesLoop: for ( i = 0; i < m.length; i++ ) { 9090 9091 // No disabled and non-accepted 9092 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) { 9093 continue; 9094 } 9095 9096 // Filter out elements in the current dragged item 9097 for ( j = 0; j < list.length; j++ ) { 9098 if ( list[ j ] === m[ i ].element[ 0 ] ) { 9099 m[ i ].proportions().height = 0; 9100 continue droppablesLoop; 9101 } 9102 } 9103 9104 m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; 9105 if ( !m[ i ].visible ) { 9106 continue; 9107 } 9108 9109 // Activate the droppable if used directly from draggables 9110 if ( type === "mousedown" ) { 9111 m[ i ]._activate.call( m[ i ], event ); 9112 } 9113 9114 m[ i ].offset = m[ i ].element.offset(); 9115 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight }); 9116 9117 } 9118 9119 }, 9120 drop: function( draggable, event ) { 9121 9122 var dropped = false; 9123 // Create a copy of the droppables in case the list changes during the drop (#9116) 9124 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { 9125 9126 if ( !this.options ) { 9127 return; 9128 } 9129 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { 9130 dropped = this._drop.call( this, event ) || dropped; 9131 } 9132 9133 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) { 9134 this.isout = true; 9135 this.isover = false; 9136 this._deactivate.call( this, event ); 9137 } 9138 9139 }); 9140 return dropped; 9141 9142 }, 9143 dragStart: function( draggable, event ) { 9144 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) 9145 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { 9146 if ( !draggable.options.refreshPositions ) { 9147 $.ui.ddmanager.prepareOffsets( draggable, event ); 9148 } 9149 }); 9150 }, 9151 drag: function( draggable, event ) { 9152 9153 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. 9154 if ( draggable.options.refreshPositions ) { 9155 $.ui.ddmanager.prepareOffsets( draggable, event ); 9156 } 9157 9158 // Run through all droppables and check their positions based on specific tolerance options 9159 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { 9160 9161 if ( this.options.disabled || this.greedyChild || !this.visible ) { 9162 return; 9163 } 9164 9165 var parentInstance, scope, parent, 9166 intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), 9167 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null ); 9168 if ( !c ) { 9169 return; 9170 } 9171 9172 if ( this.options.greedy ) { 9173 // find droppable parents with same scope 9174 scope = this.options.scope; 9175 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() { 9176 return $( this ).droppable( "instance" ).options.scope === scope; 9177 }); 9178 9179 if ( parent.length ) { 9180 parentInstance = $( parent[ 0 ] ).droppable( "instance" ); 9181 parentInstance.greedyChild = ( c === "isover" ); 9182 } 9183 } 9184 9185 // we just moved into a greedy child 9186 if ( parentInstance && c === "isover" ) { 9187 parentInstance.isover = false; 9188 parentInstance.isout = true; 9189 parentInstance._out.call( parentInstance, event ); 9190 } 9191 9192 this[ c ] = true; 9193 this[c === "isout" ? "isover" : "isout"] = false; 9194 this[c === "isover" ? "_over" : "_out"].call( this, event ); 9195 9196 // we just moved out of a greedy child 9197 if ( parentInstance && c === "isout" ) { 9198 parentInstance.isout = false; 9199 parentInstance.isover = true; 9200 parentInstance._over.call( parentInstance, event ); 9201 } 9202 }); 9203 9204 }, 9205 dragStop: function( draggable, event ) { 9206 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); 9207 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) 9208 if ( !draggable.options.refreshPositions ) { 9209 $.ui.ddmanager.prepareOffsets( draggable, event ); 9210 } 9211 } 9212 }; 9213 9214 var droppable = $.ui.droppable; 9215 9216 9217 /*! 9218 * jQuery UI Effects 1.11.1 9219 * http://jqueryui.com 9220 * 9221 * Copyright 2014 jQuery Foundation and other contributors 9222 * Released under the MIT license. 9223 * http://jquery.org/license 9224 * 9225 * http://api.jqueryui.com/category/effects-core/ 9226 */ 9227 9228 9229 var dataSpace = "ui-effects-", 9230 9231 // Create a local jQuery because jQuery Color relies on it and the 9232 // global may not exist with AMD and a custom build (#10199) 9233 jQuery = $; 9234 9235 $.effects = { 9236 effect: {} 9237 }; 9238 9239 /*! 9240 * jQuery Color Animations v2.1.2 9241 * https://github.com/jquery/jquery-color 9242 * 9243 * Copyright 2014 jQuery Foundation and other contributors 9244 * Released under the MIT license. 9245 * http://jquery.org/license 9246 * 9247 * Date: Wed Jan 16 08:47:09 2013 -0600 9248 */ 9249 (function( jQuery, undefined ) { 9250 9251 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", 9252 9253 // plusequals test for += 100 -= 100 9254 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, 9255 // a set of RE's that can match strings and generate color tuples. 9256 stringParsers = [ { 9257 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 9258 parse: function( execResult ) { 9259 return [ 9260 execResult[ 1 ], 9261 execResult[ 2 ], 9262 execResult[ 3 ], 9263 execResult[ 4 ] 9264 ]; 9265 } 9266 }, { 9267 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 9268 parse: function( execResult ) { 9269 return [ 9270 execResult[ 1 ] * 2.55, 9271 execResult[ 2 ] * 2.55, 9272 execResult[ 3 ] * 2.55, 9273 execResult[ 4 ] 9274 ]; 9275 } 9276 }, { 9277 // this regex ignores A-F because it's compared against an already lowercased string 9278 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, 9279 parse: function( execResult ) { 9280 return [ 9281 parseInt( execResult[ 1 ], 16 ), 9282 parseInt( execResult[ 2 ], 16 ), 9283 parseInt( execResult[ 3 ], 16 ) 9284 ]; 9285 } 9286 }, { 9287 // this regex ignores A-F because it's compared against an already lowercased string 9288 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, 9289 parse: function( execResult ) { 9290 return [ 9291 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), 9292 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), 9293 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) 9294 ]; 9295 } 9296 }, { 9297 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, 9298 space: "hsla", 9299 parse: function( execResult ) { 9300 return [ 9301 execResult[ 1 ], 9302 execResult[ 2 ] / 100, 9303 execResult[ 3 ] / 100, 9304 execResult[ 4 ] 9305 ]; 9306 } 9307 } ], 9308 9309 // jQuery.Color( ) 9310 color = jQuery.Color = function( color, green, blue, alpha ) { 9311 return new jQuery.Color.fn.parse( color, green, blue, alpha ); 9312 }, 9313 spaces = { 9314 rgba: { 9315 props: { 9316 red: { 9317 idx: 0, 9318 type: "byte" 9319 }, 9320 green: { 9321 idx: 1, 9322 type: "byte" 9323 }, 9324 blue: { 9325 idx: 2, 9326 type: "byte" 9327 } 9328 } 9329 }, 9330 9331 hsla: { 9332 props: { 9333 hue: { 9334 idx: 0, 9335 type: "degrees" 9336 }, 9337 saturation: { 9338 idx: 1, 9339 type: "percent" 9340 }, 9341 lightness: { 9342 idx: 2, 9343 type: "percent" 9344 } 9345 } 9346 } 9347 }, 9348 propTypes = { 9349 "byte": { 9350 floor: true, 9351 max: 255 9352 }, 9353 "percent": { 9354 max: 1 9355 }, 9356 "degrees": { 9357 mod: 360, 9358 floor: true 9359 } 9360 }, 9361 support = color.support = {}, 9362 9363 // element for support tests 9364 supportElem = jQuery( "<p>" )[ 0 ], 9365 9366 // colors = jQuery.Color.names 9367 colors, 9368 9369 // local aliases of functions called often 9370 each = jQuery.each; 9371 9372 // determine rgba support immediately 9373 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; 9374 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; 9375 9376 // define cache name and alpha properties 9377 // for rgba and hsla spaces 9378 each( spaces, function( spaceName, space ) { 9379 space.cache = "_" + spaceName; 9380 space.props.alpha = { 9381 idx: 3, 9382 type: "percent", 9383 def: 1 9384 }; 9385 }); 9386 9387 function clamp( value, prop, allowEmpty ) { 9388 var type = propTypes[ prop.type ] || {}; 9389 9390 if ( value == null ) { 9391 return (allowEmpty || !prop.def) ? null : prop.def; 9392 } 9393 9394 // ~~ is an short way of doing floor for positive numbers 9395 value = type.floor ? ~~value : parseFloat( value ); 9396 9397 // IE will pass in empty strings as value for alpha, 9398 // which will hit this case 9399 if ( isNaN( value ) ) { 9400 return prop.def; 9401 } 9402 9403 if ( type.mod ) { 9404 // we add mod before modding to make sure that negatives values 9405 // get converted properly: -10 -> 350 9406 return (value + type.mod) % type.mod; 9407 } 9408 9409 // for now all property types without mod have min and max 9410 return 0 > value ? 0 : type.max < value ? type.max : value; 9411 } 9412 9413 function stringParse( string ) { 9414 var inst = color(), 9415 rgba = inst._rgba = []; 9416 9417 string = string.toLowerCase(); 9418 9419 each( stringParsers, function( i, parser ) { 9420 var parsed, 9421 match = parser.re.exec( string ), 9422 values = match && parser.parse( match ), 9423 spaceName = parser.space || "rgba"; 9424 9425 if ( values ) { 9426 parsed = inst[ spaceName ]( values ); 9427 9428 // if this was an rgba parse the assignment might happen twice 9429 // oh well.... 9430 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; 9431 rgba = inst._rgba = parsed._rgba; 9432 9433 // exit each( stringParsers ) here because we matched 9434 return false; 9435 } 9436 }); 9437 9438 // Found a stringParser that handled it 9439 if ( rgba.length ) { 9440 9441 // if this came from a parsed string, force "transparent" when alpha is 0 9442 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) 9443 if ( rgba.join() === "0,0,0,0" ) { 9444 jQuery.extend( rgba, colors.transparent ); 9445 } 9446 return inst; 9447 } 9448 9449 // named colors 9450 return colors[ string ]; 9451 } 9452 9453 color.fn = jQuery.extend( color.prototype, { 9454 parse: function( red, green, blue, alpha ) { 9455 if ( red === undefined ) { 9456 this._rgba = [ null, null, null, null ]; 9457 return this; 9458 } 9459 if ( red.jquery || red.nodeType ) { 9460 red = jQuery( red ).css( green ); 9461 green = undefined; 9462 } 9463 9464 var inst = this, 9465 type = jQuery.type( red ), 9466 rgba = this._rgba = []; 9467 9468 // more than 1 argument specified - assume ( red, green, blue, alpha ) 9469 if ( green !== undefined ) { 9470 red = [ red, green, blue, alpha ]; 9471 type = "array"; 9472 } 9473 9474 if ( type === "string" ) { 9475 return this.parse( stringParse( red ) || colors._default ); 9476 } 9477 9478 if ( type === "array" ) { 9479 each( spaces.rgba.props, function( key, prop ) { 9480 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); 9481 }); 9482 return this; 9483 } 9484 9485 if ( type === "object" ) { 9486 if ( red instanceof color ) { 9487 each( spaces, function( spaceName, space ) { 9488 if ( red[ space.cache ] ) { 9489 inst[ space.cache ] = red[ space.cache ].slice(); 9490 } 9491 }); 9492 } else { 9493 each( spaces, function( spaceName, space ) { 9494 var cache = space.cache; 9495 each( space.props, function( key, prop ) { 9496 9497 // if the cache doesn't exist, and we know how to convert 9498 if ( !inst[ cache ] && space.to ) { 9499 9500 // if the value was null, we don't need to copy it 9501 // if the key was alpha, we don't need to copy it either 9502 if ( key === "alpha" || red[ key ] == null ) { 9503 return; 9504 } 9505 inst[ cache ] = space.to( inst._rgba ); 9506 } 9507 9508 // this is the only case where we allow nulls for ALL properties. 9509 // call clamp with alwaysAllowEmpty 9510 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); 9511 }); 9512 9513 // everything defined but alpha? 9514 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { 9515 // use the default of 1 9516 inst[ cache ][ 3 ] = 1; 9517 if ( space.from ) { 9518 inst._rgba = space.from( inst[ cache ] ); 9519 } 9520 } 9521 }); 9522 } 9523 return this; 9524 } 9525 }, 9526 is: function( compare ) { 9527 var is = color( compare ), 9528 same = true, 9529 inst = this; 9530 9531 each( spaces, function( _, space ) { 9532 var localCache, 9533 isCache = is[ space.cache ]; 9534 if (isCache) { 9535 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; 9536 each( space.props, function( _, prop ) { 9537 if ( isCache[ prop.idx ] != null ) { 9538 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); 9539 return same; 9540 } 9541 }); 9542 } 9543 return same; 9544 }); 9545 return same; 9546 }, 9547 _space: function() { 9548 var used = [], 9549 inst = this; 9550 each( spaces, function( spaceName, space ) { 9551 if ( inst[ space.cache ] ) { 9552 used.push( spaceName ); 9553 } 9554 }); 9555 return used.pop(); 9556 }, 9557 transition: function( other, distance ) { 9558 var end = color( other ), 9559 spaceName = end._space(), 9560 space = spaces[ spaceName ], 9561 startColor = this.alpha() === 0 ? color( "transparent" ) : this, 9562 start = startColor[ space.cache ] || space.to( startColor._rgba ), 9563 result = start.slice(); 9564 9565 end = end[ space.cache ]; 9566 each( space.props, function( key, prop ) { 9567 var index = prop.idx, 9568 startValue = start[ index ], 9569 endValue = end[ index ], 9570 type = propTypes[ prop.type ] || {}; 9571 9572 // if null, don't override start value 9573 if ( endValue === null ) { 9574 return; 9575 } 9576 // if null - use end 9577 if ( startValue === null ) { 9578 result[ index ] = endValue; 9579 } else { 9580 if ( type.mod ) { 9581 if ( endValue - startValue > type.mod / 2 ) { 9582 startValue += type.mod; 9583 } else if ( startValue - endValue > type.mod / 2 ) { 9584 startValue -= type.mod; 9585 } 9586 } 9587 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); 9588 } 9589 }); 9590 return this[ spaceName ]( result ); 9591 }, 9592 blend: function( opaque ) { 9593 // if we are already opaque - return ourself 9594 if ( this._rgba[ 3 ] === 1 ) { 9595 return this; 9596 } 9597 9598 var rgb = this._rgba.slice(), 9599 a = rgb.pop(), 9600 blend = color( opaque )._rgba; 9601 9602 return color( jQuery.map( rgb, function( v, i ) { 9603 return ( 1 - a ) * blend[ i ] + a * v; 9604 })); 9605 }, 9606 toRgbaString: function() { 9607 var prefix = "rgba(", 9608 rgba = jQuery.map( this._rgba, function( v, i ) { 9609 return v == null ? ( i > 2 ? 1 : 0 ) : v; 9610 }); 9611 9612 if ( rgba[ 3 ] === 1 ) { 9613 rgba.pop(); 9614 prefix = "rgb("; 9615 } 9616 9617 return prefix + rgba.join() + ")"; 9618 }, 9619 toHslaString: function() { 9620 var prefix = "hsla(", 9621 hsla = jQuery.map( this.hsla(), function( v, i ) { 9622 if ( v == null ) { 9623 v = i > 2 ? 1 : 0; 9624 } 9625 9626 // catch 1 and 2 9627 if ( i && i < 3 ) { 9628 v = Math.round( v * 100 ) + "%"; 9629 } 9630 return v; 9631 }); 9632 9633 if ( hsla[ 3 ] === 1 ) { 9634 hsla.pop(); 9635 prefix = "hsl("; 9636 } 9637 return prefix + hsla.join() + ")"; 9638 }, 9639 toHexString: function( includeAlpha ) { 9640 var rgba = this._rgba.slice(), 9641 alpha = rgba.pop(); 9642 9643 if ( includeAlpha ) { 9644 rgba.push( ~~( alpha * 255 ) ); 9645 } 9646 9647 return "#" + jQuery.map( rgba, function( v ) { 9648 9649 // default to 0 when nulls exist 9650 v = ( v || 0 ).toString( 16 ); 9651 return v.length === 1 ? "0" + v : v; 9652 }).join(""); 9653 }, 9654 toString: function() { 9655 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); 9656 } 9657 }); 9658 color.fn.parse.prototype = color.fn; 9659 9660 // hsla conversions adapted from: 9661 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 9662 9663 function hue2rgb( p, q, h ) { 9664 h = ( h + 1 ) % 1; 9665 if ( h * 6 < 1 ) { 9666 return p + ( q - p ) * h * 6; 9667 } 9668 if ( h * 2 < 1) { 9669 return q; 9670 } 9671 if ( h * 3 < 2 ) { 9672 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; 9673 } 9674 return p; 9675 } 9676 9677 spaces.hsla.to = function( rgba ) { 9678 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { 9679 return [ null, null, null, rgba[ 3 ] ]; 9680 } 9681 var r = rgba[ 0 ] / 255, 9682 g = rgba[ 1 ] / 255, 9683 b = rgba[ 2 ] / 255, 9684 a = rgba[ 3 ], 9685 max = Math.max( r, g, b ), 9686 min = Math.min( r, g, b ), 9687 diff = max - min, 9688 add = max + min, 9689 l = add * 0.5, 9690 h, s; 9691 9692 if ( min === max ) { 9693 h = 0; 9694 } else if ( r === max ) { 9695 h = ( 60 * ( g - b ) / diff ) + 360; 9696 } else if ( g === max ) { 9697 h = ( 60 * ( b - r ) / diff ) + 120; 9698 } else { 9699 h = ( 60 * ( r - g ) / diff ) + 240; 9700 } 9701 9702 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% 9703 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) 9704 if ( diff === 0 ) { 9705 s = 0; 9706 } else if ( l <= 0.5 ) { 9707 s = diff / add; 9708 } else { 9709 s = diff / ( 2 - add ); 9710 } 9711 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; 9712 }; 9713 9714 spaces.hsla.from = function( hsla ) { 9715 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { 9716 return [ null, null, null, hsla[ 3 ] ]; 9717 } 9718 var h = hsla[ 0 ] / 360, 9719 s = hsla[ 1 ], 9720 l = hsla[ 2 ], 9721 a = hsla[ 3 ], 9722 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, 9723 p = 2 * l - q; 9724 9725 return [ 9726 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), 9727 Math.round( hue2rgb( p, q, h ) * 255 ), 9728 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), 9729 a 9730 ]; 9731 }; 9732 9733 each( spaces, function( spaceName, space ) { 9734 var props = space.props, 9735 cache = space.cache, 9736 to = space.to, 9737 from = space.from; 9738 9739 // makes rgba() and hsla() 9740 color.fn[ spaceName ] = function( value ) { 9741 9742 // generate a cache for this space if it doesn't exist 9743 if ( to && !this[ cache ] ) { 9744 this[ cache ] = to( this._rgba ); 9745 } 9746 if ( value === undefined ) { 9747 return this[ cache ].slice(); 9748 } 9749 9750 var ret, 9751 type = jQuery.type( value ), 9752 arr = ( type === "array" || type === "object" ) ? value : arguments, 9753 local = this[ cache ].slice(); 9754 9755 each( props, function( key, prop ) { 9756 var val = arr[ type === "object" ? key : prop.idx ]; 9757 if ( val == null ) { 9758 val = local[ prop.idx ]; 9759 } 9760 local[ prop.idx ] = clamp( val, prop ); 9761 }); 9762 9763 if ( from ) { 9764 ret = color( from( local ) ); 9765 ret[ cache ] = local; 9766 return ret; 9767 } else { 9768 return color( local ); 9769 } 9770 }; 9771 9772 // makes red() green() blue() alpha() hue() saturation() lightness() 9773 each( props, function( key, prop ) { 9774 // alpha is included in more than one space 9775 if ( color.fn[ key ] ) { 9776 return; 9777 } 9778 color.fn[ key ] = function( value ) { 9779 var vtype = jQuery.type( value ), 9780 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), 9781 local = this[ fn ](), 9782 cur = local[ prop.idx ], 9783 match; 9784 9785 if ( vtype === "undefined" ) { 9786 return cur; 9787 } 9788 9789 if ( vtype === "function" ) { 9790 value = value.call( this, cur ); 9791 vtype = jQuery.type( value ); 9792 } 9793 if ( value == null && prop.empty ) { 9794 return this; 9795 } 9796 if ( vtype === "string" ) { 9797 match = rplusequals.exec( value ); 9798 if ( match ) { 9799 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); 9800 } 9801 } 9802 local[ prop.idx ] = value; 9803 return this[ fn ]( local ); 9804 }; 9805 }); 9806 }); 9807 9808 // add cssHook and .fx.step function for each named hook. 9809 // accept a space separated string of properties 9810 color.hook = function( hook ) { 9811 var hooks = hook.split( " " ); 9812 each( hooks, function( i, hook ) { 9813 jQuery.cssHooks[ hook ] = { 9814 set: function( elem, value ) { 9815 var parsed, curElem, 9816 backgroundColor = ""; 9817 9818 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { 9819 value = color( parsed || value ); 9820 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { 9821 curElem = hook === "backgroundColor" ? elem.parentNode : elem; 9822 while ( 9823 (backgroundColor === "" || backgroundColor === "transparent") && 9824 curElem && curElem.style 9825 ) { 9826 try { 9827 backgroundColor = jQuery.css( curElem, "backgroundColor" ); 9828 curElem = curElem.parentNode; 9829 } catch ( e ) { 9830 } 9831 } 9832 9833 value = value.blend( backgroundColor && backgroundColor !== "transparent" ? 9834 backgroundColor : 9835 "_default" ); 9836 } 9837 9838 value = value.toRgbaString(); 9839 } 9840 try { 9841 elem.style[ hook ] = value; 9842 } catch( e ) { 9843 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' 9844 } 9845 } 9846 }; 9847 jQuery.fx.step[ hook ] = function( fx ) { 9848 if ( !fx.colorInit ) { 9849 fx.start = color( fx.elem, hook ); 9850 fx.end = color( fx.end ); 9851 fx.colorInit = true; 9852 } 9853 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); 9854 }; 9855 }); 9856 9857 }; 9858 9859 color.hook( stepHooks ); 9860 9861 jQuery.cssHooks.borderColor = { 9862 expand: function( value ) { 9863 var expanded = {}; 9864 9865 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { 9866 expanded[ "border" + part + "Color" ] = value; 9867 }); 9868 return expanded; 9869 } 9870 }; 9871 9872 // Basic color names only. 9873 // Usage of any of the other color names requires adding yourself or including 9874 // jquery.color.svg-names.js. 9875 colors = jQuery.Color.names = { 9876 // 4.1. Basic color keywords 9877 aqua: "#00ffff", 9878 black: "#000000", 9879 blue: "#0000ff", 9880 fuchsia: "#ff00ff", 9881 gray: "#808080", 9882 green: "#008000", 9883 lime: "#00ff00", 9884 maroon: "#800000", 9885 navy: "#000080", 9886 olive: "#808000", 9887 purple: "#800080", 9888 red: "#ff0000", 9889 silver: "#c0c0c0", 9890 teal: "#008080", 9891 white: "#ffffff", 9892 yellow: "#ffff00", 9893 9894 // 4.2.3. "transparent" color keyword 9895 transparent: [ null, null, null, 0 ], 9896 9897 _default: "#ffffff" 9898 }; 9899 9900 })( jQuery ); 9901 9902 /******************************************************************************/ 9903 /****************************** CLASS ANIMATIONS ******************************/ 9904 /******************************************************************************/ 9905 (function() { 9906 9907 var classAnimationActions = [ "add", "remove", "toggle" ], 9908 shorthandStyles = { 9909 border: 1, 9910 borderBottom: 1, 9911 borderColor: 1, 9912 borderLeft: 1, 9913 borderRight: 1, 9914 borderTop: 1, 9915 borderWidth: 1, 9916 margin: 1, 9917 padding: 1 9918 }; 9919 9920 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { 9921 $.fx.step[ prop ] = function( fx ) { 9922 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { 9923 jQuery.style( fx.elem, prop, fx.end ); 9924 fx.setAttr = true; 9925 } 9926 }; 9927 }); 9928 9929 function getElementStyles( elem ) { 9930 var key, len, 9931 style = elem.ownerDocument.defaultView ? 9932 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : 9933 elem.currentStyle, 9934 styles = {}; 9935 9936 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { 9937 len = style.length; 9938 while ( len-- ) { 9939 key = style[ len ]; 9940 if ( typeof style[ key ] === "string" ) { 9941 styles[ $.camelCase( key ) ] = style[ key ]; 9942 } 9943 } 9944 // support: Opera, IE <9 9945 } else { 9946 for ( key in style ) { 9947 if ( typeof style[ key ] === "string" ) { 9948 styles[ key ] = style[ key ]; 9949 } 9950 } 9951 } 9952 9953 return styles; 9954 } 9955 9956 function styleDifference( oldStyle, newStyle ) { 9957 var diff = {}, 9958 name, value; 9959 9960 for ( name in newStyle ) { 9961 value = newStyle[ name ]; 9962 if ( oldStyle[ name ] !== value ) { 9963 if ( !shorthandStyles[ name ] ) { 9964 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { 9965 diff[ name ] = value; 9966 } 9967 } 9968 } 9969 } 9970 9971 return diff; 9972 } 9973 9974 // support: jQuery <1.8 9975 if ( !$.fn.addBack ) { 9976 $.fn.addBack = function( selector ) { 9977 return this.add( selector == null ? 9978 this.prevObject : this.prevObject.filter( selector ) 9979 ); 9980 }; 9981 } 9982 9983 $.effects.animateClass = function( value, duration, easing, callback ) { 9984 var o = $.speed( duration, easing, callback ); 9985 9986 return this.queue( function() { 9987 var animated = $( this ), 9988 baseClass = animated.attr( "class" ) || "", 9989 applyClassChange, 9990 allAnimations = o.children ? animated.find( "*" ).addBack() : animated; 9991 9992 // map the animated objects to store the original styles. 9993 allAnimations = allAnimations.map(function() { 9994 var el = $( this ); 9995 return { 9996 el: el, 9997 start: getElementStyles( this ) 9998 }; 9999 }); 10000 10001 // apply class change 10002 applyClassChange = function() { 10003 $.each( classAnimationActions, function(i, action) { 10004 if ( value[ action ] ) { 10005 animated[ action + "Class" ]( value[ action ] ); 10006 } 10007 }); 10008 }; 10009 applyClassChange(); 10010 10011 // map all animated objects again - calculate new styles and diff 10012 allAnimations = allAnimations.map(function() { 10013 this.end = getElementStyles( this.el[ 0 ] ); 10014 this.diff = styleDifference( this.start, this.end ); 10015 return this; 10016 }); 10017 10018 // apply original class 10019 animated.attr( "class", baseClass ); 10020 10021 // map all animated objects again - this time collecting a promise 10022 allAnimations = allAnimations.map(function() { 10023 var styleInfo = this, 10024 dfd = $.Deferred(), 10025 opts = $.extend({}, o, { 10026 queue: false, 10027 complete: function() { 10028 dfd.resolve( styleInfo ); 10029 } 10030 }); 10031 10032 this.el.animate( this.diff, opts ); 10033 return dfd.promise(); 10034 }); 10035 10036 // once all animations have completed: 10037 $.when.apply( $, allAnimations.get() ).done(function() { 10038 10039 // set the final class 10040 applyClassChange(); 10041 10042 // for each animated element, 10043 // clear all css properties that were animated 10044 $.each( arguments, function() { 10045 var el = this.el; 10046 $.each( this.diff, function(key) { 10047 el.css( key, "" ); 10048 }); 10049 }); 10050 10051 // this is guarnteed to be there if you use jQuery.speed() 10052 // it also handles dequeuing the next anim... 10053 o.complete.call( animated[ 0 ] ); 10054 }); 10055 }); 10056 }; 10057 10058 $.fn.extend({ 10059 addClass: (function( orig ) { 10060 return function( classNames, speed, easing, callback ) { 10061 return speed ? 10062 $.effects.animateClass.call( this, 10063 { add: classNames }, speed, easing, callback ) : 10064 orig.apply( this, arguments ); 10065 }; 10066 })( $.fn.addClass ), 10067 10068 removeClass: (function( orig ) { 10069 return function( classNames, speed, easing, callback ) { 10070 return arguments.length > 1 ? 10071 $.effects.animateClass.call( this, 10072 { remove: classNames }, speed, easing, callback ) : 10073 orig.apply( this, arguments ); 10074 }; 10075 })( $.fn.removeClass ), 10076 10077 toggleClass: (function( orig ) { 10078 return function( classNames, force, speed, easing, callback ) { 10079 if ( typeof force === "boolean" || force === undefined ) { 10080 if ( !speed ) { 10081 // without speed parameter 10082 return orig.apply( this, arguments ); 10083 } else { 10084 return $.effects.animateClass.call( this, 10085 (force ? { add: classNames } : { remove: classNames }), 10086 speed, easing, callback ); 10087 } 10088 } else { 10089 // without force parameter 10090 return $.effects.animateClass.call( this, 10091 { toggle: classNames }, force, speed, easing ); 10092 } 10093 }; 10094 })( $.fn.toggleClass ), 10095 10096 switchClass: function( remove, add, speed, easing, callback) { 10097 return $.effects.animateClass.call( this, { 10098 add: add, 10099 remove: remove 10100 }, speed, easing, callback ); 10101 } 10102 }); 10103 10104 })(); 10105 10106 /******************************************************************************/ 10107 /*********************************** EFFECTS **********************************/ 10108 /******************************************************************************/ 10109 10110 (function() { 10111 10112 $.extend( $.effects, { 10113 version: "1.11.1", 10114 10115 // Saves a set of properties in a data storage 10116 save: function( element, set ) { 10117 for ( var i = 0; i < set.length; i++ ) { 10118 if ( set[ i ] !== null ) { 10119 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); 10120 } 10121 } 10122 }, 10123 10124 // Restores a set of previously saved properties from a data storage 10125 restore: function( element, set ) { 10126 var val, i; 10127 for ( i = 0; i < set.length; i++ ) { 10128 if ( set[ i ] !== null ) { 10129 val = element.data( dataSpace + set[ i ] ); 10130 // support: jQuery 1.6.2 10131 // http://bugs.jquery.com/ticket/9917 10132 // jQuery 1.6.2 incorrectly returns undefined for any falsy value. 10133 // We can't differentiate between "" and 0 here, so we just assume 10134 // empty string since it's likely to be a more common value... 10135 if ( val === undefined ) { 10136 val = ""; 10137 } 10138 element.css( set[ i ], val ); 10139 } 10140 } 10141 }, 10142 10143 setMode: function( el, mode ) { 10144 if (mode === "toggle") { 10145 mode = el.is( ":hidden" ) ? "show" : "hide"; 10146 } 10147 return mode; 10148 }, 10149 10150 // Translates a [top,left] array into a baseline value 10151 // this should be a little more flexible in the future to handle a string & hash 10152 getBaseline: function( origin, original ) { 10153 var y, x; 10154 switch ( origin[ 0 ] ) { 10155 case "top": y = 0; break; 10156 case "middle": y = 0.5; break; 10157 case "bottom": y = 1; break; 10158 default: y = origin[ 0 ] / original.height; 10159 } 10160 switch ( origin[ 1 ] ) { 10161 case "left": x = 0; break; 10162 case "center": x = 0.5; break; 10163 case "right": x = 1; break; 10164 default: x = origin[ 1 ] / original.width; 10165 } 10166 return { 10167 x: x, 10168 y: y 10169 }; 10170 }, 10171 10172 // Wraps the element around a wrapper that copies position properties 10173 createWrapper: function( element ) { 10174 10175 // if the element is already wrapped, return it 10176 if ( element.parent().is( ".ui-effects-wrapper" )) { 10177 return element.parent(); 10178 } 10179 10180 // wrap the element 10181 var props = { 10182 width: element.outerWidth(true), 10183 height: element.outerHeight(true), 10184 "float": element.css( "float" ) 10185 }, 10186 wrapper = $( "<div></div>" ) 10187 .addClass( "ui-effects-wrapper" ) 10188 .css({ 10189 fontSize: "100%", 10190 background: "transparent", 10191 border: "none", 10192 margin: 0, 10193 padding: 0 10194 }), 10195 // Store the size in case width/height are defined in % - Fixes #5245 10196 size = { 10197 width: element.width(), 10198 height: element.height() 10199 }, 10200 active = document.activeElement; 10201 10202 // support: Firefox 10203 // Firefox incorrectly exposes anonymous content 10204 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 10205 try { 10206 active.id; 10207 } catch( e ) { 10208 active = document.body; 10209 } 10210 10211 element.wrap( wrapper ); 10212 10213 // Fixes #7595 - Elements lose focus when wrapped. 10214 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 10215 $( active ).focus(); 10216 } 10217 10218 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element 10219 10220 // transfer positioning properties to the wrapper 10221 if ( element.css( "position" ) === "static" ) { 10222 wrapper.css({ position: "relative" }); 10223 element.css({ position: "relative" }); 10224 } else { 10225 $.extend( props, { 10226 position: element.css( "position" ), 10227 zIndex: element.css( "z-index" ) 10228 }); 10229 $.each([ "top", "left", "bottom", "right" ], function(i, pos) { 10230 props[ pos ] = element.css( pos ); 10231 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { 10232 props[ pos ] = "auto"; 10233 } 10234 }); 10235 element.css({ 10236 position: "relative", 10237 top: 0, 10238 left: 0, 10239 right: "auto", 10240 bottom: "auto" 10241 }); 10242 } 10243 element.css(size); 10244 10245 return wrapper.css( props ).show(); 10246 }, 10247 10248 removeWrapper: function( element ) { 10249 var active = document.activeElement; 10250 10251 if ( element.parent().is( ".ui-effects-wrapper" ) ) { 10252 element.parent().replaceWith( element ); 10253 10254 // Fixes #7595 - Elements lose focus when wrapped. 10255 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { 10256 $( active ).focus(); 10257 } 10258 } 10259 10260 return element; 10261 }, 10262 10263 setTransition: function( element, list, factor, value ) { 10264 value = value || {}; 10265 $.each( list, function( i, x ) { 10266 var unit = element.cssUnit( x ); 10267 if ( unit[ 0 ] > 0 ) { 10268 value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; 10269 } 10270 }); 10271 return value; 10272 } 10273 }); 10274 10275 // return an effect options object for the given parameters: 10276 function _normalizeArguments( effect, options, speed, callback ) { 10277 10278 // allow passing all options as the first parameter 10279 if ( $.isPlainObject( effect ) ) { 10280 options = effect; 10281 effect = effect.effect; 10282 } 10283 10284 // convert to an object 10285 effect = { effect: effect }; 10286 10287 // catch (effect, null, ...) 10288 if ( options == null ) { 10289 options = {}; 10290 } 10291 10292 // catch (effect, callback) 10293 if ( $.isFunction( options ) ) { 10294 callback = options; 10295 speed = null; 10296 options = {}; 10297 } 10298 10299 // catch (effect, speed, ?) 10300 if ( typeof options === "number" || $.fx.speeds[ options ] ) { 10301 callback = speed; 10302 speed = options; 10303 options = {}; 10304 } 10305 10306 // catch (effect, options, callback) 10307 if ( $.isFunction( speed ) ) { 10308 callback = speed; 10309 speed = null; 10310 } 10311 10312 // add options to effect 10313 if ( options ) { 10314 $.extend( effect, options ); 10315 } 10316 10317 speed = speed || options.duration; 10318 effect.duration = $.fx.off ? 0 : 10319 typeof speed === "number" ? speed : 10320 speed in $.fx.speeds ? $.fx.speeds[ speed ] : 10321 $.fx.speeds._default; 10322 10323 effect.complete = callback || options.complete; 10324 10325 return effect; 10326 } 10327 10328 function standardAnimationOption( option ) { 10329 // Valid standard speeds (nothing, number, named speed) 10330 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { 10331 return true; 10332 } 10333 10334 // Invalid strings - treat as "normal" speed 10335 if ( typeof option === "string" && !$.effects.effect[ option ] ) { 10336 return true; 10337 } 10338 10339 // Complete callback 10340 if ( $.isFunction( option ) ) { 10341 return true; 10342 } 10343 10344 // Options hash (but not naming an effect) 10345 if ( typeof option === "object" && !option.effect ) { 10346 return true; 10347 } 10348 10349 // Didn't match any standard API 10350 return false; 10351 } 10352 10353 $.fn.extend({ 10354 effect: function( /* effect, options, speed, callback */ ) { 10355 var args = _normalizeArguments.apply( this, arguments ), 10356 mode = args.mode, 10357 queue = args.queue, 10358 effectMethod = $.effects.effect[ args.effect ]; 10359 10360 if ( $.fx.off || !effectMethod ) { 10361 // delegate to the original method (e.g., .show()) if possible 10362 if ( mode ) { 10363 return this[ mode ]( args.duration, args.complete ); 10364 } else { 10365 return this.each( function() { 10366 if ( args.complete ) { 10367 args.complete.call( this ); 10368 } 10369 }); 10370 } 10371 } 10372 10373 function run( next ) { 10374 var elem = $( this ), 10375 complete = args.complete, 10376 mode = args.mode; 10377 10378 function done() { 10379 if ( $.isFunction( complete ) ) { 10380 complete.call( elem[0] ); 10381 } 10382 if ( $.isFunction( next ) ) { 10383 next(); 10384 } 10385 } 10386 10387 // If the element already has the correct final state, delegate to 10388 // the core methods so the internal tracking of "olddisplay" works. 10389 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { 10390 elem[ mode ](); 10391 done(); 10392 } else { 10393 effectMethod.call( elem[0], args, done ); 10394 } 10395 } 10396 10397 return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); 10398 }, 10399 10400 show: (function( orig ) { 10401 return function( option ) { 10402 if ( standardAnimationOption( option ) ) { 10403 return orig.apply( this, arguments ); 10404 } else { 10405 var args = _normalizeArguments.apply( this, arguments ); 10406 args.mode = "show"; 10407 return this.effect.call( this, args ); 10408 } 10409 }; 10410 })( $.fn.show ), 10411 10412 hide: (function( orig ) { 10413 return function( option ) { 10414 if ( standardAnimationOption( option ) ) { 10415 return orig.apply( this, arguments ); 10416 } else { 10417 var args = _normalizeArguments.apply( this, arguments ); 10418 args.mode = "hide"; 10419 return this.effect.call( this, args ); 10420 } 10421 }; 10422 })( $.fn.hide ), 10423 10424 toggle: (function( orig ) { 10425 return function( option ) { 10426 if ( standardAnimationOption( option ) || typeof option === "boolean" ) { 10427 return orig.apply( this, arguments ); 10428 } else { 10429 var args = _normalizeArguments.apply( this, arguments ); 10430 args.mode = "toggle"; 10431 return this.effect.call( this, args ); 10432 } 10433 }; 10434 })( $.fn.toggle ), 10435 10436 // helper functions 10437 cssUnit: function(key) { 10438 var style = this.css( key ), 10439 val = []; 10440 10441 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { 10442 if ( style.indexOf( unit ) > 0 ) { 10443 val = [ parseFloat( style ), unit ]; 10444 } 10445 }); 10446 return val; 10447 } 10448 }); 10449 10450 })(); 10451 10452 /******************************************************************************/ 10453 /*********************************** EASING ***********************************/ 10454 /******************************************************************************/ 10455 10456 (function() { 10457 10458 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing) 10459 10460 var baseEasings = {}; 10461 10462 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { 10463 baseEasings[ name ] = function( p ) { 10464 return Math.pow( p, i + 2 ); 10465 }; 10466 }); 10467 10468 $.extend( baseEasings, { 10469 Sine: function( p ) { 10470 return 1 - Math.cos( p * Math.PI / 2 ); 10471 }, 10472 Circ: function( p ) { 10473 return 1 - Math.sqrt( 1 - p * p ); 10474 }, 10475 Elastic: function( p ) { 10476 return p === 0 || p === 1 ? p : 10477 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); 10478 }, 10479 Back: function( p ) { 10480 return p * p * ( 3 * p - 2 ); 10481 }, 10482 Bounce: function( p ) { 10483 var pow2, 10484 bounce = 4; 10485 10486 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} 10487 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); 10488 } 10489 }); 10490 10491 $.each( baseEasings, function( name, easeIn ) { 10492 $.easing[ "easeIn" + name ] = easeIn; 10493 $.easing[ "easeOut" + name ] = function( p ) { 10494 return 1 - easeIn( 1 - p ); 10495 }; 10496 $.easing[ "easeInOut" + name ] = function( p ) { 10497 return p < 0.5 ? 10498 easeIn( p * 2 ) / 2 : 10499 1 - easeIn( p * -2 + 2 ) / 2; 10500 }; 10501 }); 10502 10503 })(); 10504 10505 var effect = $.effects; 10506 10507 10508 /*! 10509 * jQuery UI Effects Blind 1.11.1 10510 * http://jqueryui.com 10511 * 10512 * Copyright 2014 jQuery Foundation and other contributors 10513 * Released under the MIT license. 10514 * http://jquery.org/license 10515 * 10516 * http://api.jqueryui.com/blind-effect/ 10517 */ 10518 10519 10520 var effectBlind = $.effects.effect.blind = function( o, done ) { 10521 // Create element 10522 var el = $( this ), 10523 rvertical = /up|down|vertical/, 10524 rpositivemotion = /up|left|vertical|horizontal/, 10525 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10526 mode = $.effects.setMode( el, o.mode || "hide" ), 10527 direction = o.direction || "up", 10528 vertical = rvertical.test( direction ), 10529 ref = vertical ? "height" : "width", 10530 ref2 = vertical ? "top" : "left", 10531 motion = rpositivemotion.test( direction ), 10532 animation = {}, 10533 show = mode === "show", 10534 wrapper, distance, margin; 10535 10536 // if already wrapped, the wrapper's properties are my property. #6245 10537 if ( el.parent().is( ".ui-effects-wrapper" ) ) { 10538 $.effects.save( el.parent(), props ); 10539 } else { 10540 $.effects.save( el, props ); 10541 } 10542 el.show(); 10543 wrapper = $.effects.createWrapper( el ).css({ 10544 overflow: "hidden" 10545 }); 10546 10547 distance = wrapper[ ref ](); 10548 margin = parseFloat( wrapper.css( ref2 ) ) || 0; 10549 10550 animation[ ref ] = show ? distance : 0; 10551 if ( !motion ) { 10552 el 10553 .css( vertical ? "bottom" : "right", 0 ) 10554 .css( vertical ? "top" : "left", "auto" ) 10555 .css({ position: "absolute" }); 10556 10557 animation[ ref2 ] = show ? margin : distance + margin; 10558 } 10559 10560 // start at 0 if we are showing 10561 if ( show ) { 10562 wrapper.css( ref, 0 ); 10563 if ( !motion ) { 10564 wrapper.css( ref2, margin + distance ); 10565 } 10566 } 10567 10568 // Animate 10569 wrapper.animate( animation, { 10570 duration: o.duration, 10571 easing: o.easing, 10572 queue: false, 10573 complete: function() { 10574 if ( mode === "hide" ) { 10575 el.hide(); 10576 } 10577 $.effects.restore( el, props ); 10578 $.effects.removeWrapper( el ); 10579 done(); 10580 } 10581 }); 10582 }; 10583 10584 10585 /*! 10586 * jQuery UI Effects Bounce 1.11.1 10587 * http://jqueryui.com 10588 * 10589 * Copyright 2014 jQuery Foundation and other contributors 10590 * Released under the MIT license. 10591 * http://jquery.org/license 10592 * 10593 * http://api.jqueryui.com/bounce-effect/ 10594 */ 10595 10596 10597 var effectBounce = $.effects.effect.bounce = function( o, done ) { 10598 var el = $( this ), 10599 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10600 10601 // defaults: 10602 mode = $.effects.setMode( el, o.mode || "effect" ), 10603 hide = mode === "hide", 10604 show = mode === "show", 10605 direction = o.direction || "up", 10606 distance = o.distance, 10607 times = o.times || 5, 10608 10609 // number of internal animations 10610 anims = times * 2 + ( show || hide ? 1 : 0 ), 10611 speed = o.duration / anims, 10612 easing = o.easing, 10613 10614 // utility: 10615 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 10616 motion = ( direction === "up" || direction === "left" ), 10617 i, 10618 upAnim, 10619 downAnim, 10620 10621 // we will need to re-assemble the queue to stack our animations in place 10622 queue = el.queue(), 10623 queuelen = queue.length; 10624 10625 // Avoid touching opacity to prevent clearType and PNG issues in IE 10626 if ( show || hide ) { 10627 props.push( "opacity" ); 10628 } 10629 10630 $.effects.save( el, props ); 10631 el.show(); 10632 $.effects.createWrapper( el ); // Create Wrapper 10633 10634 // default distance for the BIGGEST bounce is the outer Distance / 3 10635 if ( !distance ) { 10636 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; 10637 } 10638 10639 if ( show ) { 10640 downAnim = { opacity: 1 }; 10641 downAnim[ ref ] = 0; 10642 10643 // if we are showing, force opacity 0 and set the initial position 10644 // then do the "first" animation 10645 el.css( "opacity", 0 ) 10646 .css( ref, motion ? -distance * 2 : distance * 2 ) 10647 .animate( downAnim, speed, easing ); 10648 } 10649 10650 // start at the smallest distance if we are hiding 10651 if ( hide ) { 10652 distance = distance / Math.pow( 2, times - 1 ); 10653 } 10654 10655 downAnim = {}; 10656 downAnim[ ref ] = 0; 10657 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here 10658 for ( i = 0; i < times; i++ ) { 10659 upAnim = {}; 10660 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 10661 10662 el.animate( upAnim, speed, easing ) 10663 .animate( downAnim, speed, easing ); 10664 10665 distance = hide ? distance * 2 : distance / 2; 10666 } 10667 10668 // Last Bounce when Hiding 10669 if ( hide ) { 10670 upAnim = { opacity: 0 }; 10671 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; 10672 10673 el.animate( upAnim, speed, easing ); 10674 } 10675 10676 el.queue(function() { 10677 if ( hide ) { 10678 el.hide(); 10679 } 10680 $.effects.restore( el, props ); 10681 $.effects.removeWrapper( el ); 10682 done(); 10683 }); 10684 10685 // inject all the animations we just queued to be first in line (after "inprogress") 10686 if ( queuelen > 1) { 10687 queue.splice.apply( queue, 10688 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); 10689 } 10690 el.dequeue(); 10691 10692 }; 10693 10694 10695 /*! 10696 * jQuery UI Effects Clip 1.11.1 10697 * http://jqueryui.com 10698 * 10699 * Copyright 2014 jQuery Foundation and other contributors 10700 * Released under the MIT license. 10701 * http://jquery.org/license 10702 * 10703 * http://api.jqueryui.com/clip-effect/ 10704 */ 10705 10706 10707 var effectClip = $.effects.effect.clip = function( o, done ) { 10708 // Create element 10709 var el = $( this ), 10710 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10711 mode = $.effects.setMode( el, o.mode || "hide" ), 10712 show = mode === "show", 10713 direction = o.direction || "vertical", 10714 vert = direction === "vertical", 10715 size = vert ? "height" : "width", 10716 position = vert ? "top" : "left", 10717 animation = {}, 10718 wrapper, animate, distance; 10719 10720 // Save & Show 10721 $.effects.save( el, props ); 10722 el.show(); 10723 10724 // Create Wrapper 10725 wrapper = $.effects.createWrapper( el ).css({ 10726 overflow: "hidden" 10727 }); 10728 animate = ( el[0].tagName === "IMG" ) ? wrapper : el; 10729 distance = animate[ size ](); 10730 10731 // Shift 10732 if ( show ) { 10733 animate.css( size, 0 ); 10734 animate.css( position, distance / 2 ); 10735 } 10736 10737 // Create Animation Object: 10738 animation[ size ] = show ? distance : 0; 10739 animation[ position ] = show ? 0 : distance / 2; 10740 10741 // Animate 10742 animate.animate( animation, { 10743 queue: false, 10744 duration: o.duration, 10745 easing: o.easing, 10746 complete: function() { 10747 if ( !show ) { 10748 el.hide(); 10749 } 10750 $.effects.restore( el, props ); 10751 $.effects.removeWrapper( el ); 10752 done(); 10753 } 10754 }); 10755 10756 }; 10757 10758 10759 /*! 10760 * jQuery UI Effects Drop 1.11.1 10761 * http://jqueryui.com 10762 * 10763 * Copyright 2014 jQuery Foundation and other contributors 10764 * Released under the MIT license. 10765 * http://jquery.org/license 10766 * 10767 * http://api.jqueryui.com/drop-effect/ 10768 */ 10769 10770 10771 var effectDrop = $.effects.effect.drop = function( o, done ) { 10772 10773 var el = $( this ), 10774 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ], 10775 mode = $.effects.setMode( el, o.mode || "hide" ), 10776 show = mode === "show", 10777 direction = o.direction || "left", 10778 ref = ( direction === "up" || direction === "down" ) ? "top" : "left", 10779 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg", 10780 animation = { 10781 opacity: show ? 1 : 0 10782 }, 10783 distance; 10784 10785 // Adjust 10786 $.effects.save( el, props ); 10787 el.show(); 10788 $.effects.createWrapper( el ); 10789 10790 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2; 10791 10792 if ( show ) { 10793 el 10794 .css( "opacity", 0 ) 10795 .css( ref, motion === "pos" ? -distance : distance ); 10796 } 10797 10798 // Animation 10799 animation[ ref ] = ( show ? 10800 ( motion === "pos" ? "+=" : "-=" ) : 10801 ( motion === "pos" ? "-=" : "+=" ) ) + 10802 distance; 10803 10804 // Animate 10805 el.animate( animation, { 10806 queue: false, 10807 duration: o.duration, 10808 easing: o.easing, 10809 complete: function() { 10810 if ( mode === "hide" ) { 10811 el.hide(); 10812 } 10813 $.effects.restore( el, props ); 10814 $.effects.removeWrapper( el ); 10815 done(); 10816 } 10817 }); 10818 }; 10819 10820 10821 /*! 10822 * jQuery UI Effects Explode 1.11.1 10823 * http://jqueryui.com 10824 * 10825 * Copyright 2014 jQuery Foundation and other contributors 10826 * Released under the MIT license. 10827 * http://jquery.org/license 10828 * 10829 * http://api.jqueryui.com/explode-effect/ 10830 */ 10831 10832 10833 var effectExplode = $.effects.effect.explode = function( o, done ) { 10834 10835 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3, 10836 cells = rows, 10837 el = $( this ), 10838 mode = $.effects.setMode( el, o.mode || "hide" ), 10839 show = mode === "show", 10840 10841 // show and then visibility:hidden the element before calculating offset 10842 offset = el.show().css( "visibility", "hidden" ).offset(), 10843 10844 // width and height of a piece 10845 width = Math.ceil( el.outerWidth() / cells ), 10846 height = Math.ceil( el.outerHeight() / rows ), 10847 pieces = [], 10848 10849 // loop 10850 i, j, left, top, mx, my; 10851 10852 // children animate complete: 10853 function childComplete() { 10854 pieces.push( this ); 10855 if ( pieces.length === rows * cells ) { 10856 animComplete(); 10857 } 10858 } 10859 10860 // clone the element for each row and cell. 10861 for ( i = 0; i < rows ; i++ ) { // ===> 10862 top = offset.top + i * height; 10863 my = i - ( rows - 1 ) / 2 ; 10864 10865 for ( j = 0; j < cells ; j++ ) { // ||| 10866 left = offset.left + j * width; 10867 mx = j - ( cells - 1 ) / 2 ; 10868 10869 // Create a clone of the now hidden main element that will be absolute positioned 10870 // within a wrapper div off the -left and -top equal to size of our pieces 10871 el 10872 .clone() 10873 .appendTo( "body" ) 10874 .wrap( "<div></div>" ) 10875 .css({ 10876 position: "absolute", 10877 visibility: "visible", 10878 left: -j * width, 10879 top: -i * height 10880 }) 10881 10882 // select the wrapper - make it overflow: hidden and absolute positioned based on 10883 // where the original was located +left and +top equal to the size of pieces 10884 .parent() 10885 .addClass( "ui-effects-explode" ) 10886 .css({ 10887 position: "absolute", 10888 overflow: "hidden", 10889 width: width, 10890 height: height, 10891 left: left + ( show ? mx * width : 0 ), 10892 top: top + ( show ? my * height : 0 ), 10893 opacity: show ? 0 : 1 10894 }).animate({ 10895 left: left + ( show ? 0 : mx * width ), 10896 top: top + ( show ? 0 : my * height ), 10897 opacity: show ? 1 : 0 10898 }, o.duration || 500, o.easing, childComplete ); 10899 } 10900 } 10901 10902 function animComplete() { 10903 el.css({ 10904 visibility: "visible" 10905 }); 10906 $( pieces ).remove(); 10907 if ( !show ) { 10908 el.hide(); 10909 } 10910 done(); 10911 } 10912 }; 10913 10914 10915 /*! 10916 * jQuery UI Effects Fade 1.11.1 10917 * http://jqueryui.com 10918 * 10919 * Copyright 2014 jQuery Foundation and other contributors 10920 * Released under the MIT license. 10921 * http://jquery.org/license 10922 * 10923 * http://api.jqueryui.com/fade-effect/ 10924 */ 10925 10926 10927 var effectFade = $.effects.effect.fade = function( o, done ) { 10928 var el = $( this ), 10929 mode = $.effects.setMode( el, o.mode || "toggle" ); 10930 10931 el.animate({ 10932 opacity: mode 10933 }, { 10934 queue: false, 10935 duration: o.duration, 10936 easing: o.easing, 10937 complete: done 10938 }); 10939 }; 10940 10941 10942 /*! 10943 * jQuery UI Effects Fold 1.11.1 10944 * http://jqueryui.com 10945 * 10946 * Copyright 2014 jQuery Foundation and other contributors 10947 * Released under the MIT license. 10948 * http://jquery.org/license 10949 * 10950 * http://api.jqueryui.com/fold-effect/ 10951 */ 10952 10953 10954 var effectFold = $.effects.effect.fold = function( o, done ) { 10955 10956 // Create element 10957 var el = $( this ), 10958 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 10959 mode = $.effects.setMode( el, o.mode || "hide" ), 10960 show = mode === "show", 10961 hide = mode === "hide", 10962 size = o.size || 15, 10963 percent = /([0-9]+)%/.exec( size ), 10964 horizFirst = !!o.horizFirst, 10965 widthFirst = show !== horizFirst, 10966 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ], 10967 duration = o.duration / 2, 10968 wrapper, distance, 10969 animation1 = {}, 10970 animation2 = {}; 10971 10972 $.effects.save( el, props ); 10973 el.show(); 10974 10975 // Create Wrapper 10976 wrapper = $.effects.createWrapper( el ).css({ 10977 overflow: "hidden" 10978 }); 10979 distance = widthFirst ? 10980 [ wrapper.width(), wrapper.height() ] : 10981 [ wrapper.height(), wrapper.width() ]; 10982 10983 if ( percent ) { 10984 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; 10985 } 10986 if ( show ) { 10987 wrapper.css( horizFirst ? { 10988 height: 0, 10989 width: size 10990 } : { 10991 height: size, 10992 width: 0 10993 }); 10994 } 10995 10996 // Animation 10997 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size; 10998 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0; 10999 11000 // Animate 11001 wrapper 11002 .animate( animation1, duration, o.easing ) 11003 .animate( animation2, duration, o.easing, function() { 11004 if ( hide ) { 11005 el.hide(); 11006 } 11007 $.effects.restore( el, props ); 11008 $.effects.removeWrapper( el ); 11009 done(); 11010 }); 11011 11012 }; 11013 11014 11015 /*! 11016 * jQuery UI Effects Highlight 1.11.1 11017 * http://jqueryui.com 11018 * 11019 * Copyright 2014 jQuery Foundation and other contributors 11020 * Released under the MIT license. 11021 * http://jquery.org/license 11022 * 11023 * http://api.jqueryui.com/highlight-effect/ 11024 */ 11025 11026 11027 var effectHighlight = $.effects.effect.highlight = function( o, done ) { 11028 var elem = $( this ), 11029 props = [ "backgroundImage", "backgroundColor", "opacity" ], 11030 mode = $.effects.setMode( elem, o.mode || "show" ), 11031 animation = { 11032 backgroundColor: elem.css( "backgroundColor" ) 11033 }; 11034 11035 if (mode === "hide") { 11036 animation.opacity = 0; 11037 } 11038 11039 $.effects.save( elem, props ); 11040 11041 elem 11042 .show() 11043 .css({ 11044 backgroundImage: "none", 11045 backgroundColor: o.color || "#ffff99" 11046 }) 11047 .animate( animation, { 11048 queue: false, 11049 duration: o.duration, 11050 easing: o.easing, 11051 complete: function() { 11052 if ( mode === "hide" ) { 11053 elem.hide(); 11054 } 11055 $.effects.restore( elem, props ); 11056 done(); 11057 } 11058 }); 11059 }; 11060 11061 11062 /*! 11063 * jQuery UI Effects Size 1.11.1 11064 * http://jqueryui.com 11065 * 11066 * Copyright 2014 jQuery Foundation and other contributors 11067 * Released under the MIT license. 11068 * http://jquery.org/license 11069 * 11070 * http://api.jqueryui.com/size-effect/ 11071 */ 11072 11073 11074 var effectSize = $.effects.effect.size = function( o, done ) { 11075 11076 // Create element 11077 var original, baseline, factor, 11078 el = $( this ), 11079 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ], 11080 11081 // Always restore 11082 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ], 11083 11084 // Copy for children 11085 props2 = [ "width", "height", "overflow" ], 11086 cProps = [ "fontSize" ], 11087 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], 11088 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], 11089 11090 // Set options 11091 mode = $.effects.setMode( el, o.mode || "effect" ), 11092 restore = o.restore || mode !== "effect", 11093 scale = o.scale || "both", 11094 origin = o.origin || [ "middle", "center" ], 11095 position = el.css( "position" ), 11096 props = restore ? props0 : props1, 11097 zero = { 11098 height: 0, 11099 width: 0, 11100 outerHeight: 0, 11101 outerWidth: 0 11102 }; 11103 11104 if ( mode === "show" ) { 11105 el.show(); 11106 } 11107 original = { 11108 height: el.height(), 11109 width: el.width(), 11110 outerHeight: el.outerHeight(), 11111 outerWidth: el.outerWidth() 11112 }; 11113 11114 if ( o.mode === "toggle" && mode === "show" ) { 11115 el.from = o.to || zero; 11116 el.to = o.from || original; 11117 } else { 11118 el.from = o.from || ( mode === "show" ? zero : original ); 11119 el.to = o.to || ( mode === "hide" ? zero : original ); 11120 } 11121 11122 // Set scaling factor 11123 factor = { 11124 from: { 11125 y: el.from.height / original.height, 11126 x: el.from.width / original.width 11127 }, 11128 to: { 11129 y: el.to.height / original.height, 11130 x: el.to.width / original.width 11131 } 11132 }; 11133 11134 // Scale the css box 11135 if ( scale === "box" || scale === "both" ) { 11136 11137 // Vertical props scaling 11138 if ( factor.from.y !== factor.to.y ) { 11139 props = props.concat( vProps ); 11140 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from ); 11141 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to ); 11142 } 11143 11144 // Horizontal props scaling 11145 if ( factor.from.x !== factor.to.x ) { 11146 props = props.concat( hProps ); 11147 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from ); 11148 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to ); 11149 } 11150 } 11151 11152 // Scale the content 11153 if ( scale === "content" || scale === "both" ) { 11154 11155 // Vertical props scaling 11156 if ( factor.from.y !== factor.to.y ) { 11157 props = props.concat( cProps ).concat( props2 ); 11158 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from ); 11159 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to ); 11160 } 11161 } 11162 11163 $.effects.save( el, props ); 11164 el.show(); 11165 $.effects.createWrapper( el ); 11166 el.css( "overflow", "hidden" ).css( el.from ); 11167 11168 // Adjust 11169 if (origin) { // Calculate baseline shifts 11170 baseline = $.effects.getBaseline( origin, original ); 11171 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y; 11172 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x; 11173 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y; 11174 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x; 11175 } 11176 el.css( el.from ); // set top & left 11177 11178 // Animate 11179 if ( scale === "content" || scale === "both" ) { // Scale the children 11180 11181 // Add margins/font-size 11182 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps); 11183 hProps = hProps.concat([ "marginLeft", "marginRight" ]); 11184 props2 = props0.concat(vProps).concat(hProps); 11185 11186 el.find( "*[width]" ).each( function() { 11187 var child = $( this ), 11188 c_original = { 11189 height: child.height(), 11190 width: child.width(), 11191 outerHeight: child.outerHeight(), 11192 outerWidth: child.outerWidth() 11193 }; 11194 if (restore) { 11195 $.effects.save(child, props2); 11196 } 11197 11198 child.from = { 11199 height: c_original.height * factor.from.y, 11200 width: c_original.width * factor.from.x, 11201 outerHeight: c_original.outerHeight * factor.from.y, 11202 outerWidth: c_original.outerWidth * factor.from.x 11203 }; 11204 child.to = { 11205 height: c_original.height * factor.to.y, 11206 width: c_original.width * factor.to.x, 11207 outerHeight: c_original.height * factor.to.y, 11208 outerWidth: c_original.width * factor.to.x 11209 }; 11210 11211 // Vertical props scaling 11212 if ( factor.from.y !== factor.to.y ) { 11213 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from ); 11214 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to ); 11215 } 11216 11217 // Horizontal props scaling 11218 if ( factor.from.x !== factor.to.x ) { 11219 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from ); 11220 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to ); 11221 } 11222 11223 // Animate children 11224 child.css( child.from ); 11225 child.animate( child.to, o.duration, o.easing, function() { 11226 11227 // Restore children 11228 if ( restore ) { 11229 $.effects.restore( child, props2 ); 11230 } 11231 }); 11232 }); 11233 } 11234 11235 // Animate 11236 el.animate( el.to, { 11237 queue: false, 11238 duration: o.duration, 11239 easing: o.easing, 11240 complete: function() { 11241 if ( el.to.opacity === 0 ) { 11242 el.css( "opacity", el.from.opacity ); 11243 } 11244 if ( mode === "hide" ) { 11245 el.hide(); 11246 } 11247 $.effects.restore( el, props ); 11248 if ( !restore ) { 11249 11250 // we need to calculate our new positioning based on the scaling 11251 if ( position === "static" ) { 11252 el.css({ 11253 position: "relative", 11254 top: el.to.top, 11255 left: el.to.left 11256 }); 11257 } else { 11258 $.each([ "top", "left" ], function( idx, pos ) { 11259 el.css( pos, function( _, str ) { 11260 var val = parseInt( str, 10 ), 11261 toRef = idx ? el.to.left : el.to.top; 11262 11263 // if original was "auto", recalculate the new value from wrapper 11264 if ( str === "auto" ) { 11265 return toRef + "px"; 11266 } 11267 11268 return val + toRef + "px"; 11269 }); 11270 }); 11271 } 11272 } 11273 11274 $.effects.removeWrapper( el ); 11275 done(); 11276 } 11277 }); 11278 11279 }; 11280 11281 11282 /*! 11283 * jQuery UI Effects Scale 1.11.1 11284 * http://jqueryui.com 11285 * 11286 * Copyright 2014 jQuery Foundation and other contributors 11287 * Released under the MIT license. 11288 * http://jquery.org/license 11289 * 11290 * http://api.jqueryui.com/scale-effect/ 11291 */ 11292 11293 11294 var effectScale = $.effects.effect.scale = function( o, done ) { 11295 11296 // Create element 11297 var el = $( this ), 11298 options = $.extend( true, {}, o ), 11299 mode = $.effects.setMode( el, o.mode || "effect" ), 11300 percent = parseInt( o.percent, 10 ) || 11301 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ), 11302 direction = o.direction || "both", 11303 origin = o.origin, 11304 original = { 11305 height: el.height(), 11306 width: el.width(), 11307 outerHeight: el.outerHeight(), 11308 outerWidth: el.outerWidth() 11309 }, 11310 factor = { 11311 y: direction !== "horizontal" ? (percent / 100) : 1, 11312 x: direction !== "vertical" ? (percent / 100) : 1 11313 }; 11314 11315 // We are going to pass this effect to the size effect: 11316 options.effect = "size"; 11317 options.queue = false; 11318 options.complete = done; 11319 11320 // Set default origin and restore for show/hide 11321 if ( mode !== "effect" ) { 11322 options.origin = origin || [ "middle", "center" ]; 11323 options.restore = true; 11324 } 11325 11326 options.from = o.from || ( mode === "show" ? { 11327 height: 0, 11328 width: 0, 11329 outerHeight: 0, 11330 outerWidth: 0 11331 } : original ); 11332 options.to = { 11333 height: original.height * factor.y, 11334 width: original.width * factor.x, 11335 outerHeight: original.outerHeight * factor.y, 11336 outerWidth: original.outerWidth * factor.x 11337 }; 11338 11339 // Fade option to support puff 11340 if ( options.fade ) { 11341 if ( mode === "show" ) { 11342 options.from.opacity = 0; 11343 options.to.opacity = 1; 11344 } 11345 if ( mode === "hide" ) { 11346 options.from.opacity = 1; 11347 options.to.opacity = 0; 11348 } 11349 } 11350 11351 // Animate 11352 el.effect( options ); 11353 11354 }; 11355 11356 11357 /*! 11358 * jQuery UI Effects Puff 1.11.1 11359 * http://jqueryui.com 11360 * 11361 * Copyright 2014 jQuery Foundation and other contributors 11362 * Released under the MIT license. 11363 * http://jquery.org/license 11364 * 11365 * http://api.jqueryui.com/puff-effect/ 11366 */ 11367 11368 11369 var effectPuff = $.effects.effect.puff = function( o, done ) { 11370 var elem = $( this ), 11371 mode = $.effects.setMode( elem, o.mode || "hide" ), 11372 hide = mode === "hide", 11373 percent = parseInt( o.percent, 10 ) || 150, 11374 factor = percent / 100, 11375 original = { 11376 height: elem.height(), 11377 width: elem.width(), 11378 outerHeight: elem.outerHeight(), 11379 outerWidth: elem.outerWidth() 11380 }; 11381 11382 $.extend( o, { 11383 effect: "scale", 11384 queue: false, 11385 fade: true, 11386 mode: mode, 11387 complete: done, 11388 percent: hide ? percent : 100, 11389 from: hide ? 11390 original : 11391 { 11392 height: original.height * factor, 11393 width: original.width * factor, 11394 outerHeight: original.outerHeight * factor, 11395 outerWidth: original.outerWidth * factor 11396 } 11397 }); 11398 11399 elem.effect( o ); 11400 }; 11401 11402 11403 /*! 11404 * jQuery UI Effects Pulsate 1.11.1 11405 * http://jqueryui.com 11406 * 11407 * Copyright 2014 jQuery Foundation and other contributors 11408 * Released under the MIT license. 11409 * http://jquery.org/license 11410 * 11411 * http://api.jqueryui.com/pulsate-effect/ 11412 */ 11413 11414 11415 var effectPulsate = $.effects.effect.pulsate = function( o, done ) { 11416 var elem = $( this ), 11417 mode = $.effects.setMode( elem, o.mode || "show" ), 11418 show = mode === "show", 11419 hide = mode === "hide", 11420 showhide = ( show || mode === "hide" ), 11421 11422 // showing or hiding leaves of the "last" animation 11423 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), 11424 duration = o.duration / anims, 11425 animateTo = 0, 11426 queue = elem.queue(), 11427 queuelen = queue.length, 11428 i; 11429 11430 if ( show || !elem.is(":visible")) { 11431 elem.css( "opacity", 0 ).show(); 11432 animateTo = 1; 11433 } 11434 11435 // anims - 1 opacity "toggles" 11436 for ( i = 1; i < anims; i++ ) { 11437 elem.animate({ 11438 opacity: animateTo 11439 }, duration, o.easing ); 11440 animateTo = 1 - animateTo; 11441 } 11442 11443 elem.animate({ 11444 opacity: animateTo 11445 }, duration, o.easing); 11446 11447 elem.queue(function() { 11448 if ( hide ) { 11449 elem.hide(); 11450 } 11451 done(); 11452 }); 11453 11454 // We just queued up "anims" animations, we need to put them next in the queue 11455 if ( queuelen > 1 ) { 11456 queue.splice.apply( queue, 11457 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); 11458 } 11459 elem.dequeue(); 11460 }; 11461 11462 11463 /*! 11464 * jQuery UI Effects Shake 1.11.1 11465 * http://jqueryui.com 11466 * 11467 * Copyright 2014 jQuery Foundation and other contributors 11468 * Released under the MIT license. 11469 * http://jquery.org/license 11470 * 11471 * http://api.jqueryui.com/shake-effect/ 11472 */ 11473 11474 11475 var effectShake = $.effects.effect.shake = function( o, done ) { 11476 11477 var el = $( this ), 11478 props = [ "position", "top", "bottom", "left", "right", "height", "width" ], 11479 mode = $.effects.setMode( el, o.mode || "effect" ), 11480 direction = o.direction || "left", 11481 distance = o.distance || 20, 11482 times = o.times || 3, 11483 anims = times * 2 + 1, 11484 speed = Math.round( o.duration / anims ), 11485 ref = (direction === "up" || direction === "down") ? "top" : "left", 11486 positiveMotion = (direction === "up" || direction === "left"), 11487 animation = {}, 11488 animation1 = {}, 11489 animation2 = {}, 11490 i, 11491 11492 // we will need to re-assemble the queue to stack our animations in place 11493 queue = el.queue(), 11494 queuelen = queue.length; 11495 11496 $.effects.save( el, props ); 11497 el.show(); 11498 $.effects.createWrapper( el ); 11499 11500 // Animation 11501 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; 11502 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; 11503 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; 11504 11505 // Animate 11506 el.animate( animation, speed, o.easing ); 11507 11508 // Shakes 11509 for ( i = 1; i < times; i++ ) { 11510 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing ); 11511 } 11512 el 11513 .animate( animation1, speed, o.easing ) 11514 .animate( animation, speed / 2, o.easing ) 11515 .queue(function() { 11516 if ( mode === "hide" ) { 11517 el.hide(); 11518 } 11519 $.effects.restore( el, props ); 11520 $.effects.removeWrapper( el ); 11521 done(); 11522 }); 11523 11524 // inject all the animations we just queued to be first in line (after "inprogress") 11525 if ( queuelen > 1) { 11526 queue.splice.apply( queue, 11527 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) ); 11528 } 11529 el.dequeue(); 11530 11531 }; 11532 11533 11534 /*! 11535 * jQuery UI Effects Slide 1.11.1 11536 * http://jqueryui.com 11537 * 11538 * Copyright 2014 jQuery Foundation and other contributors 11539 * Released under the MIT license. 11540 * http://jquery.org/license 11541 * 11542 * http://api.jqueryui.com/slide-effect/ 11543 */ 11544 11545 11546 var effectSlide = $.effects.effect.slide = function( o, done ) { 11547 11548 // Create element 11549 var el = $( this ), 11550 props = [ "position", "top", "bottom", "left", "right", "width", "height" ], 11551 mode = $.effects.setMode( el, o.mode || "show" ), 11552 show = mode === "show", 11553 direction = o.direction || "left", 11554 ref = (direction === "up" || direction === "down") ? "top" : "left", 11555 positiveMotion = (direction === "up" || direction === "left"), 11556 distance, 11557 animation = {}; 11558 11559 // Adjust 11560 $.effects.save( el, props ); 11561 el.show(); 11562 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ); 11563 11564 $.effects.createWrapper( el ).css({ 11565 overflow: "hidden" 11566 }); 11567 11568 if ( show ) { 11569 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance ); 11570 } 11571 11572 // Animation 11573 animation[ ref ] = ( show ? 11574 ( positiveMotion ? "+=" : "-=") : 11575 ( positiveMotion ? "-=" : "+=")) + 11576 distance; 11577 11578 // Animate 11579 el.animate( animation, { 11580 queue: false, 11581 duration: o.duration, 11582 easing: o.easing, 11583 complete: function() { 11584 if ( mode === "hide" ) { 11585 el.hide(); 11586 } 11587 $.effects.restore( el, props ); 11588 $.effects.removeWrapper( el ); 11589 done(); 11590 } 11591 }); 11592 }; 11593 11594 11595 /*! 11596 * jQuery UI Effects Transfer 1.11.1 11597 * http://jqueryui.com 11598 * 11599 * Copyright 2014 jQuery Foundation and other contributors 11600 * Released under the MIT license. 11601 * http://jquery.org/license 11602 * 11603 * http://api.jqueryui.com/transfer-effect/ 11604 */ 11605 11606 11607 var effectTransfer = $.effects.effect.transfer = function( o, done ) { 11608 var elem = $( this ), 11609 target = $( o.to ), 11610 targetFixed = target.css( "position" ) === "fixed", 11611 body = $("body"), 11612 fixTop = targetFixed ? body.scrollTop() : 0, 11613 fixLeft = targetFixed ? body.scrollLeft() : 0, 11614 endPosition = target.offset(), 11615 animation = { 11616 top: endPosition.top - fixTop, 11617 left: endPosition.left - fixLeft, 11618 height: target.innerHeight(), 11619 width: target.innerWidth() 11620 }, 11621 startPosition = elem.offset(), 11622 transfer = $( "<div class='ui-effects-transfer'></div>" ) 11623 .appendTo( document.body ) 11624 .addClass( o.className ) 11625 .css({ 11626 top: startPosition.top - fixTop, 11627 left: startPosition.left - fixLeft, 11628 height: elem.innerHeight(), 11629 width: elem.innerWidth(), 11630 position: targetFixed ? "fixed" : "absolute" 11631 }) 11632 .animate( animation, o.duration, o.easing, function() { 11633 transfer.remove(); 11634 done(); 11635 }); 11636 }; 11637 11638 11639 /*! 11640 * jQuery UI Progressbar 1.11.1 11641 * http://jqueryui.com 11642 * 11643 * Copyright 2014 jQuery Foundation and other contributors 11644 * Released under the MIT license. 11645 * http://jquery.org/license 11646 * 11647 * http://api.jqueryui.com/progressbar/ 11648 */ 11649 11650 11651 var progressbar = $.widget( "ui.progressbar", { 11652 version: "1.11.1", 11653 options: { 11654 max: 100, 11655 value: 0, 11656 11657 change: null, 11658 complete: null 11659 }, 11660 11661 min: 0, 11662 11663 _create: function() { 11664 // Constrain initial value 11665 this.oldValue = this.options.value = this._constrainedValue(); 11666 11667 this.element 11668 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) 11669 .attr({ 11670 // Only set static values, aria-valuenow and aria-valuemax are 11671 // set inside _refreshValue() 11672 role: "progressbar", 11673 "aria-valuemin": this.min 11674 }); 11675 11676 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" ) 11677 .appendTo( this.element ); 11678 11679 this._refreshValue(); 11680 }, 11681 11682 _destroy: function() { 11683 this.element 11684 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" ) 11685 .removeAttr( "role" ) 11686 .removeAttr( "aria-valuemin" ) 11687 .removeAttr( "aria-valuemax" ) 11688 .removeAttr( "aria-valuenow" ); 11689 11690 this.valueDiv.remove(); 11691 }, 11692 11693 value: function( newValue ) { 11694 if ( newValue === undefined ) { 11695 return this.options.value; 11696 } 11697 11698 this.options.value = this._constrainedValue( newValue ); 11699 this._refreshValue(); 11700 }, 11701 11702 _constrainedValue: function( newValue ) { 11703 if ( newValue === undefined ) { 11704 newValue = this.options.value; 11705 } 11706 11707 this.indeterminate = newValue === false; 11708 11709 // sanitize value 11710 if ( typeof newValue !== "number" ) { 11711 newValue = 0; 11712 } 11713 11714 return this.indeterminate ? false : 11715 Math.min( this.options.max, Math.max( this.min, newValue ) ); 11716 }, 11717 11718 _setOptions: function( options ) { 11719 // Ensure "value" option is set after other values (like max) 11720 var value = options.value; 11721 delete options.value; 11722 11723 this._super( options ); 11724 11725 this.options.value = this._constrainedValue( value ); 11726 this._refreshValue(); 11727 }, 11728 11729 _setOption: function( key, value ) { 11730 if ( key === "max" ) { 11731 // Don't allow a max less than min 11732 value = Math.max( this.min, value ); 11733 } 11734 if ( key === "disabled" ) { 11735 this.element 11736 .toggleClass( "ui-state-disabled", !!value ) 11737 .attr( "aria-disabled", value ); 11738 } 11739 this._super( key, value ); 11740 }, 11741 11742 _percentage: function() { 11743 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); 11744 }, 11745 11746 _refreshValue: function() { 11747 var value = this.options.value, 11748 percentage = this._percentage(); 11749 11750 this.valueDiv 11751 .toggle( this.indeterminate || value > this.min ) 11752 .toggleClass( "ui-corner-right", value === this.options.max ) 11753 .width( percentage.toFixed(0) + "%" ); 11754 11755 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate ); 11756 11757 if ( this.indeterminate ) { 11758 this.element.removeAttr( "aria-valuenow" ); 11759 if ( !this.overlayDiv ) { 11760 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv ); 11761 } 11762 } else { 11763 this.element.attr({ 11764 "aria-valuemax": this.options.max, 11765 "aria-valuenow": value 11766 }); 11767 if ( this.overlayDiv ) { 11768 this.overlayDiv.remove(); 11769 this.overlayDiv = null; 11770 } 11771 } 11772 11773 if ( this.oldValue !== value ) { 11774 this.oldValue = value; 11775 this._trigger( "change" ); 11776 } 11777 if ( value === this.options.max ) { 11778 this._trigger( "complete" ); 11779 } 11780 } 11781 }); 11782 11783 11784 /*! 11785 * jQuery UI Selectable 1.11.1 11786 * http://jqueryui.com 11787 * 11788 * Copyright 2014 jQuery Foundation and other contributors 11789 * Released under the MIT license. 11790 * http://jquery.org/license 11791 * 11792 * http://api.jqueryui.com/selectable/ 11793 */ 11794 11795 11796 var selectable = $.widget("ui.selectable", $.ui.mouse, { 11797 version: "1.11.1", 11798 options: { 11799 appendTo: "body", 11800 autoRefresh: true, 11801 distance: 0, 11802 filter: "*", 11803 tolerance: "touch", 11804 11805 // callbacks 11806 selected: null, 11807 selecting: null, 11808 start: null, 11809 stop: null, 11810 unselected: null, 11811 unselecting: null 11812 }, 11813 _create: function() { 11814 var selectees, 11815 that = this; 11816 11817 this.element.addClass("ui-selectable"); 11818 11819 this.dragged = false; 11820 11821 // cache selectee children based on filter 11822 this.refresh = function() { 11823 selectees = $(that.options.filter, that.element[0]); 11824 selectees.addClass("ui-selectee"); 11825 selectees.each(function() { 11826 var $this = $(this), 11827 pos = $this.offset(); 11828 $.data(this, "selectable-item", { 11829 element: this, 11830 $element: $this, 11831 left: pos.left, 11832 top: pos.top, 11833 right: pos.left + $this.outerWidth(), 11834 bottom: pos.top + $this.outerHeight(), 11835 startselected: false, 11836 selected: $this.hasClass("ui-selected"), 11837 selecting: $this.hasClass("ui-selecting"), 11838 unselecting: $this.hasClass("ui-unselecting") 11839 }); 11840 }); 11841 }; 11842 this.refresh(); 11843 11844 this.selectees = selectees.addClass("ui-selectee"); 11845 11846 this._mouseInit(); 11847 11848 this.helper = $("<div class='ui-selectable-helper'></div>"); 11849 }, 11850 11851 _destroy: function() { 11852 this.selectees 11853 .removeClass("ui-selectee") 11854 .removeData("selectable-item"); 11855 this.element 11856 .removeClass("ui-selectable ui-selectable-disabled"); 11857 this._mouseDestroy(); 11858 }, 11859 11860 _mouseStart: function(event) { 11861 var that = this, 11862 options = this.options; 11863 11864 this.opos = [ event.pageX, event.pageY ]; 11865 11866 if (this.options.disabled) { 11867 return; 11868 } 11869 11870 this.selectees = $(options.filter, this.element[0]); 11871 11872 this._trigger("start", event); 11873 11874 $(options.appendTo).append(this.helper); 11875 // position helper (lasso) 11876 this.helper.css({ 11877 "left": event.pageX, 11878 "top": event.pageY, 11879 "width": 0, 11880 "height": 0 11881 }); 11882 11883 if (options.autoRefresh) { 11884 this.refresh(); 11885 } 11886 11887 this.selectees.filter(".ui-selected").each(function() { 11888 var selectee = $.data(this, "selectable-item"); 11889 selectee.startselected = true; 11890 if (!event.metaKey && !event.ctrlKey) { 11891 selectee.$element.removeClass("ui-selected"); 11892 selectee.selected = false; 11893 selectee.$element.addClass("ui-unselecting"); 11894 selectee.unselecting = true; 11895 // selectable UNSELECTING callback 11896 that._trigger("unselecting", event, { 11897 unselecting: selectee.element 11898 }); 11899 } 11900 }); 11901 11902 $(event.target).parents().addBack().each(function() { 11903 var doSelect, 11904 selectee = $.data(this, "selectable-item"); 11905 if (selectee) { 11906 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); 11907 selectee.$element 11908 .removeClass(doSelect ? "ui-unselecting" : "ui-selected") 11909 .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); 11910 selectee.unselecting = !doSelect; 11911 selectee.selecting = doSelect; 11912 selectee.selected = doSelect; 11913 // selectable (UN)SELECTING callback 11914 if (doSelect) { 11915 that._trigger("selecting", event, { 11916 selecting: selectee.element 11917 }); 11918 } else { 11919 that._trigger("unselecting", event, { 11920 unselecting: selectee.element 11921 }); 11922 } 11923 return false; 11924 } 11925 }); 11926 11927 }, 11928 11929 _mouseDrag: function(event) { 11930 11931 this.dragged = true; 11932 11933 if (this.options.disabled) { 11934 return; 11935 } 11936 11937 var tmp, 11938 that = this, 11939 options = this.options, 11940 x1 = this.opos[0], 11941 y1 = this.opos[1], 11942 x2 = event.pageX, 11943 y2 = event.pageY; 11944 11945 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } 11946 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } 11947 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 }); 11948 11949 this.selectees.each(function() { 11950 var selectee = $.data(this, "selectable-item"), 11951 hit = false; 11952 11953 //prevent helper from being selected if appendTo: selectable 11954 if (!selectee || selectee.element === that.element[0]) { 11955 return; 11956 } 11957 11958 if (options.tolerance === "touch") { 11959 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); 11960 } else if (options.tolerance === "fit") { 11961 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); 11962 } 11963 11964 if (hit) { 11965 // SELECT 11966 if (selectee.selected) { 11967 selectee.$element.removeClass("ui-selected"); 11968 selectee.selected = false; 11969 } 11970 if (selectee.unselecting) { 11971 selectee.$element.removeClass("ui-unselecting"); 11972 selectee.unselecting = false; 11973 } 11974 if (!selectee.selecting) { 11975 selectee.$element.addClass("ui-selecting"); 11976 selectee.selecting = true; 11977 // selectable SELECTING callback 11978 that._trigger("selecting", event, { 11979 selecting: selectee.element 11980 }); 11981 } 11982 } else { 11983 // UNSELECT 11984 if (selectee.selecting) { 11985 if ((event.metaKey || event.ctrlKey) && selectee.startselected) { 11986 selectee.$element.removeClass("ui-selecting"); 11987 selectee.selecting = false; 11988 selectee.$element.addClass("ui-selected"); 11989 selectee.selected = true; 11990 } else { 11991 selectee.$element.removeClass("ui-selecting"); 11992 selectee.selecting = false; 11993 if (selectee.startselected) { 11994 selectee.$element.addClass("ui-unselecting"); 11995 selectee.unselecting = true; 11996 } 11997 // selectable UNSELECTING callback 11998 that._trigger("unselecting", event, { 11999 unselecting: selectee.element 12000 }); 12001 } 12002 } 12003 if (selectee.selected) { 12004 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { 12005 selectee.$element.removeClass("ui-selected"); 12006 selectee.selected = false; 12007 12008 selectee.$element.addClass("ui-unselecting"); 12009 selectee.unselecting = true; 12010 // selectable UNSELECTING callback 12011 that._trigger("unselecting", event, { 12012 unselecting: selectee.element 12013 }); 12014 } 12015 } 12016 } 12017 }); 12018 12019 return false; 12020 }, 12021 12022 _mouseStop: function(event) { 12023 var that = this; 12024 12025 this.dragged = false; 12026 12027 $(".ui-unselecting", this.element[0]).each(function() { 12028 var selectee = $.data(this, "selectable-item"); 12029 selectee.$element.removeClass("ui-unselecting"); 12030 selectee.unselecting = false; 12031 selectee.startselected = false; 12032 that._trigger("unselected", event, { 12033 unselected: selectee.element 12034 }); 12035 }); 12036 $(".ui-selecting", this.element[0]).each(function() { 12037 var selectee = $.data(this, "selectable-item"); 12038 selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); 12039 selectee.selecting = false; 12040 selectee.selected = true; 12041 selectee.startselected = true; 12042 that._trigger("selected", event, { 12043 selected: selectee.element 12044 }); 12045 }); 12046 this._trigger("stop", event); 12047 12048 this.helper.remove(); 12049 12050 return false; 12051 } 12052 12053 }); 12054 12055 12056 /*! 12057 * jQuery UI Selectmenu 1.11.1 12058 * http://jqueryui.com 12059 * 12060 * Copyright 2014 jQuery Foundation and other contributors 12061 * Released under the MIT license. 12062 * http://jquery.org/license 12063 * 12064 * http://api.jqueryui.com/selectmenu 12065 */ 12066 12067 12068 var selectmenu = $.widget( "ui.selectmenu", { 12069 version: "1.11.1", 12070 defaultElement: "<select>", 12071 options: { 12072 appendTo: null, 12073 disabled: null, 12074 icons: { 12075 button: "ui-icon-triangle-1-s" 12076 }, 12077 position: { 12078 my: "left top", 12079 at: "left bottom", 12080 collision: "none" 12081 }, 12082 width: null, 12083 12084 // callbacks 12085 change: null, 12086 close: null, 12087 focus: null, 12088 open: null, 12089 select: null 12090 }, 12091 12092 _create: function() { 12093 var selectmenuId = this.element.uniqueId().attr( "id" ); 12094 this.ids = { 12095 element: selectmenuId, 12096 button: selectmenuId + "-button", 12097 menu: selectmenuId + "-menu" 12098 }; 12099 12100 this._drawButton(); 12101 this._drawMenu(); 12102 12103 if ( this.options.disabled ) { 12104 this.disable(); 12105 } 12106 }, 12107 12108 _drawButton: function() { 12109 var that = this, 12110 tabindex = this.element.attr( "tabindex" ); 12111 12112 // Associate existing label with the new button 12113 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button ); 12114 this._on( this.label, { 12115 click: function( event ) { 12116 this.button.focus(); 12117 event.preventDefault(); 12118 } 12119 }); 12120 12121 // Hide original select element 12122 this.element.hide(); 12123 12124 // Create button 12125 this.button = $( "<span>", { 12126 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all", 12127 tabindex: tabindex || this.options.disabled ? -1 : 0, 12128 id: this.ids.button, 12129 role: "combobox", 12130 "aria-expanded": "false", 12131 "aria-autocomplete": "list", 12132 "aria-owns": this.ids.menu, 12133 "aria-haspopup": "true" 12134 }) 12135 .insertAfter( this.element ); 12136 12137 $( "<span>", { 12138 "class": "ui-icon " + this.options.icons.button 12139 }) 12140 .prependTo( this.button ); 12141 12142 this.buttonText = $( "<span>", { 12143 "class": "ui-selectmenu-text" 12144 }) 12145 .appendTo( this.button ); 12146 12147 this._setText( this.buttonText, this.element.find( "option:selected" ).text() ); 12148 this._resizeButton(); 12149 12150 this._on( this.button, this._buttonEvents ); 12151 this.button.one( "focusin", function() { 12152 12153 // Delay rendering the menu items until the button receives focus. 12154 // The menu may have already been rendered via a programmatic open. 12155 if ( !that.menuItems ) { 12156 that._refreshMenu(); 12157 } 12158 }); 12159 this._hoverable( this.button ); 12160 this._focusable( this.button ); 12161 }, 12162 12163 _drawMenu: function() { 12164 var that = this; 12165 12166 // Create menu 12167 this.menu = $( "<ul>", { 12168 "aria-hidden": "true", 12169 "aria-labelledby": this.ids.button, 12170 id: this.ids.menu 12171 }); 12172 12173 // Wrap menu 12174 this.menuWrap = $( "<div>", { 12175 "class": "ui-selectmenu-menu ui-front" 12176 }) 12177 .append( this.menu ) 12178 .appendTo( this._appendTo() ); 12179 12180 // Initialize menu widget 12181 this.menuInstance = this.menu 12182 .menu({ 12183 role: "listbox", 12184 select: function( event, ui ) { 12185 event.preventDefault(); 12186 that._select( ui.item.data( "ui-selectmenu-item" ), event ); 12187 }, 12188 focus: function( event, ui ) { 12189 var item = ui.item.data( "ui-selectmenu-item" ); 12190 12191 // Prevent inital focus from firing and check if its a newly focused item 12192 if ( that.focusIndex != null && item.index !== that.focusIndex ) { 12193 that._trigger( "focus", event, { item: item } ); 12194 if ( !that.isOpen ) { 12195 that._select( item, event ); 12196 } 12197 } 12198 that.focusIndex = item.index; 12199 12200 that.button.attr( "aria-activedescendant", 12201 that.menuItems.eq( item.index ).attr( "id" ) ); 12202 } 12203 }) 12204 .menu( "instance" ); 12205 12206 // Adjust menu styles to dropdown 12207 this.menu 12208 .addClass( "ui-corner-bottom" ) 12209 .removeClass( "ui-corner-all" ); 12210 12211 // Don't close the menu on mouseleave 12212 this.menuInstance._off( this.menu, "mouseleave" ); 12213 12214 // Cancel the menu's collapseAll on document click 12215 this.menuInstance._closeOnDocumentClick = function() { 12216 return false; 12217 }; 12218 12219 // Selects often contain empty items, but never contain dividers 12220 this.menuInstance._isDivider = function() { 12221 return false; 12222 }; 12223 }, 12224 12225 refresh: function() { 12226 this._refreshMenu(); 12227 this._setText( this.buttonText, this._getSelectedItem().text() ); 12228 if ( !this.options.width ) { 12229 this._resizeButton(); 12230 } 12231 }, 12232 12233 _refreshMenu: function() { 12234 this.menu.empty(); 12235 12236 var item, 12237 options = this.element.find( "option" ); 12238 12239 if ( !options.length ) { 12240 return; 12241 } 12242 12243 this._parseOptions( options ); 12244 this._renderMenu( this.menu, this.items ); 12245 12246 this.menuInstance.refresh(); 12247 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" ); 12248 12249 item = this._getSelectedItem(); 12250 12251 // Update the menu to have the correct item focused 12252 this.menuInstance.focus( null, item ); 12253 this._setAria( item.data( "ui-selectmenu-item" ) ); 12254 12255 // Set disabled state 12256 this._setOption( "disabled", this.element.prop( "disabled" ) ); 12257 }, 12258 12259 open: function( event ) { 12260 if ( this.options.disabled ) { 12261 return; 12262 } 12263 12264 // If this is the first time the menu is being opened, render the items 12265 if ( !this.menuItems ) { 12266 this._refreshMenu(); 12267 } else { 12268 12269 // Menu clears focus on close, reset focus to selected item 12270 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" ); 12271 this.menuInstance.focus( null, this._getSelectedItem() ); 12272 } 12273 12274 this.isOpen = true; 12275 this._toggleAttr(); 12276 this._resizeMenu(); 12277 this._position(); 12278 12279 this._on( this.document, this._documentClick ); 12280 12281 this._trigger( "open", event ); 12282 }, 12283 12284 _position: function() { 12285 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) ); 12286 }, 12287 12288 close: function( event ) { 12289 if ( !this.isOpen ) { 12290 return; 12291 } 12292 12293 this.isOpen = false; 12294 this._toggleAttr(); 12295 12296 this._off( this.document ); 12297 12298 this._trigger( "close", event ); 12299 }, 12300 12301 widget: function() { 12302 return this.button; 12303 }, 12304 12305 menuWidget: function() { 12306 return this.menu; 12307 }, 12308 12309 _renderMenu: function( ul, items ) { 12310 var that = this, 12311 currentOptgroup = ""; 12312 12313 $.each( items, function( index, item ) { 12314 if ( item.optgroup !== currentOptgroup ) { 12315 $( "<li>", { 12316 "class": "ui-selectmenu-optgroup ui-menu-divider" + 12317 ( item.element.parent( "optgroup" ).prop( "disabled" ) ? 12318 " ui-state-disabled" : 12319 "" ), 12320 text: item.optgroup 12321 }) 12322 .appendTo( ul ); 12323 12324 currentOptgroup = item.optgroup; 12325 } 12326 12327 that._renderItemData( ul, item ); 12328 }); 12329 }, 12330 12331 _renderItemData: function( ul, item ) { 12332 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item ); 12333 }, 12334 12335 _renderItem: function( ul, item ) { 12336 var li = $( "<li>" ); 12337 12338 if ( item.disabled ) { 12339 li.addClass( "ui-state-disabled" ); 12340 } 12341 this._setText( li, item.label ); 12342 12343 return li.appendTo( ul ); 12344 }, 12345 12346 _setText: function( element, value ) { 12347 if ( value ) { 12348 element.text( value ); 12349 } else { 12350 element.html( " " ); 12351 } 12352 }, 12353 12354 _move: function( direction, event ) { 12355 var item, next, 12356 filter = ".ui-menu-item"; 12357 12358 if ( this.isOpen ) { 12359 item = this.menuItems.eq( this.focusIndex ); 12360 } else { 12361 item = this.menuItems.eq( this.element[ 0 ].selectedIndex ); 12362 filter += ":not(.ui-state-disabled)"; 12363 } 12364 12365 if ( direction === "first" || direction === "last" ) { 12366 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 ); 12367 } else { 12368 next = item[ direction + "All" ]( filter ).eq( 0 ); 12369 } 12370 12371 if ( next.length ) { 12372 this.menuInstance.focus( event, next ); 12373 } 12374 }, 12375 12376 _getSelectedItem: function() { 12377 return this.menuItems.eq( this.element[ 0 ].selectedIndex ); 12378 }, 12379 12380 _toggle: function( event ) { 12381 this[ this.isOpen ? "close" : "open" ]( event ); 12382 }, 12383 12384 _documentClick: { 12385 mousedown: function( event ) { 12386 if ( !this.isOpen ) { 12387 return; 12388 } 12389 12390 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) { 12391 this.close( event ); 12392 } 12393 } 12394 }, 12395 12396 _buttonEvents: { 12397 12398 // Prevent text selection from being reset when interacting with the selectmenu (#10144) 12399 mousedown: function( event ) { 12400 event.preventDefault(); 12401 }, 12402 12403 click: "_toggle", 12404 12405 keydown: function( event ) { 12406 var preventDefault = true; 12407 switch ( event.keyCode ) { 12408 case $.ui.keyCode.TAB: 12409 case $.ui.keyCode.ESCAPE: 12410 this.close( event ); 12411 preventDefault = false; 12412 break; 12413 case $.ui.keyCode.ENTER: 12414 if ( this.isOpen ) { 12415 this._selectFocusedItem( event ); 12416 } 12417 break; 12418 case $.ui.keyCode.UP: 12419 if ( event.altKey ) { 12420 this._toggle( event ); 12421 } else { 12422 this._move( "prev", event ); 12423 } 12424 break; 12425 case $.ui.keyCode.DOWN: 12426 if ( event.altKey ) { 12427 this._toggle( event ); 12428 } else { 12429 this._move( "next", event ); 12430 } 12431 break; 12432 case $.ui.keyCode.SPACE: 12433 if ( this.isOpen ) { 12434 this._selectFocusedItem( event ); 12435 } else { 12436 this._toggle( event ); 12437 } 12438 break; 12439 case $.ui.keyCode.LEFT: 12440 this._move( "prev", event ); 12441 break; 12442 case $.ui.keyCode.RIGHT: 12443 this._move( "next", event ); 12444 break; 12445 case $.ui.keyCode.HOME: 12446 case $.ui.keyCode.PAGE_UP: 12447 this._move( "first", event ); 12448 break; 12449 case $.ui.keyCode.END: 12450 case $.ui.keyCode.PAGE_DOWN: 12451 this._move( "last", event ); 12452 break; 12453 default: 12454 this.menu.trigger( event ); 12455 preventDefault = false; 12456 } 12457 12458 if ( preventDefault ) { 12459 event.preventDefault(); 12460 } 12461 } 12462 }, 12463 12464 _selectFocusedItem: function( event ) { 12465 var item = this.menuItems.eq( this.focusIndex ); 12466 if ( !item.hasClass( "ui-state-disabled" ) ) { 12467 this._select( item.data( "ui-selectmenu-item" ), event ); 12468 } 12469 }, 12470 12471 _select: function( item, event ) { 12472 var oldIndex = this.element[ 0 ].selectedIndex; 12473 12474 // Change native select element 12475 this.element[ 0 ].selectedIndex = item.index; 12476 this._setText( this.buttonText, item.label ); 12477 this._setAria( item ); 12478 this._trigger( "select", event, { item: item } ); 12479 12480 if ( item.index !== oldIndex ) { 12481 this._trigger( "change", event, { item: item } ); 12482 } 12483 12484 this.close( event ); 12485 }, 12486 12487 _setAria: function( item ) { 12488 var id = this.menuItems.eq( item.index ).attr( "id" ); 12489 12490 this.button.attr({ 12491 "aria-labelledby": id, 12492 "aria-activedescendant": id 12493 }); 12494 this.menu.attr( "aria-activedescendant", id ); 12495 }, 12496 12497 _setOption: function( key, value ) { 12498 if ( key === "icons" ) { 12499 this.button.find( "span.ui-icon" ) 12500 .removeClass( this.options.icons.button ) 12501 .addClass( value.button ); 12502 } 12503 12504 this._super( key, value ); 12505 12506 if ( key === "appendTo" ) { 12507 this.menuWrap.appendTo( this._appendTo() ); 12508 } 12509 12510 if ( key === "disabled" ) { 12511 this.menuInstance.option( "disabled", value ); 12512 this.button 12513 .toggleClass( "ui-state-disabled", value ) 12514 .attr( "aria-disabled", value ); 12515 12516 this.element.prop( "disabled", value ); 12517 if ( value ) { 12518 this.button.attr( "tabindex", -1 ); 12519 this.close(); 12520 } else { 12521 this.button.attr( "tabindex", 0 ); 12522 } 12523 } 12524 12525 if ( key === "width" ) { 12526 this._resizeButton(); 12527 } 12528 }, 12529 12530 _appendTo: function() { 12531 var element = this.options.appendTo; 12532 12533 if ( element ) { 12534 element = element.jquery || element.nodeType ? 12535 $( element ) : 12536 this.document.find( element ).eq( 0 ); 12537 } 12538 12539 if ( !element || !element[ 0 ] ) { 12540 element = this.element.closest( ".ui-front" ); 12541 } 12542 12543 if ( !element.length ) { 12544 element = this.document[ 0 ].body; 12545 } 12546 12547 return element; 12548 }, 12549 12550 _toggleAttr: function() { 12551 this.button 12552 .toggleClass( "ui-corner-top", this.isOpen ) 12553 .toggleClass( "ui-corner-all", !this.isOpen ) 12554 .attr( "aria-expanded", this.isOpen ); 12555 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen ); 12556 this.menu.attr( "aria-hidden", !this.isOpen ); 12557 }, 12558 12559 _resizeButton: function() { 12560 var width = this.options.width; 12561 12562 if ( !width ) { 12563 width = this.element.show().outerWidth(); 12564 this.element.hide(); 12565 } 12566 12567 this.button.outerWidth( width ); 12568 }, 12569 12570 _resizeMenu: function() { 12571 this.menu.outerWidth( Math.max( 12572 this.button.outerWidth(), 12573 12574 // support: IE10 12575 // IE10 wraps long text (possibly a rounding bug) 12576 // so we add 1px to avoid the wrapping 12577 this.menu.width( "" ).outerWidth() + 1 12578 ) ); 12579 }, 12580 12581 _getCreateOptions: function() { 12582 return { disabled: this.element.prop( "disabled" ) }; 12583 }, 12584 12585 _parseOptions: function( options ) { 12586 var data = []; 12587 options.each(function( index, item ) { 12588 var option = $( item ), 12589 optgroup = option.parent( "optgroup" ); 12590 data.push({ 12591 element: option, 12592 index: index, 12593 value: option.attr( "value" ), 12594 label: option.text(), 12595 optgroup: optgroup.attr( "label" ) || "", 12596 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" ) 12597 }); 12598 }); 12599 this.items = data; 12600 }, 12601 12602 _destroy: function() { 12603 this.menuWrap.remove(); 12604 this.button.remove(); 12605 this.element.show(); 12606 this.element.removeUniqueId(); 12607 this.label.attr( "for", this.ids.element ); 12608 } 12609 }); 12610 12611 12612 /*! 12613 * jQuery UI Slider 1.11.1 12614 * http://jqueryui.com 12615 * 12616 * Copyright 2014 jQuery Foundation and other contributors 12617 * Released under the MIT license. 12618 * http://jquery.org/license 12619 * 12620 * http://api.jqueryui.com/slider/ 12621 */ 12622 12623 12624 var slider = $.widget( "ui.slider", $.ui.mouse, { 12625 version: "1.11.1", 12626 widgetEventPrefix: "slide", 12627 12628 options: { 12629 animate: false, 12630 distance: 0, 12631 max: 100, 12632 min: 0, 12633 orientation: "horizontal", 12634 range: false, 12635 step: 1, 12636 value: 0, 12637 values: null, 12638 12639 // callbacks 12640 change: null, 12641 slide: null, 12642 start: null, 12643 stop: null 12644 }, 12645 12646 // number of pages in a slider 12647 // (how many times can you page up/down to go through the whole range) 12648 numPages: 5, 12649 12650 _create: function() { 12651 this._keySliding = false; 12652 this._mouseSliding = false; 12653 this._animateOff = true; 12654 this._handleIndex = null; 12655 this._detectOrientation(); 12656 this._mouseInit(); 12657 12658 this.element 12659 .addClass( "ui-slider" + 12660 " ui-slider-" + this.orientation + 12661 " ui-widget" + 12662 " ui-widget-content" + 12663 " ui-corner-all"); 12664 12665 this._refresh(); 12666 this._setOption( "disabled", this.options.disabled ); 12667 12668 this._animateOff = false; 12669 }, 12670 12671 _refresh: function() { 12672 this._createRange(); 12673 this._createHandles(); 12674 this._setupEvents(); 12675 this._refreshValue(); 12676 }, 12677 12678 _createHandles: function() { 12679 var i, handleCount, 12680 options = this.options, 12681 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ), 12682 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>", 12683 handles = []; 12684 12685 handleCount = ( options.values && options.values.length ) || 1; 12686 12687 if ( existingHandles.length > handleCount ) { 12688 existingHandles.slice( handleCount ).remove(); 12689 existingHandles = existingHandles.slice( 0, handleCount ); 12690 } 12691 12692 for ( i = existingHandles.length; i < handleCount; i++ ) { 12693 handles.push( handle ); 12694 } 12695 12696 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) ); 12697 12698 this.handle = this.handles.eq( 0 ); 12699 12700 this.handles.each(function( i ) { 12701 $( this ).data( "ui-slider-handle-index", i ); 12702 }); 12703 }, 12704 12705 _createRange: function() { 12706 var options = this.options, 12707 classes = ""; 12708 12709 if ( options.range ) { 12710 if ( options.range === true ) { 12711 if ( !options.values ) { 12712 options.values = [ this._valueMin(), this._valueMin() ]; 12713 } else if ( options.values.length && options.values.length !== 2 ) { 12714 options.values = [ options.values[0], options.values[0] ]; 12715 } else if ( $.isArray( options.values ) ) { 12716 options.values = options.values.slice(0); 12717 } 12718 } 12719 12720 if ( !this.range || !this.range.length ) { 12721 this.range = $( "<div></div>" ) 12722 .appendTo( this.element ); 12723 12724 classes = "ui-slider-range" + 12725 // note: this isn't the most fittingly semantic framework class for this element, 12726 // but worked best visually with a variety of themes 12727 " ui-widget-header ui-corner-all"; 12728 } else { 12729 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" ) 12730 // Handle range switching from true to min/max 12731 .css({ 12732 "left": "", 12733 "bottom": "" 12734 }); 12735 } 12736 12737 this.range.addClass( classes + 12738 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) ); 12739 } else { 12740 if ( this.range ) { 12741 this.range.remove(); 12742 } 12743 this.range = null; 12744 } 12745 }, 12746 12747 _setupEvents: function() { 12748 this._off( this.handles ); 12749 this._on( this.handles, this._handleEvents ); 12750 this._hoverable( this.handles ); 12751 this._focusable( this.handles ); 12752 }, 12753 12754 _destroy: function() { 12755 this.handles.remove(); 12756 if ( this.range ) { 12757 this.range.remove(); 12758 } 12759 12760 this.element 12761 .removeClass( "ui-slider" + 12762 " ui-slider-horizontal" + 12763 " ui-slider-vertical" + 12764 " ui-widget" + 12765 " ui-widget-content" + 12766 " ui-corner-all" ); 12767 12768 this._mouseDestroy(); 12769 }, 12770 12771 _mouseCapture: function( event ) { 12772 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle, 12773 that = this, 12774 o = this.options; 12775 12776 if ( o.disabled ) { 12777 return false; 12778 } 12779 12780 this.elementSize = { 12781 width: this.element.outerWidth(), 12782 height: this.element.outerHeight() 12783 }; 12784 this.elementOffset = this.element.offset(); 12785 12786 position = { x: event.pageX, y: event.pageY }; 12787 normValue = this._normValueFromMouse( position ); 12788 distance = this._valueMax() - this._valueMin() + 1; 12789 this.handles.each(function( i ) { 12790 var thisDistance = Math.abs( normValue - that.values(i) ); 12791 if (( distance > thisDistance ) || 12792 ( distance === thisDistance && 12793 (i === that._lastChangedValue || that.values(i) === o.min ))) { 12794 distance = thisDistance; 12795 closestHandle = $( this ); 12796 index = i; 12797 } 12798 }); 12799 12800 allowed = this._start( event, index ); 12801 if ( allowed === false ) { 12802 return false; 12803 } 12804 this._mouseSliding = true; 12805 12806 this._handleIndex = index; 12807 12808 closestHandle 12809 .addClass( "ui-state-active" ) 12810 .focus(); 12811 12812 offset = closestHandle.offset(); 12813 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" ); 12814 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : { 12815 left: event.pageX - offset.left - ( closestHandle.width() / 2 ), 12816 top: event.pageY - offset.top - 12817 ( closestHandle.height() / 2 ) - 12818 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) - 12819 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) + 12820 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0) 12821 }; 12822 12823 if ( !this.handles.hasClass( "ui-state-hover" ) ) { 12824 this._slide( event, index, normValue ); 12825 } 12826 this._animateOff = true; 12827 return true; 12828 }, 12829 12830 _mouseStart: function() { 12831 return true; 12832 }, 12833 12834 _mouseDrag: function( event ) { 12835 var position = { x: event.pageX, y: event.pageY }, 12836 normValue = this._normValueFromMouse( position ); 12837 12838 this._slide( event, this._handleIndex, normValue ); 12839 12840 return false; 12841 }, 12842 12843 _mouseStop: function( event ) { 12844 this.handles.removeClass( "ui-state-active" ); 12845 this._mouseSliding = false; 12846 12847 this._stop( event, this._handleIndex ); 12848 this._change( event, this._handleIndex ); 12849 12850 this._handleIndex = null; 12851 this._clickOffset = null; 12852 this._animateOff = false; 12853 12854 return false; 12855 }, 12856 12857 _detectOrientation: function() { 12858 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal"; 12859 }, 12860 12861 _normValueFromMouse: function( position ) { 12862 var pixelTotal, 12863 pixelMouse, 12864 percentMouse, 12865 valueTotal, 12866 valueMouse; 12867 12868 if ( this.orientation === "horizontal" ) { 12869 pixelTotal = this.elementSize.width; 12870 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 ); 12871 } else { 12872 pixelTotal = this.elementSize.height; 12873 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 ); 12874 } 12875 12876 percentMouse = ( pixelMouse / pixelTotal ); 12877 if ( percentMouse > 1 ) { 12878 percentMouse = 1; 12879 } 12880 if ( percentMouse < 0 ) { 12881 percentMouse = 0; 12882 } 12883 if ( this.orientation === "vertical" ) { 12884 percentMouse = 1 - percentMouse; 12885 } 12886 12887 valueTotal = this._valueMax() - this._valueMin(); 12888 valueMouse = this._valueMin() + percentMouse * valueTotal; 12889 12890 return this._trimAlignValue( valueMouse ); 12891 }, 12892 12893 _start: function( event, index ) { 12894 var uiHash = { 12895 handle: this.handles[ index ], 12896 value: this.value() 12897 }; 12898 if ( this.options.values && this.options.values.length ) { 12899 uiHash.value = this.values( index ); 12900 uiHash.values = this.values(); 12901 } 12902 return this._trigger( "start", event, uiHash ); 12903 }, 12904 12905 _slide: function( event, index, newVal ) { 12906 var otherVal, 12907 newValues, 12908 allowed; 12909 12910 if ( this.options.values && this.options.values.length ) { 12911 otherVal = this.values( index ? 0 : 1 ); 12912 12913 if ( ( this.options.values.length === 2 && this.options.range === true ) && 12914 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) ) 12915 ) { 12916 newVal = otherVal; 12917 } 12918 12919 if ( newVal !== this.values( index ) ) { 12920 newValues = this.values(); 12921 newValues[ index ] = newVal; 12922 // A slide can be canceled by returning false from the slide callback 12923 allowed = this._trigger( "slide", event, { 12924 handle: this.handles[ index ], 12925 value: newVal, 12926 values: newValues 12927 } ); 12928 otherVal = this.values( index ? 0 : 1 ); 12929 if ( allowed !== false ) { 12930 this.values( index, newVal ); 12931 } 12932 } 12933 } else { 12934 if ( newVal !== this.value() ) { 12935 // A slide can be canceled by returning false from the slide callback 12936 allowed = this._trigger( "slide", event, { 12937 handle: this.handles[ index ], 12938 value: newVal 12939 } ); 12940 if ( allowed !== false ) { 12941 this.value( newVal ); 12942 } 12943 } 12944 } 12945 }, 12946 12947 _stop: function( event, index ) { 12948 var uiHash = { 12949 handle: this.handles[ index ], 12950 value: this.value() 12951 }; 12952 if ( this.options.values && this.options.values.length ) { 12953 uiHash.value = this.values( index ); 12954 uiHash.values = this.values(); 12955 } 12956 12957 this._trigger( "stop", event, uiHash ); 12958 }, 12959 12960 _change: function( event, index ) { 12961 if ( !this._keySliding && !this._mouseSliding ) { 12962 var uiHash = { 12963 handle: this.handles[ index ], 12964 value: this.value() 12965 }; 12966 if ( this.options.values && this.options.values.length ) { 12967 uiHash.value = this.values( index ); 12968 uiHash.values = this.values(); 12969 } 12970 12971 //store the last changed value index for reference when handles overlap 12972 this._lastChangedValue = index; 12973 12974 this._trigger( "change", event, uiHash ); 12975 } 12976 }, 12977 12978 value: function( newValue ) { 12979 if ( arguments.length ) { 12980 this.options.value = this._trimAlignValue( newValue ); 12981 this._refreshValue(); 12982 this._change( null, 0 ); 12983 return; 12984 } 12985 12986 return this._value(); 12987 }, 12988 12989 values: function( index, newValue ) { 12990 var vals, 12991 newValues, 12992 i; 12993 12994 if ( arguments.length > 1 ) { 12995 this.options.values[ index ] = this._trimAlignValue( newValue ); 12996 this._refreshValue(); 12997 this._change( null, index ); 12998 return; 12999 } 13000 13001 if ( arguments.length ) { 13002 if ( $.isArray( arguments[ 0 ] ) ) { 13003 vals = this.options.values; 13004 newValues = arguments[ 0 ]; 13005 for ( i = 0; i < vals.length; i += 1 ) { 13006 vals[ i ] = this._trimAlignValue( newValues[ i ] ); 13007 this._change( null, i ); 13008 } 13009 this._refreshValue(); 13010 } else { 13011 if ( this.options.values && this.options.values.length ) { 13012 return this._values( index ); 13013 } else { 13014 return this.value(); 13015 } 13016 } 13017 } else { 13018 return this._values(); 13019 } 13020 }, 13021 13022 _setOption: function( key, value ) { 13023 var i, 13024 valsLength = 0; 13025 13026 if ( key === "range" && this.options.range === true ) { 13027 if ( value === "min" ) { 13028 this.options.value = this._values( 0 ); 13029 this.options.values = null; 13030 } else if ( value === "max" ) { 13031 this.options.value = this._values( this.options.values.length - 1 ); 13032 this.options.values = null; 13033 } 13034 } 13035 13036 if ( $.isArray( this.options.values ) ) { 13037 valsLength = this.options.values.length; 13038 } 13039 13040 if ( key === "disabled" ) { 13041 this.element.toggleClass( "ui-state-disabled", !!value ); 13042 } 13043 13044 this._super( key, value ); 13045 13046 switch ( key ) { 13047 case "orientation": 13048 this._detectOrientation(); 13049 this.element 13050 .removeClass( "ui-slider-horizontal ui-slider-vertical" ) 13051 .addClass( "ui-slider-" + this.orientation ); 13052 this._refreshValue(); 13053 13054 // Reset positioning from previous orientation 13055 this.handles.css( value === "horizontal" ? "bottom" : "left", "" ); 13056 break; 13057 case "value": 13058 this._animateOff = true; 13059 this._refreshValue(); 13060 this._change( null, 0 ); 13061 this._animateOff = false; 13062 break; 13063 case "values": 13064 this._animateOff = true; 13065 this._refreshValue(); 13066 for ( i = 0; i < valsLength; i += 1 ) { 13067 this._change( null, i ); 13068 } 13069 this._animateOff = false; 13070 break; 13071 case "min": 13072 case "max": 13073 this._animateOff = true; 13074 this._refreshValue(); 13075 this._animateOff = false; 13076 break; 13077 case "range": 13078 this._animateOff = true; 13079 this._refresh(); 13080 this._animateOff = false; 13081 break; 13082 } 13083 }, 13084 13085 //internal value getter 13086 // _value() returns value trimmed by min and max, aligned by step 13087 _value: function() { 13088 var val = this.options.value; 13089 val = this._trimAlignValue( val ); 13090 13091 return val; 13092 }, 13093 13094 //internal values getter 13095 // _values() returns array of values trimmed by min and max, aligned by step 13096 // _values( index ) returns single value trimmed by min and max, aligned by step 13097 _values: function( index ) { 13098 var val, 13099 vals, 13100 i; 13101 13102 if ( arguments.length ) { 13103 val = this.options.values[ index ]; 13104 val = this._trimAlignValue( val ); 13105 13106 return val; 13107 } else if ( this.options.values && this.options.values.length ) { 13108 // .slice() creates a copy of the array 13109 // this copy gets trimmed by min and max and then returned 13110 vals = this.options.values.slice(); 13111 for ( i = 0; i < vals.length; i+= 1) { 13112 vals[ i ] = this._trimAlignValue( vals[ i ] ); 13113 } 13114 13115 return vals; 13116 } else { 13117 return []; 13118 } 13119 }, 13120 13121 // returns the step-aligned value that val is closest to, between (inclusive) min and max 13122 _trimAlignValue: function( val ) { 13123 if ( val <= this._valueMin() ) { 13124 return this._valueMin(); 13125 } 13126 if ( val >= this._valueMax() ) { 13127 return this._valueMax(); 13128 } 13129 var step = ( this.options.step > 0 ) ? this.options.step : 1, 13130 valModStep = (val - this._valueMin()) % step, 13131 alignValue = val - valModStep; 13132 13133 if ( Math.abs(valModStep) * 2 >= step ) { 13134 alignValue += ( valModStep > 0 ) ? step : ( -step ); 13135 } 13136 13137 // Since JavaScript has problems with large floats, round 13138 // the final value to 5 digits after the decimal point (see #4124) 13139 return parseFloat( alignValue.toFixed(5) ); 13140 }, 13141 13142 _valueMin: function() { 13143 return this.options.min; 13144 }, 13145 13146 _valueMax: function() { 13147 return this.options.max; 13148 }, 13149 13150 _refreshValue: function() { 13151 var lastValPercent, valPercent, value, valueMin, valueMax, 13152 oRange = this.options.range, 13153 o = this.options, 13154 that = this, 13155 animate = ( !this._animateOff ) ? o.animate : false, 13156 _set = {}; 13157 13158 if ( this.options.values && this.options.values.length ) { 13159 this.handles.each(function( i ) { 13160 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100; 13161 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 13162 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 13163 if ( that.options.range === true ) { 13164 if ( that.orientation === "horizontal" ) { 13165 if ( i === 0 ) { 13166 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate ); 13167 } 13168 if ( i === 1 ) { 13169 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 13170 } 13171 } else { 13172 if ( i === 0 ) { 13173 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate ); 13174 } 13175 if ( i === 1 ) { 13176 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } ); 13177 } 13178 } 13179 } 13180 lastValPercent = valPercent; 13181 }); 13182 } else { 13183 value = this.value(); 13184 valueMin = this._valueMin(); 13185 valueMax = this._valueMax(); 13186 valPercent = ( valueMax !== valueMin ) ? 13187 ( value - valueMin ) / ( valueMax - valueMin ) * 100 : 13188 0; 13189 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%"; 13190 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate ); 13191 13192 if ( oRange === "min" && this.orientation === "horizontal" ) { 13193 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate ); 13194 } 13195 if ( oRange === "max" && this.orientation === "horizontal" ) { 13196 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 13197 } 13198 if ( oRange === "min" && this.orientation === "vertical" ) { 13199 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate ); 13200 } 13201 if ( oRange === "max" && this.orientation === "vertical" ) { 13202 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } ); 13203 } 13204 } 13205 }, 13206 13207 _handleEvents: { 13208 keydown: function( event ) { 13209 var allowed, curVal, newVal, step, 13210 index = $( event.target ).data( "ui-slider-handle-index" ); 13211 13212 switch ( event.keyCode ) { 13213 case $.ui.keyCode.HOME: 13214 case $.ui.keyCode.END: 13215 case $.ui.keyCode.PAGE_UP: 13216 case $.ui.keyCode.PAGE_DOWN: 13217 case $.ui.keyCode.UP: 13218 case $.ui.keyCode.RIGHT: 13219 case $.ui.keyCode.DOWN: 13220 case $.ui.keyCode.LEFT: 13221 event.preventDefault(); 13222 if ( !this._keySliding ) { 13223 this._keySliding = true; 13224 $( event.target ).addClass( "ui-state-active" ); 13225 allowed = this._start( event, index ); 13226 if ( allowed === false ) { 13227 return; 13228 } 13229 } 13230 break; 13231 } 13232 13233 step = this.options.step; 13234 if ( this.options.values && this.options.values.length ) { 13235 curVal = newVal = this.values( index ); 13236 } else { 13237 curVal = newVal = this.value(); 13238 } 13239 13240 switch ( event.keyCode ) { 13241 case $.ui.keyCode.HOME: 13242 newVal = this._valueMin(); 13243 break; 13244 case $.ui.keyCode.END: 13245 newVal = this._valueMax(); 13246 break; 13247 case $.ui.keyCode.PAGE_UP: 13248 newVal = this._trimAlignValue( 13249 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages ) 13250 ); 13251 break; 13252 case $.ui.keyCode.PAGE_DOWN: 13253 newVal = this._trimAlignValue( 13254 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) ); 13255 break; 13256 case $.ui.keyCode.UP: 13257 case $.ui.keyCode.RIGHT: 13258 if ( curVal === this._valueMax() ) { 13259 return; 13260 } 13261 newVal = this._trimAlignValue( curVal + step ); 13262 break; 13263 case $.ui.keyCode.DOWN: 13264 case $.ui.keyCode.LEFT: 13265 if ( curVal === this._valueMin() ) { 13266 return; 13267 } 13268 newVal = this._trimAlignValue( curVal - step ); 13269 break; 13270 } 13271 13272 this._slide( event, index, newVal ); 13273 }, 13274 keyup: function( event ) { 13275 var index = $( event.target ).data( "ui-slider-handle-index" ); 13276 13277 if ( this._keySliding ) { 13278 this._keySliding = false; 13279 this._stop( event, index ); 13280 this._change( event, index ); 13281 $( event.target ).removeClass( "ui-state-active" ); 13282 } 13283 } 13284 } 13285 }); 13286 13287 13288 /*! 13289 * jQuery UI Sortable 1.11.1 13290 * http://jqueryui.com 13291 * 13292 * Copyright 2014 jQuery Foundation and other contributors 13293 * Released under the MIT license. 13294 * http://jquery.org/license 13295 * 13296 * http://api.jqueryui.com/sortable/ 13297 */ 13298 13299 13300 var sortable = $.widget("ui.sortable", $.ui.mouse, { 13301 version: "1.11.1", 13302 widgetEventPrefix: "sort", 13303 ready: false, 13304 options: { 13305 appendTo: "parent", 13306 axis: false, 13307 connectWith: false, 13308 containment: false, 13309 cursor: "auto", 13310 cursorAt: false, 13311 dropOnEmpty: true, 13312 forcePlaceholderSize: false, 13313 forceHelperSize: false, 13314 grid: false, 13315 handle: false, 13316 helper: "original", 13317 items: "> *", 13318 opacity: false, 13319 placeholder: false, 13320 revert: false, 13321 scroll: true, 13322 scrollSensitivity: 20, 13323 scrollSpeed: 20, 13324 scope: "default", 13325 tolerance: "intersect", 13326 zIndex: 1000, 13327 13328 // callbacks 13329 activate: null, 13330 beforeStop: null, 13331 change: null, 13332 deactivate: null, 13333 out: null, 13334 over: null, 13335 receive: null, 13336 remove: null, 13337 sort: null, 13338 start: null, 13339 stop: null, 13340 update: null 13341 }, 13342 13343 _isOverAxis: function( x, reference, size ) { 13344 return ( x >= reference ) && ( x < ( reference + size ) ); 13345 }, 13346 13347 _isFloating: function( item ) { 13348 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); 13349 }, 13350 13351 _create: function() { 13352 13353 var o = this.options; 13354 this.containerCache = {}; 13355 this.element.addClass("ui-sortable"); 13356 13357 //Get the items 13358 this.refresh(); 13359 13360 //Let's determine if the items are being displayed horizontally 13361 this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false; 13362 13363 //Let's determine the parent's offset 13364 this.offset = this.element.offset(); 13365 13366 //Initialize mouse events for interaction 13367 this._mouseInit(); 13368 13369 this._setHandleClassName(); 13370 13371 //We're ready to go 13372 this.ready = true; 13373 13374 }, 13375 13376 _setOption: function( key, value ) { 13377 this._super( key, value ); 13378 13379 if ( key === "handle" ) { 13380 this._setHandleClassName(); 13381 } 13382 }, 13383 13384 _setHandleClassName: function() { 13385 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" ); 13386 $.each( this.items, function() { 13387 ( this.instance.options.handle ? 13388 this.item.find( this.instance.options.handle ) : this.item ) 13389 .addClass( "ui-sortable-handle" ); 13390 }); 13391 }, 13392 13393 _destroy: function() { 13394 this.element 13395 .removeClass( "ui-sortable ui-sortable-disabled" ) 13396 .find( ".ui-sortable-handle" ) 13397 .removeClass( "ui-sortable-handle" ); 13398 this._mouseDestroy(); 13399 13400 for ( var i = this.items.length - 1; i >= 0; i-- ) { 13401 this.items[i].item.removeData(this.widgetName + "-item"); 13402 } 13403 13404 return this; 13405 }, 13406 13407 _mouseCapture: function(event, overrideHandle) { 13408 var currentItem = null, 13409 validHandle = false, 13410 that = this; 13411 13412 if (this.reverting) { 13413 return false; 13414 } 13415 13416 if(this.options.disabled || this.options.type === "static") { 13417 return false; 13418 } 13419 13420 //We have to refresh the items data once first 13421 this._refreshItems(event); 13422 13423 //Find out if the clicked node (or one of its parents) is a actual item in this.items 13424 $(event.target).parents().each(function() { 13425 if($.data(this, that.widgetName + "-item") === that) { 13426 currentItem = $(this); 13427 return false; 13428 } 13429 }); 13430 if($.data(event.target, that.widgetName + "-item") === that) { 13431 currentItem = $(event.target); 13432 } 13433 13434 if(!currentItem) { 13435 return false; 13436 } 13437 if(this.options.handle && !overrideHandle) { 13438 $(this.options.handle, currentItem).find("*").addBack().each(function() { 13439 if(this === event.target) { 13440 validHandle = true; 13441 } 13442 }); 13443 if(!validHandle) { 13444 return false; 13445 } 13446 } 13447 13448 this.currentItem = currentItem; 13449 this._removeCurrentsFromItems(); 13450 return true; 13451 13452 }, 13453 13454 _mouseStart: function(event, overrideHandle, noActivation) { 13455 13456 var i, body, 13457 o = this.options; 13458 13459 this.currentContainer = this; 13460 13461 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture 13462 this.refreshPositions(); 13463 13464 //Create and append the visible helper 13465 this.helper = this._createHelper(event); 13466 13467 //Cache the helper size 13468 this._cacheHelperProportions(); 13469 13470 /* 13471 * - Position generation - 13472 * This block generates everything position related - it's the core of draggables. 13473 */ 13474 13475 //Cache the margins of the original element 13476 this._cacheMargins(); 13477 13478 //Get the next scrolling parent 13479 this.scrollParent = this.helper.scrollParent(); 13480 13481 //The element's absolute position on the page minus margins 13482 this.offset = this.currentItem.offset(); 13483 this.offset = { 13484 top: this.offset.top - this.margins.top, 13485 left: this.offset.left - this.margins.left 13486 }; 13487 13488 $.extend(this.offset, { 13489 click: { //Where the click happened, relative to the element 13490 left: event.pageX - this.offset.left, 13491 top: event.pageY - this.offset.top 13492 }, 13493 parent: this._getParentOffset(), 13494 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper 13495 }); 13496 13497 // Only after we got the offset, we can change the helper's position to absolute 13498 // TODO: Still need to figure out a way to make relative sorting possible 13499 this.helper.css("position", "absolute"); 13500 this.cssPosition = this.helper.css("position"); 13501 13502 //Generate the original position 13503 this.originalPosition = this._generatePosition(event); 13504 this.originalPageX = event.pageX; 13505 this.originalPageY = event.pageY; 13506 13507 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied 13508 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); 13509 13510 //Cache the former DOM position 13511 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; 13512 13513 //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 13514 if(this.helper[0] !== this.currentItem[0]) { 13515 this.currentItem.hide(); 13516 } 13517 13518 //Create the placeholder 13519 this._createPlaceholder(); 13520 13521 //Set a containment if given in the options 13522 if(o.containment) { 13523 this._setContainment(); 13524 } 13525 13526 if( o.cursor && o.cursor !== "auto" ) { // cursor option 13527 body = this.document.find( "body" ); 13528 13529 // support: IE 13530 this.storedCursor = body.css( "cursor" ); 13531 body.css( "cursor", o.cursor ); 13532 13533 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body ); 13534 } 13535 13536 if(o.opacity) { // opacity option 13537 if (this.helper.css("opacity")) { 13538 this._storedOpacity = this.helper.css("opacity"); 13539 } 13540 this.helper.css("opacity", o.opacity); 13541 } 13542 13543 if(o.zIndex) { // zIndex option 13544 if (this.helper.css("zIndex")) { 13545 this._storedZIndex = this.helper.css("zIndex"); 13546 } 13547 this.helper.css("zIndex", o.zIndex); 13548 } 13549 13550 //Prepare scrolling 13551 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { 13552 this.overflowOffset = this.scrollParent.offset(); 13553 } 13554 13555 //Call callbacks 13556 this._trigger("start", event, this._uiHash()); 13557 13558 //Recache the helper size 13559 if(!this._preserveHelperProportions) { 13560 this._cacheHelperProportions(); 13561 } 13562 13563 13564 //Post "activate" events to possible containers 13565 if( !noActivation ) { 13566 for ( i = this.containers.length - 1; i >= 0; i-- ) { 13567 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); 13568 } 13569 } 13570 13571 //Prepare possible droppables 13572 if($.ui.ddmanager) { 13573 $.ui.ddmanager.current = this; 13574 } 13575 13576 if ($.ui.ddmanager && !o.dropBehaviour) { 13577 $.ui.ddmanager.prepareOffsets(this, event); 13578 } 13579 13580 this.dragging = true; 13581 13582 this.helper.addClass("ui-sortable-helper"); 13583 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position 13584 return true; 13585 13586 }, 13587 13588 _mouseDrag: function(event) { 13589 var i, item, itemElement, intersection, 13590 o = this.options, 13591 scrolled = false; 13592 13593 //Compute the helpers position 13594 this.position = this._generatePosition(event); 13595 this.positionAbs = this._convertPositionTo("absolute"); 13596 13597 if (!this.lastPositionAbs) { 13598 this.lastPositionAbs = this.positionAbs; 13599 } 13600 13601 //Do scrolling 13602 if(this.options.scroll) { 13603 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { 13604 13605 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { 13606 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; 13607 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { 13608 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; 13609 } 13610 13611 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { 13612 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; 13613 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { 13614 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; 13615 } 13616 13617 } else { 13618 13619 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { 13620 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); 13621 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { 13622 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); 13623 } 13624 13625 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { 13626 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); 13627 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { 13628 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); 13629 } 13630 13631 } 13632 13633 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { 13634 $.ui.ddmanager.prepareOffsets(this, event); 13635 } 13636 } 13637 13638 //Regenerate the absolute position used for position checks 13639 this.positionAbs = this._convertPositionTo("absolute"); 13640 13641 //Set the helper position 13642 if(!this.options.axis || this.options.axis !== "y") { 13643 this.helper[0].style.left = this.position.left+"px"; 13644 } 13645 if(!this.options.axis || this.options.axis !== "x") { 13646 this.helper[0].style.top = this.position.top+"px"; 13647 } 13648 13649 //Rearrange 13650 for (i = this.items.length - 1; i >= 0; i--) { 13651 13652 //Cache variables and intersection, continue if no intersection 13653 item = this.items[i]; 13654 itemElement = item.item[0]; 13655 intersection = this._intersectsWithPointer(item); 13656 if (!intersection) { 13657 continue; 13658 } 13659 13660 // Only put the placeholder inside the current Container, skip all 13661 // items from other containers. This works because when moving 13662 // an item from one container to another the 13663 // currentContainer is switched before the placeholder is moved. 13664 // 13665 // Without this, moving items in "sub-sortables" can cause 13666 // the placeholder to jitter between the outer and inner container. 13667 if (item.instance !== this.currentContainer) { 13668 continue; 13669 } 13670 13671 // cannot intersect with itself 13672 // no useless actions that have been done before 13673 // no action if the item moved is the parent of the item checked 13674 if (itemElement !== this.currentItem[0] && 13675 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && 13676 !$.contains(this.placeholder[0], itemElement) && 13677 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) 13678 ) { 13679 13680 this.direction = intersection === 1 ? "down" : "up"; 13681 13682 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { 13683 this._rearrange(event, item); 13684 } else { 13685 break; 13686 } 13687 13688 this._trigger("change", event, this._uiHash()); 13689 break; 13690 } 13691 } 13692 13693 //Post events to containers 13694 this._contactContainers(event); 13695 13696 //Interconnect with droppables 13697 if($.ui.ddmanager) { 13698 $.ui.ddmanager.drag(this, event); 13699 } 13700 13701 //Call callbacks 13702 this._trigger("sort", event, this._uiHash()); 13703 13704 this.lastPositionAbs = this.positionAbs; 13705 return false; 13706 13707 }, 13708 13709 _mouseStop: function(event, noPropagation) { 13710 13711 if(!event) { 13712 return; 13713 } 13714 13715 //If we are using droppables, inform the manager about the drop 13716 if ($.ui.ddmanager && !this.options.dropBehaviour) { 13717 $.ui.ddmanager.drop(this, event); 13718 } 13719 13720 if(this.options.revert) { 13721 var that = this, 13722 cur = this.placeholder.offset(), 13723 axis = this.options.axis, 13724 animation = {}; 13725 13726 if ( !axis || axis === "x" ) { 13727 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); 13728 } 13729 if ( !axis || axis === "y" ) { 13730 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); 13731 } 13732 this.reverting = true; 13733 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { 13734 that._clear(event); 13735 }); 13736 } else { 13737 this._clear(event, noPropagation); 13738 } 13739 13740 return false; 13741 13742 }, 13743 13744 cancel: function() { 13745 13746 if(this.dragging) { 13747 13748 this._mouseUp({ target: null }); 13749 13750 if(this.options.helper === "original") { 13751 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); 13752 } else { 13753 this.currentItem.show(); 13754 } 13755 13756 //Post deactivating events to containers 13757 for (var i = this.containers.length - 1; i >= 0; i--){ 13758 this.containers[i]._trigger("deactivate", null, this._uiHash(this)); 13759 if(this.containers[i].containerCache.over) { 13760 this.containers[i]._trigger("out", null, this._uiHash(this)); 13761 this.containers[i].containerCache.over = 0; 13762 } 13763 } 13764 13765 } 13766 13767 if (this.placeholder) { 13768 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! 13769 if(this.placeholder[0].parentNode) { 13770 this.placeholder[0].parentNode.removeChild(this.placeholder[0]); 13771 } 13772 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { 13773 this.helper.remove(); 13774 } 13775 13776 $.extend(this, { 13777 helper: null, 13778 dragging: false, 13779 reverting: false, 13780 _noFinalSort: null 13781 }); 13782 13783 if(this.domPosition.prev) { 13784 $(this.domPosition.prev).after(this.currentItem); 13785 } else { 13786 $(this.domPosition.parent).prepend(this.currentItem); 13787 } 13788 } 13789 13790 return this; 13791 13792 }, 13793 13794 serialize: function(o) { 13795 13796 var items = this._getItemsAsjQuery(o && o.connected), 13797 str = []; 13798 o = o || {}; 13799 13800 $(items).each(function() { 13801 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); 13802 if (res) { 13803 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); 13804 } 13805 }); 13806 13807 if(!str.length && o.key) { 13808 str.push(o.key + "="); 13809 } 13810 13811 return str.join("&"); 13812 13813 }, 13814 13815 toArray: function(o) { 13816 13817 var items = this._getItemsAsjQuery(o && o.connected), 13818 ret = []; 13819 13820 o = o || {}; 13821 13822 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); 13823 return ret; 13824 13825 }, 13826 13827 /* Be careful with the following core functions */ 13828 _intersectsWith: function(item) { 13829 13830 var x1 = this.positionAbs.left, 13831 x2 = x1 + this.helperProportions.width, 13832 y1 = this.positionAbs.top, 13833 y2 = y1 + this.helperProportions.height, 13834 l = item.left, 13835 r = l + item.width, 13836 t = item.top, 13837 b = t + item.height, 13838 dyClick = this.offset.click.top, 13839 dxClick = this.offset.click.left, 13840 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), 13841 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), 13842 isOverElement = isOverElementHeight && isOverElementWidth; 13843 13844 if ( this.options.tolerance === "pointer" || 13845 this.options.forcePointerForContainers || 13846 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) 13847 ) { 13848 return isOverElement; 13849 } else { 13850 13851 return (l < x1 + (this.helperProportions.width / 2) && // Right Half 13852 x2 - (this.helperProportions.width / 2) < r && // Left Half 13853 t < y1 + (this.helperProportions.height / 2) && // Bottom Half 13854 y2 - (this.helperProportions.height / 2) < b ); // Top Half 13855 13856 } 13857 }, 13858 13859 _intersectsWithPointer: function(item) { 13860 13861 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), 13862 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), 13863 isOverElement = isOverElementHeight && isOverElementWidth, 13864 verticalDirection = this._getDragVerticalDirection(), 13865 horizontalDirection = this._getDragHorizontalDirection(); 13866 13867 if (!isOverElement) { 13868 return false; 13869 } 13870 13871 return this.floating ? 13872 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) 13873 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); 13874 13875 }, 13876 13877 _intersectsWithSides: function(item) { 13878 13879 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), 13880 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), 13881 verticalDirection = this._getDragVerticalDirection(), 13882 horizontalDirection = this._getDragHorizontalDirection(); 13883 13884 if (this.floating && horizontalDirection) { 13885 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); 13886 } else { 13887 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); 13888 } 13889 13890 }, 13891 13892 _getDragVerticalDirection: function() { 13893 var delta = this.positionAbs.top - this.lastPositionAbs.top; 13894 return delta !== 0 && (delta > 0 ? "down" : "up"); 13895 }, 13896 13897 _getDragHorizontalDirection: function() { 13898 var delta = this.positionAbs.left - this.lastPositionAbs.left; 13899 return delta !== 0 && (delta > 0 ? "right" : "left"); 13900 }, 13901 13902 refresh: function(event) { 13903 this._refreshItems(event); 13904 this._setHandleClassName(); 13905 this.refreshPositions(); 13906 return this; 13907 }, 13908 13909 _connectWith: function() { 13910 var options = this.options; 13911 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; 13912 }, 13913 13914 _getItemsAsjQuery: function(connected) { 13915 13916 var i, j, cur, inst, 13917 items = [], 13918 queries = [], 13919 connectWith = this._connectWith(); 13920 13921 if(connectWith && connected) { 13922 for (i = connectWith.length - 1; i >= 0; i--){ 13923 cur = $(connectWith[i]); 13924 for ( j = cur.length - 1; j >= 0; j--){ 13925 inst = $.data(cur[j], this.widgetFullName); 13926 if(inst && inst !== this && !inst.options.disabled) { 13927 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]); 13928 } 13929 } 13930 } 13931 } 13932 13933 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]); 13934 13935 function addItems() { 13936 items.push( this ); 13937 } 13938 for (i = queries.length - 1; i >= 0; i--){ 13939 queries[i][0].each( addItems ); 13940 } 13941 13942 return $(items); 13943 13944 }, 13945 13946 _removeCurrentsFromItems: function() { 13947 13948 var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); 13949 13950 this.items = $.grep(this.items, function (item) { 13951 for (var j=0; j < list.length; j++) { 13952 if(list[j] === item.item[0]) { 13953 return false; 13954 } 13955 } 13956 return true; 13957 }); 13958 13959 }, 13960 13961 _refreshItems: function(event) { 13962 13963 this.items = []; 13964 this.containers = [this]; 13965 13966 var i, j, cur, inst, targetData, _queries, item, queriesLength, 13967 items = this.items, 13968 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], 13969 connectWith = this._connectWith(); 13970 13971 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down 13972 for (i = connectWith.length - 1; i >= 0; i--){ 13973 cur = $(connectWith[i]); 13974 for (j = cur.length - 1; j >= 0; j--){ 13975 inst = $.data(cur[j], this.widgetFullName); 13976 if(inst && inst !== this && !inst.options.disabled) { 13977 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); 13978 this.containers.push(inst); 13979 } 13980 } 13981 } 13982 } 13983 13984 for (i = queries.length - 1; i >= 0; i--) { 13985 targetData = queries[i][1]; 13986 _queries = queries[i][0]; 13987 13988 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { 13989 item = $(_queries[j]); 13990 13991 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) 13992 13993 items.push({ 13994 item: item, 13995 instance: targetData, 13996 width: 0, height: 0, 13997 left: 0, top: 0 13998 }); 13999 } 14000 } 14001 14002 }, 14003 14004 refreshPositions: function(fast) { 14005 14006 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change 14007 if(this.offsetParent && this.helper) { 14008 this.offset.parent = this._getParentOffset(); 14009 } 14010 14011 var i, item, t, p; 14012 14013 for (i = this.items.length - 1; i >= 0; i--){ 14014 item = this.items[i]; 14015 14016 //We ignore calculating positions of all connected containers when we're not over them 14017 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { 14018 continue; 14019 } 14020 14021 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; 14022 14023 if (!fast) { 14024 item.width = t.outerWidth(); 14025 item.height = t.outerHeight(); 14026 } 14027 14028 p = t.offset(); 14029 item.left = p.left; 14030 item.top = p.top; 14031 } 14032 14033 if(this.options.custom && this.options.custom.refreshContainers) { 14034 this.options.custom.refreshContainers.call(this); 14035 } else { 14036 for (i = this.containers.length - 1; i >= 0; i--){ 14037 p = this.containers[i].element.offset(); 14038 this.containers[i].containerCache.left = p.left; 14039 this.containers[i].containerCache.top = p.top; 14040 this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); 14041 this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); 14042 } 14043 } 14044 14045 return this; 14046 }, 14047 14048 _createPlaceholder: function(that) { 14049 that = that || this; 14050 var className, 14051 o = that.options; 14052 14053 if(!o.placeholder || o.placeholder.constructor === String) { 14054 className = o.placeholder; 14055 o.placeholder = { 14056 element: function() { 14057 14058 var nodeName = that.currentItem[0].nodeName.toLowerCase(), 14059 element = $( "<" + nodeName + ">", that.document[0] ) 14060 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") 14061 .removeClass("ui-sortable-helper"); 14062 14063 if ( nodeName === "tr" ) { 14064 that.currentItem.children().each(function() { 14065 $( "<td> </td>", that.document[0] ) 14066 .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) 14067 .appendTo( element ); 14068 }); 14069 } else if ( nodeName === "img" ) { 14070 element.attr( "src", that.currentItem.attr( "src" ) ); 14071 } 14072 14073 if ( !className ) { 14074 element.css( "visibility", "hidden" ); 14075 } 14076 14077 return element; 14078 }, 14079 update: function(container, p) { 14080 14081 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that 14082 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified 14083 if(className && !o.forcePlaceholderSize) { 14084 return; 14085 } 14086 14087 //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 14088 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } 14089 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } 14090 } 14091 }; 14092 } 14093 14094 //Create the placeholder 14095 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); 14096 14097 //Append it after the actual current item 14098 that.currentItem.after(that.placeholder); 14099 14100 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) 14101 o.placeholder.update(that, that.placeholder); 14102 14103 }, 14104 14105 _contactContainers: function(event) { 14106 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis, 14107 innermostContainer = null, 14108 innermostIndex = null; 14109 14110 // get innermost container that intersects with item 14111 for (i = this.containers.length - 1; i >= 0; i--) { 14112 14113 // never consider a container that's located within the item itself 14114 if($.contains(this.currentItem[0], this.containers[i].element[0])) { 14115 continue; 14116 } 14117 14118 if(this._intersectsWith(this.containers[i].containerCache)) { 14119 14120 // if we've already found a container and it's more "inner" than this, then continue 14121 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { 14122 continue; 14123 } 14124 14125 innermostContainer = this.containers[i]; 14126 innermostIndex = i; 14127 14128 } else { 14129 // container doesn't intersect. trigger "out" event if necessary 14130 if(this.containers[i].containerCache.over) { 14131 this.containers[i]._trigger("out", event, this._uiHash(this)); 14132 this.containers[i].containerCache.over = 0; 14133 } 14134 } 14135 14136 } 14137 14138 // if no intersecting containers found, return 14139 if(!innermostContainer) { 14140 return; 14141 } 14142 14143 // move the item into the container if it's not there already 14144 if(this.containers.length === 1) { 14145 if (!this.containers[innermostIndex].containerCache.over) { 14146 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 14147 this.containers[innermostIndex].containerCache.over = 1; 14148 } 14149 } else { 14150 14151 //When entering a new container, we will find the item with the least distance and append our item near it 14152 dist = 10000; 14153 itemWithLeastDistance = null; 14154 floating = innermostContainer.floating || this._isFloating(this.currentItem); 14155 posProperty = floating ? "left" : "top"; 14156 sizeProperty = floating ? "width" : "height"; 14157 axis = floating ? "clientX" : "clientY"; 14158 14159 for (j = this.items.length - 1; j >= 0; j--) { 14160 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { 14161 continue; 14162 } 14163 if(this.items[j].item[0] === this.currentItem[0]) { 14164 continue; 14165 } 14166 14167 cur = this.items[j].item.offset()[posProperty]; 14168 nearBottom = false; 14169 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) { 14170 nearBottom = true; 14171 } 14172 14173 if ( Math.abs( event[ axis ] - cur ) < dist ) { 14174 dist = Math.abs( event[ axis ] - cur ); 14175 itemWithLeastDistance = this.items[ j ]; 14176 this.direction = nearBottom ? "up": "down"; 14177 } 14178 } 14179 14180 //Check if dropOnEmpty is enabled 14181 if(!itemWithLeastDistance && !this.options.dropOnEmpty) { 14182 return; 14183 } 14184 14185 if(this.currentContainer === this.containers[innermostIndex]) { 14186 return; 14187 } 14188 14189 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); 14190 this._trigger("change", event, this._uiHash()); 14191 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); 14192 this.currentContainer = this.containers[innermostIndex]; 14193 14194 //Update the placeholder 14195 this.options.placeholder.update(this.currentContainer, this.placeholder); 14196 14197 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); 14198 this.containers[innermostIndex].containerCache.over = 1; 14199 } 14200 14201 14202 }, 14203 14204 _createHelper: function(event) { 14205 14206 var o = this.options, 14207 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); 14208 14209 //Add the helper to the DOM if that didn't happen already 14210 if(!helper.parents("body").length) { 14211 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); 14212 } 14213 14214 if(helper[0] === this.currentItem[0]) { 14215 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") }; 14216 } 14217 14218 if(!helper[0].style.width || o.forceHelperSize) { 14219 helper.width(this.currentItem.width()); 14220 } 14221 if(!helper[0].style.height || o.forceHelperSize) { 14222 helper.height(this.currentItem.height()); 14223 } 14224 14225 return helper; 14226 14227 }, 14228 14229 _adjustOffsetFromHelper: function(obj) { 14230 if (typeof obj === "string") { 14231 obj = obj.split(" "); 14232 } 14233 if ($.isArray(obj)) { 14234 obj = {left: +obj[0], top: +obj[1] || 0}; 14235 } 14236 if ("left" in obj) { 14237 this.offset.click.left = obj.left + this.margins.left; 14238 } 14239 if ("right" in obj) { 14240 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; 14241 } 14242 if ("top" in obj) { 14243 this.offset.click.top = obj.top + this.margins.top; 14244 } 14245 if ("bottom" in obj) { 14246 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; 14247 } 14248 }, 14249 14250 _getParentOffset: function() { 14251 14252 14253 //Get the offsetParent and cache its position 14254 this.offsetParent = this.helper.offsetParent(); 14255 var po = this.offsetParent.offset(); 14256 14257 // This is a special case where we need to modify a offset calculated on start, since the following happened: 14258 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent 14259 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that 14260 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag 14261 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { 14262 po.left += this.scrollParent.scrollLeft(); 14263 po.top += this.scrollParent.scrollTop(); 14264 } 14265 14266 // This needs to be actually done for all browsers, since pageX/pageY includes this information 14267 // with an ugly IE fix 14268 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { 14269 po = { top: 0, left: 0 }; 14270 } 14271 14272 return { 14273 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), 14274 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) 14275 }; 14276 14277 }, 14278 14279 _getRelativeOffset: function() { 14280 14281 if(this.cssPosition === "relative") { 14282 var p = this.currentItem.position(); 14283 return { 14284 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), 14285 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() 14286 }; 14287 } else { 14288 return { top: 0, left: 0 }; 14289 } 14290 14291 }, 14292 14293 _cacheMargins: function() { 14294 this.margins = { 14295 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), 14296 top: (parseInt(this.currentItem.css("marginTop"),10) || 0) 14297 }; 14298 }, 14299 14300 _cacheHelperProportions: function() { 14301 this.helperProportions = { 14302 width: this.helper.outerWidth(), 14303 height: this.helper.outerHeight() 14304 }; 14305 }, 14306 14307 _setContainment: function() { 14308 14309 var ce, co, over, 14310 o = this.options; 14311 if(o.containment === "parent") { 14312 o.containment = this.helper[0].parentNode; 14313 } 14314 if(o.containment === "document" || o.containment === "window") { 14315 this.containment = [ 14316 0 - this.offset.relative.left - this.offset.parent.left, 14317 0 - this.offset.relative.top - this.offset.parent.top, 14318 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, 14319 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top 14320 ]; 14321 } 14322 14323 if(!(/^(document|window|parent)$/).test(o.containment)) { 14324 ce = $(o.containment)[0]; 14325 co = $(o.containment).offset(); 14326 over = ($(ce).css("overflow") !== "hidden"); 14327 14328 this.containment = [ 14329 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, 14330 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, 14331 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, 14332 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 14333 ]; 14334 } 14335 14336 }, 14337 14338 _convertPositionTo: function(d, pos) { 14339 14340 if(!pos) { 14341 pos = this.position; 14342 } 14343 var mod = d === "absolute" ? 1 : -1, 14344 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, 14345 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 14346 14347 return { 14348 top: ( 14349 pos.top + // The absolute mouse position 14350 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 14351 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) 14352 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) 14353 ), 14354 left: ( 14355 pos.left + // The absolute mouse position 14356 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent 14357 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) 14358 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) 14359 ) 14360 }; 14361 14362 }, 14363 14364 _generatePosition: function(event) { 14365 14366 var top, left, 14367 o = this.options, 14368 pageX = event.pageX, 14369 pageY = event.pageY, 14370 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); 14371 14372 // This is another very weird special case that only happens for relative elements: 14373 // 1. If the css position is relative 14374 // 2. and the scroll parent is the document or similar to the offset parent 14375 // we have to refresh the relative offset during the scroll so there are no jumps 14376 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { 14377 this.offset.relative = this._getRelativeOffset(); 14378 } 14379 14380 /* 14381 * - Position constraining - 14382 * Constrain the position to a mix of grid, containment. 14383 */ 14384 14385 if(this.originalPosition) { //If we are not dragging yet, we won't check for options 14386 14387 if(this.containment) { 14388 if(event.pageX - this.offset.click.left < this.containment[0]) { 14389 pageX = this.containment[0] + this.offset.click.left; 14390 } 14391 if(event.pageY - this.offset.click.top < this.containment[1]) { 14392 pageY = this.containment[1] + this.offset.click.top; 14393 } 14394 if(event.pageX - this.offset.click.left > this.containment[2]) { 14395 pageX = this.containment[2] + this.offset.click.left; 14396 } 14397 if(event.pageY - this.offset.click.top > this.containment[3]) { 14398 pageY = this.containment[3] + this.offset.click.top; 14399 } 14400 } 14401 14402 if(o.grid) { 14403 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; 14404 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; 14405 14406 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; 14407 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; 14408 } 14409 14410 } 14411 14412 return { 14413 top: ( 14414 pageY - // The absolute mouse position 14415 this.offset.click.top - // Click offset (relative to the element) 14416 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent 14417 this.offset.parent.top + // The offsetParent's offset without borders (offset + border) 14418 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) 14419 ), 14420 left: ( 14421 pageX - // The absolute mouse position 14422 this.offset.click.left - // Click offset (relative to the element) 14423 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent 14424 this.offset.parent.left + // The offsetParent's offset without borders (offset + border) 14425 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) 14426 ) 14427 }; 14428 14429 }, 14430 14431 _rearrange: function(event, i, a, hardRefresh) { 14432 14433 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)); 14434 14435 //Various things done here to improve the performance: 14436 // 1. we create a setTimeout, that calls refreshPositions 14437 // 2. on the instance, we have a counter variable, that get's higher after every append 14438 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same 14439 // 4. this lets only the last addition to the timeout stack through 14440 this.counter = this.counter ? ++this.counter : 1; 14441 var counter = this.counter; 14442 14443 this._delay(function() { 14444 if(counter === this.counter) { 14445 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove 14446 } 14447 }); 14448 14449 }, 14450 14451 _clear: function(event, noPropagation) { 14452 14453 this.reverting = false; 14454 // We delay all events that have to be triggered to after the point where the placeholder has been removed and 14455 // everything else normalized again 14456 var i, 14457 delayedTriggers = []; 14458 14459 // We first have to update the dom position of the actual currentItem 14460 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) 14461 if(!this._noFinalSort && this.currentItem.parent().length) { 14462 this.placeholder.before(this.currentItem); 14463 } 14464 this._noFinalSort = null; 14465 14466 if(this.helper[0] === this.currentItem[0]) { 14467 for(i in this._storedCSS) { 14468 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { 14469 this._storedCSS[i] = ""; 14470 } 14471 } 14472 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); 14473 } else { 14474 this.currentItem.show(); 14475 } 14476 14477 if(this.fromOutside && !noPropagation) { 14478 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); 14479 } 14480 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { 14481 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed 14482 } 14483 14484 // Check if the items Container has Changed and trigger appropriate 14485 // events. 14486 if (this !== this.currentContainer) { 14487 if(!noPropagation) { 14488 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); 14489 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); 14490 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); 14491 } 14492 } 14493 14494 14495 //Post events to containers 14496 function delayEvent( type, instance, container ) { 14497 return function( event ) { 14498 container._trigger( type, event, instance._uiHash( instance ) ); 14499 }; 14500 } 14501 for (i = this.containers.length - 1; i >= 0; i--){ 14502 if (!noPropagation) { 14503 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) ); 14504 } 14505 if(this.containers[i].containerCache.over) { 14506 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) ); 14507 this.containers[i].containerCache.over = 0; 14508 } 14509 } 14510 14511 //Do what was originally in plugins 14512 if ( this.storedCursor ) { 14513 this.document.find( "body" ).css( "cursor", this.storedCursor ); 14514 this.storedStylesheet.remove(); 14515 } 14516 if(this._storedOpacity) { 14517 this.helper.css("opacity", this._storedOpacity); 14518 } 14519 if(this._storedZIndex) { 14520 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); 14521 } 14522 14523 this.dragging = false; 14524 if(this.cancelHelperRemoval) { 14525 if(!noPropagation) { 14526 this._trigger("beforeStop", event, this._uiHash()); 14527 for (i=0; i < delayedTriggers.length; i++) { 14528 delayedTriggers[i].call(this, event); 14529 } //Trigger all delayed events 14530 this._trigger("stop", event, this._uiHash()); 14531 } 14532 14533 this.fromOutside = false; 14534 return false; 14535 } 14536 14537 if(!noPropagation) { 14538 this._trigger("beforeStop", event, this._uiHash()); 14539 } 14540 14541 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! 14542 this.placeholder[0].parentNode.removeChild(this.placeholder[0]); 14543 14544 if(this.helper[0] !== this.currentItem[0]) { 14545 this.helper.remove(); 14546 } 14547 this.helper = null; 14548 14549 if(!noPropagation) { 14550 for (i=0; i < delayedTriggers.length; i++) { 14551 delayedTriggers[i].call(this, event); 14552 } //Trigger all delayed events 14553 this._trigger("stop", event, this._uiHash()); 14554 } 14555 14556 this.fromOutside = false; 14557 return true; 14558 14559 }, 14560 14561 _trigger: function() { 14562 if ($.Widget.prototype._trigger.apply(this, arguments) === false) { 14563 this.cancel(); 14564 } 14565 }, 14566 14567 _uiHash: function(_inst) { 14568 var inst = _inst || this; 14569 return { 14570 helper: inst.helper, 14571 placeholder: inst.placeholder || $([]), 14572 position: inst.position, 14573 originalPosition: inst.originalPosition, 14574 offset: inst.positionAbs, 14575 item: inst.currentItem, 14576 sender: _inst ? _inst.element : null 14577 }; 14578 } 14579 14580 }); 14581 14582 14583 /*! 14584 * jQuery UI Spinner 1.11.1 14585 * http://jqueryui.com 14586 * 14587 * Copyright 2014 jQuery Foundation and other contributors 14588 * Released under the MIT license. 14589 * http://jquery.org/license 14590 * 14591 * http://api.jqueryui.com/spinner/ 14592 */ 14593 14594 14595 function spinner_modifier( fn ) { 14596 return function() { 14597 var previous = this.element.val(); 14598 fn.apply( this, arguments ); 14599 this._refresh(); 14600 if ( previous !== this.element.val() ) { 14601 this._trigger( "change" ); 14602 } 14603 }; 14604 } 14605 14606 var spinner = $.widget( "ui.spinner", { 14607 version: "1.11.1", 14608 defaultElement: "<input>", 14609 widgetEventPrefix: "spin", 14610 options: { 14611 culture: null, 14612 icons: { 14613 down: "ui-icon-triangle-1-s", 14614 up: "ui-icon-triangle-1-n" 14615 }, 14616 incremental: true, 14617 max: null, 14618 min: null, 14619 numberFormat: null, 14620 page: 10, 14621 step: 1, 14622 14623 change: null, 14624 spin: null, 14625 start: null, 14626 stop: null 14627 }, 14628 14629 _create: function() { 14630 // handle string values that need to be parsed 14631 this._setOption( "max", this.options.max ); 14632 this._setOption( "min", this.options.min ); 14633 this._setOption( "step", this.options.step ); 14634 14635 // Only format if there is a value, prevents the field from being marked 14636 // as invalid in Firefox, see #9573. 14637 if ( this.value() !== "" ) { 14638 // Format the value, but don't constrain. 14639 this._value( this.element.val(), true ); 14640 } 14641 14642 this._draw(); 14643 this._on( this._events ); 14644 this._refresh(); 14645 14646 // turning off autocomplete prevents the browser from remembering the 14647 // value when navigating through history, so we re-enable autocomplete 14648 // if the page is unloaded before the widget is destroyed. #7790 14649 this._on( this.window, { 14650 beforeunload: function() { 14651 this.element.removeAttr( "autocomplete" ); 14652 } 14653 }); 14654 }, 14655 14656 _getCreateOptions: function() { 14657 var options = {}, 14658 element = this.element; 14659 14660 $.each( [ "min", "max", "step" ], function( i, option ) { 14661 var value = element.attr( option ); 14662 if ( value !== undefined && value.length ) { 14663 options[ option ] = value; 14664 } 14665 }); 14666 14667 return options; 14668 }, 14669 14670 _events: { 14671 keydown: function( event ) { 14672 if ( this._start( event ) && this._keydown( event ) ) { 14673 event.preventDefault(); 14674 } 14675 }, 14676 keyup: "_stop", 14677 focus: function() { 14678 this.previous = this.element.val(); 14679 }, 14680 blur: function( event ) { 14681 if ( this.cancelBlur ) { 14682 delete this.cancelBlur; 14683 return; 14684 } 14685 14686 this._stop(); 14687 this._refresh(); 14688 if ( this.previous !== this.element.val() ) { 14689 this._trigger( "change", event ); 14690 } 14691 }, 14692 mousewheel: function( event, delta ) { 14693 if ( !delta ) { 14694 return; 14695 } 14696 if ( !this.spinning && !this._start( event ) ) { 14697 return false; 14698 } 14699 14700 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event ); 14701 clearTimeout( this.mousewheelTimer ); 14702 this.mousewheelTimer = this._delay(function() { 14703 if ( this.spinning ) { 14704 this._stop( event ); 14705 } 14706 }, 100 ); 14707 event.preventDefault(); 14708 }, 14709 "mousedown .ui-spinner-button": function( event ) { 14710 var previous; 14711 14712 // We never want the buttons to have focus; whenever the user is 14713 // interacting with the spinner, the focus should be on the input. 14714 // If the input is focused then this.previous is properly set from 14715 // when the input first received focus. If the input is not focused 14716 // then we need to set this.previous based on the value before spinning. 14717 previous = this.element[0] === this.document[0].activeElement ? 14718 this.previous : this.element.val(); 14719 function checkFocus() { 14720 var isActive = this.element[0] === this.document[0].activeElement; 14721 if ( !isActive ) { 14722 this.element.focus(); 14723 this.previous = previous; 14724 // support: IE 14725 // IE sets focus asynchronously, so we need to check if focus 14726 // moved off of the input because the user clicked on the button. 14727 this._delay(function() { 14728 this.previous = previous; 14729 }); 14730 } 14731 } 14732 14733 // ensure focus is on (or stays on) the text field 14734 event.preventDefault(); 14735 checkFocus.call( this ); 14736 14737 // support: IE 14738 // IE doesn't prevent moving focus even with event.preventDefault() 14739 // so we set a flag to know when we should ignore the blur event 14740 // and check (again) if focus moved off of the input. 14741 this.cancelBlur = true; 14742 this._delay(function() { 14743 delete this.cancelBlur; 14744 checkFocus.call( this ); 14745 }); 14746 14747 if ( this._start( event ) === false ) { 14748 return; 14749 } 14750 14751 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 14752 }, 14753 "mouseup .ui-spinner-button": "_stop", 14754 "mouseenter .ui-spinner-button": function( event ) { 14755 // button will add ui-state-active if mouse was down while mouseleave and kept down 14756 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { 14757 return; 14758 } 14759 14760 if ( this._start( event ) === false ) { 14761 return false; 14762 } 14763 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event ); 14764 }, 14765 // TODO: do we really want to consider this a stop? 14766 // shouldn't we just stop the repeater and wait until mouseup before 14767 // we trigger the stop event? 14768 "mouseleave .ui-spinner-button": "_stop" 14769 }, 14770 14771 _draw: function() { 14772 var uiSpinner = this.uiSpinner = this.element 14773 .addClass( "ui-spinner-input" ) 14774 .attr( "autocomplete", "off" ) 14775 .wrap( this._uiSpinnerHtml() ) 14776 .parent() 14777 // add buttons 14778 .append( this._buttonHtml() ); 14779 14780 this.element.attr( "role", "spinbutton" ); 14781 14782 // button bindings 14783 this.buttons = uiSpinner.find( ".ui-spinner-button" ) 14784 .attr( "tabIndex", -1 ) 14785 .button() 14786 .removeClass( "ui-corner-all" ); 14787 14788 // IE 6 doesn't understand height: 50% for the buttons 14789 // unless the wrapper has an explicit height 14790 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) && 14791 uiSpinner.height() > 0 ) { 14792 uiSpinner.height( uiSpinner.height() ); 14793 } 14794 14795 // disable spinner if element was already disabled 14796 if ( this.options.disabled ) { 14797 this.disable(); 14798 } 14799 }, 14800 14801 _keydown: function( event ) { 14802 var options = this.options, 14803 keyCode = $.ui.keyCode; 14804 14805 switch ( event.keyCode ) { 14806 case keyCode.UP: 14807 this._repeat( null, 1, event ); 14808 return true; 14809 case keyCode.DOWN: 14810 this._repeat( null, -1, event ); 14811 return true; 14812 case keyCode.PAGE_UP: 14813 this._repeat( null, options.page, event ); 14814 return true; 14815 case keyCode.PAGE_DOWN: 14816 this._repeat( null, -options.page, event ); 14817 return true; 14818 } 14819 14820 return false; 14821 }, 14822 14823 _uiSpinnerHtml: function() { 14824 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>"; 14825 }, 14826 14827 _buttonHtml: function() { 14828 return "" + 14829 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" + 14830 "<span class='ui-icon " + this.options.icons.up + "'>▲</span>" + 14831 "</a>" + 14832 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" + 14833 "<span class='ui-icon " + this.options.icons.down + "'>▼</span>" + 14834 "</a>"; 14835 }, 14836 14837 _start: function( event ) { 14838 if ( !this.spinning && this._trigger( "start", event ) === false ) { 14839 return false; 14840 } 14841 14842 if ( !this.counter ) { 14843 this.counter = 1; 14844 } 14845 this.spinning = true; 14846 return true; 14847 }, 14848 14849 _repeat: function( i, steps, event ) { 14850 i = i || 500; 14851 14852 clearTimeout( this.timer ); 14853 this.timer = this._delay(function() { 14854 this._repeat( 40, steps, event ); 14855 }, i ); 14856 14857 this._spin( steps * this.options.step, event ); 14858 }, 14859 14860 _spin: function( step, event ) { 14861 var value = this.value() || 0; 14862 14863 if ( !this.counter ) { 14864 this.counter = 1; 14865 } 14866 14867 value = this._adjustValue( value + step * this._increment( this.counter ) ); 14868 14869 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) { 14870 this._value( value ); 14871 this.counter++; 14872 } 14873 }, 14874 14875 _increment: function( i ) { 14876 var incremental = this.options.incremental; 14877 14878 if ( incremental ) { 14879 return $.isFunction( incremental ) ? 14880 incremental( i ) : 14881 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); 14882 } 14883 14884 return 1; 14885 }, 14886 14887 _precision: function() { 14888 var precision = this._precisionOf( this.options.step ); 14889 if ( this.options.min !== null ) { 14890 precision = Math.max( precision, this._precisionOf( this.options.min ) ); 14891 } 14892 return precision; 14893 }, 14894 14895 _precisionOf: function( num ) { 14896 var str = num.toString(), 14897 decimal = str.indexOf( "." ); 14898 return decimal === -1 ? 0 : str.length - decimal - 1; 14899 }, 14900 14901 _adjustValue: function( value ) { 14902 var base, aboveMin, 14903 options = this.options; 14904 14905 // make sure we're at a valid step 14906 // - find out where we are relative to the base (min or 0) 14907 base = options.min !== null ? options.min : 0; 14908 aboveMin = value - base; 14909 // - round to the nearest step 14910 aboveMin = Math.round(aboveMin / options.step) * options.step; 14911 // - rounding is based on 0, so adjust back to our base 14912 value = base + aboveMin; 14913 14914 // fix precision from bad JS floating point math 14915 value = parseFloat( value.toFixed( this._precision() ) ); 14916 14917 // clamp the value 14918 if ( options.max !== null && value > options.max) { 14919 return options.max; 14920 } 14921 if ( options.min !== null && value < options.min ) { 14922 return options.min; 14923 } 14924 14925 return value; 14926 }, 14927 14928 _stop: function( event ) { 14929 if ( !this.spinning ) { 14930 return; 14931 } 14932 14933 clearTimeout( this.timer ); 14934 clearTimeout( this.mousewheelTimer ); 14935 this.counter = 0; 14936 this.spinning = false; 14937 this._trigger( "stop", event ); 14938 }, 14939 14940 _setOption: function( key, value ) { 14941 if ( key === "culture" || key === "numberFormat" ) { 14942 var prevValue = this._parse( this.element.val() ); 14943 this.options[ key ] = value; 14944 this.element.val( this._format( prevValue ) ); 14945 return; 14946 } 14947 14948 if ( key === "max" || key === "min" || key === "step" ) { 14949 if ( typeof value === "string" ) { 14950 value = this._parse( value ); 14951 } 14952 } 14953 if ( key === "icons" ) { 14954 this.buttons.first().find( ".ui-icon" ) 14955 .removeClass( this.options.icons.up ) 14956 .addClass( value.up ); 14957 this.buttons.last().find( ".ui-icon" ) 14958 .removeClass( this.options.icons.down ) 14959 .addClass( value.down ); 14960 } 14961 14962 this._super( key, value ); 14963 14964 if ( key === "disabled" ) { 14965 this.widget().toggleClass( "ui-state-disabled", !!value ); 14966 this.element.prop( "disabled", !!value ); 14967 this.buttons.button( value ? "disable" : "enable" ); 14968 } 14969 }, 14970 14971 _setOptions: spinner_modifier(function( options ) { 14972 this._super( options ); 14973 }), 14974 14975 _parse: function( val ) { 14976 if ( typeof val === "string" && val !== "" ) { 14977 val = window.Globalize && this.options.numberFormat ? 14978 Globalize.parseFloat( val, 10, this.options.culture ) : +val; 14979 } 14980 return val === "" || isNaN( val ) ? null : val; 14981 }, 14982 14983 _format: function( value ) { 14984 if ( value === "" ) { 14985 return ""; 14986 } 14987 return window.Globalize && this.options.numberFormat ? 14988 Globalize.format( value, this.options.numberFormat, this.options.culture ) : 14989 value; 14990 }, 14991 14992 _refresh: function() { 14993 this.element.attr({ 14994 "aria-valuemin": this.options.min, 14995 "aria-valuemax": this.options.max, 14996 // TODO: what should we do with values that can't be parsed? 14997 "aria-valuenow": this._parse( this.element.val() ) 14998 }); 14999 }, 15000 15001 isValid: function() { 15002 var value = this.value(); 15003 15004 // null is invalid 15005 if ( value === null ) { 15006 return false; 15007 } 15008 15009 // if value gets adjusted, it's invalid 15010 return value === this._adjustValue( value ); 15011 }, 15012 15013 // update the value without triggering change 15014 _value: function( value, allowAny ) { 15015 var parsed; 15016 if ( value !== "" ) { 15017 parsed = this._parse( value ); 15018 if ( parsed !== null ) { 15019 if ( !allowAny ) { 15020 parsed = this._adjustValue( parsed ); 15021 } 15022 value = this._format( parsed ); 15023 } 15024 } 15025 this.element.val( value ); 15026 this._refresh(); 15027 }, 15028 15029 _destroy: function() { 15030 this.element 15031 .removeClass( "ui-spinner-input" ) 15032 .prop( "disabled", false ) 15033 .removeAttr( "autocomplete" ) 15034 .removeAttr( "role" ) 15035 .removeAttr( "aria-valuemin" ) 15036 .removeAttr( "aria-valuemax" ) 15037 .removeAttr( "aria-valuenow" ); 15038 this.uiSpinner.replaceWith( this.element ); 15039 }, 15040 15041 stepUp: spinner_modifier(function( steps ) { 15042 this._stepUp( steps ); 15043 }), 15044 _stepUp: function( steps ) { 15045 if ( this._start() ) { 15046 this._spin( (steps || 1) * this.options.step ); 15047 this._stop(); 15048 } 15049 }, 15050 15051 stepDown: spinner_modifier(function( steps ) { 15052 this._stepDown( steps ); 15053 }), 15054 _stepDown: function( steps ) { 15055 if ( this._start() ) { 15056 this._spin( (steps || 1) * -this.options.step ); 15057 this._stop(); 15058 } 15059 }, 15060 15061 pageUp: spinner_modifier(function( pages ) { 15062 this._stepUp( (pages || 1) * this.options.page ); 15063 }), 15064 15065 pageDown: spinner_modifier(function( pages ) { 15066 this._stepDown( (pages || 1) * this.options.page ); 15067 }), 15068 15069 value: function( newVal ) { 15070 if ( !arguments.length ) { 15071 return this._parse( this.element.val() ); 15072 } 15073 spinner_modifier( this._value ).call( this, newVal ); 15074 }, 15075 15076 widget: function() { 15077 return this.uiSpinner; 15078 } 15079 }); 15080 15081 15082 /*! 15083 * jQuery UI Tabs 1.11.1 15084 * http://jqueryui.com 15085 * 15086 * Copyright 2014 jQuery Foundation and other contributors 15087 * Released under the MIT license. 15088 * http://jquery.org/license 15089 * 15090 * http://api.jqueryui.com/tabs/ 15091 */ 15092 15093 15094 var tabs = $.widget( "ui.tabs", { 15095 version: "1.11.1", 15096 delay: 300, 15097 options: { 15098 active: null, 15099 collapsible: false, 15100 event: "click", 15101 heightStyle: "content", 15102 hide: null, 15103 show: null, 15104 15105 // callbacks 15106 activate: null, 15107 beforeActivate: null, 15108 beforeLoad: null, 15109 load: null 15110 }, 15111 15112 _isLocal: (function() { 15113 var rhash = /#.*$/; 15114 15115 return function( anchor ) { 15116 var anchorUrl, locationUrl; 15117 15118 // support: IE7 15119 // IE7 doesn't normalize the href property when set via script (#9317) 15120 anchor = anchor.cloneNode( false ); 15121 15122 anchorUrl = anchor.href.replace( rhash, "" ); 15123 locationUrl = location.href.replace( rhash, "" ); 15124 15125 // decoding may throw an error if the URL isn't UTF-8 (#9518) 15126 try { 15127 anchorUrl = decodeURIComponent( anchorUrl ); 15128 } catch ( error ) {} 15129 try { 15130 locationUrl = decodeURIComponent( locationUrl ); 15131 } catch ( error ) {} 15132 15133 return anchor.hash.length > 1 && anchorUrl === locationUrl; 15134 }; 15135 })(), 15136 15137 _create: function() { 15138 var that = this, 15139 options = this.options; 15140 15141 this.running = false; 15142 15143 this.element 15144 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" ) 15145 .toggleClass( "ui-tabs-collapsible", options.collapsible ); 15146 15147 this._processTabs(); 15148 options.active = this._initialActive(); 15149 15150 // Take disabling tabs via class attribute from HTML 15151 // into account and update option properly. 15152 if ( $.isArray( options.disabled ) ) { 15153 options.disabled = $.unique( options.disabled.concat( 15154 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { 15155 return that.tabs.index( li ); 15156 }) 15157 ) ).sort(); 15158 } 15159 15160 // check for length avoids error when initializing empty list 15161 if ( this.options.active !== false && this.anchors.length ) { 15162 this.active = this._findActive( options.active ); 15163 } else { 15164 this.active = $(); 15165 } 15166 15167 this._refresh(); 15168 15169 if ( this.active.length ) { 15170 this.load( options.active ); 15171 } 15172 }, 15173 15174 _initialActive: function() { 15175 var active = this.options.active, 15176 collapsible = this.options.collapsible, 15177 locationHash = location.hash.substring( 1 ); 15178 15179 if ( active === null ) { 15180 // check the fragment identifier in the URL 15181 if ( locationHash ) { 15182 this.tabs.each(function( i, tab ) { 15183 if ( $( tab ).attr( "aria-controls" ) === locationHash ) { 15184 active = i; 15185 return false; 15186 } 15187 }); 15188 } 15189 15190 // check for a tab marked active via a class 15191 if ( active === null ) { 15192 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); 15193 } 15194 15195 // no active tab, set to false 15196 if ( active === null || active === -1 ) { 15197 active = this.tabs.length ? 0 : false; 15198 } 15199 } 15200 15201 // handle numbers: negative, out of range 15202 if ( active !== false ) { 15203 active = this.tabs.index( this.tabs.eq( active ) ); 15204 if ( active === -1 ) { 15205 active = collapsible ? false : 0; 15206 } 15207 } 15208 15209 // don't allow collapsible: false and active: false 15210 if ( !collapsible && active === false && this.anchors.length ) { 15211 active = 0; 15212 } 15213 15214 return active; 15215 }, 15216 15217 _getCreateEventData: function() { 15218 return { 15219 tab: this.active, 15220 panel: !this.active.length ? $() : this._getPanelForTab( this.active ) 15221 }; 15222 }, 15223 15224 _tabKeydown: function( event ) { 15225 var focusedTab = $( this.document[0].activeElement ).closest( "li" ), 15226 selectedIndex = this.tabs.index( focusedTab ), 15227 goingForward = true; 15228 15229 if ( this._handlePageNav( event ) ) { 15230 return; 15231 } 15232 15233 switch ( event.keyCode ) { 15234 case $.ui.keyCode.RIGHT: 15235 case $.ui.keyCode.DOWN: 15236 selectedIndex++; 15237 break; 15238 case $.ui.keyCode.UP: 15239 case $.ui.keyCode.LEFT: 15240 goingForward = false; 15241 selectedIndex--; 15242 break; 15243 case $.ui.keyCode.END: 15244 selectedIndex = this.anchors.length - 1; 15245 break; 15246 case $.ui.keyCode.HOME: 15247 selectedIndex = 0; 15248 break; 15249 case $.ui.keyCode.SPACE: 15250 // Activate only, no collapsing 15251 event.preventDefault(); 15252 clearTimeout( this.activating ); 15253 this._activate( selectedIndex ); 15254 return; 15255 case $.ui.keyCode.ENTER: 15256 // Toggle (cancel delayed activation, allow collapsing) 15257 event.preventDefault(); 15258 clearTimeout( this.activating ); 15259 // Determine if we should collapse or activate 15260 this._activate( selectedIndex === this.options.active ? false : selectedIndex ); 15261 return; 15262 default: 15263 return; 15264 } 15265 15266 // Focus the appropriate tab, based on which key was pressed 15267 event.preventDefault(); 15268 clearTimeout( this.activating ); 15269 selectedIndex = this._focusNextTab( selectedIndex, goingForward ); 15270 15271 // Navigating with control key will prevent automatic activation 15272 if ( !event.ctrlKey ) { 15273 // Update aria-selected immediately so that AT think the tab is already selected. 15274 // Otherwise AT may confuse the user by stating that they need to activate the tab, 15275 // but the tab will already be activated by the time the announcement finishes. 15276 focusedTab.attr( "aria-selected", "false" ); 15277 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); 15278 15279 this.activating = this._delay(function() { 15280 this.option( "active", selectedIndex ); 15281 }, this.delay ); 15282 } 15283 }, 15284 15285 _panelKeydown: function( event ) { 15286 if ( this._handlePageNav( event ) ) { 15287 return; 15288 } 15289 15290 // Ctrl+up moves focus to the current tab 15291 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { 15292 event.preventDefault(); 15293 this.active.focus(); 15294 } 15295 }, 15296 15297 // Alt+page up/down moves focus to the previous/next tab (and activates) 15298 _handlePageNav: function( event ) { 15299 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { 15300 this._activate( this._focusNextTab( this.options.active - 1, false ) ); 15301 return true; 15302 } 15303 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { 15304 this._activate( this._focusNextTab( this.options.active + 1, true ) ); 15305 return true; 15306 } 15307 }, 15308 15309 _findNextTab: function( index, goingForward ) { 15310 var lastTabIndex = this.tabs.length - 1; 15311 15312 function constrain() { 15313 if ( index > lastTabIndex ) { 15314 index = 0; 15315 } 15316 if ( index < 0 ) { 15317 index = lastTabIndex; 15318 } 15319 return index; 15320 } 15321 15322 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { 15323 index = goingForward ? index + 1 : index - 1; 15324 } 15325 15326 return index; 15327 }, 15328 15329 _focusNextTab: function( index, goingForward ) { 15330 index = this._findNextTab( index, goingForward ); 15331 this.tabs.eq( index ).focus(); 15332 return index; 15333 }, 15334 15335 _setOption: function( key, value ) { 15336 if ( key === "active" ) { 15337 // _activate() will handle invalid values and update this.options 15338 this._activate( value ); 15339 return; 15340 } 15341 15342 if ( key === "disabled" ) { 15343 // don't use the widget factory's disabled handling 15344 this._setupDisabled( value ); 15345 return; 15346 } 15347 15348 this._super( key, value); 15349 15350 if ( key === "collapsible" ) { 15351 this.element.toggleClass( "ui-tabs-collapsible", value ); 15352 // Setting collapsible: false while collapsed; open first panel 15353 if ( !value && this.options.active === false ) { 15354 this._activate( 0 ); 15355 } 15356 } 15357 15358 if ( key === "event" ) { 15359 this._setupEvents( value ); 15360 } 15361 15362 if ( key === "heightStyle" ) { 15363 this._setupHeightStyle( value ); 15364 } 15365 }, 15366 15367 _sanitizeSelector: function( hash ) { 15368 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : ""; 15369 }, 15370 15371 refresh: function() { 15372 var options = this.options, 15373 lis = this.tablist.children( ":has(a[href])" ); 15374 15375 // get disabled tabs from class attribute from HTML 15376 // this will get converted to a boolean if needed in _refresh() 15377 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { 15378 return lis.index( tab ); 15379 }); 15380 15381 this._processTabs(); 15382 15383 // was collapsed or no tabs 15384 if ( options.active === false || !this.anchors.length ) { 15385 options.active = false; 15386 this.active = $(); 15387 // was active, but active tab is gone 15388 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { 15389 // all remaining tabs are disabled 15390 if ( this.tabs.length === options.disabled.length ) { 15391 options.active = false; 15392 this.active = $(); 15393 // activate previous tab 15394 } else { 15395 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); 15396 } 15397 // was active, active tab still exists 15398 } else { 15399 // make sure active index is correct 15400 options.active = this.tabs.index( this.active ); 15401 } 15402 15403 this._refresh(); 15404 }, 15405 15406 _refresh: function() { 15407 this._setupDisabled( this.options.disabled ); 15408 this._setupEvents( this.options.event ); 15409 this._setupHeightStyle( this.options.heightStyle ); 15410 15411 this.tabs.not( this.active ).attr({ 15412 "aria-selected": "false", 15413 "aria-expanded": "false", 15414 tabIndex: -1 15415 }); 15416 this.panels.not( this._getPanelForTab( this.active ) ) 15417 .hide() 15418 .attr({ 15419 "aria-hidden": "true" 15420 }); 15421 15422 // Make sure one tab is in the tab order 15423 if ( !this.active.length ) { 15424 this.tabs.eq( 0 ).attr( "tabIndex", 0 ); 15425 } else { 15426 this.active 15427 .addClass( "ui-tabs-active ui-state-active" ) 15428 .attr({ 15429 "aria-selected": "true", 15430 "aria-expanded": "true", 15431 tabIndex: 0 15432 }); 15433 this._getPanelForTab( this.active ) 15434 .show() 15435 .attr({ 15436 "aria-hidden": "false" 15437 }); 15438 } 15439 }, 15440 15441 _processTabs: function() { 15442 var that = this; 15443 15444 this.tablist = this._getList() 15445 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) 15446 .attr( "role", "tablist" ) 15447 15448 // Prevent users from focusing disabled tabs via click 15449 .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) { 15450 if ( $( this ).is( ".ui-state-disabled" ) ) { 15451 event.preventDefault(); 15452 } 15453 }) 15454 15455 // support: IE <9 15456 // Preventing the default action in mousedown doesn't prevent IE 15457 // from focusing the element, so if the anchor gets focused, blur. 15458 // We don't have to worry about focusing the previously focused 15459 // element since clicking on a non-focusable element should focus 15460 // the body anyway. 15461 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() { 15462 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) { 15463 this.blur(); 15464 } 15465 }); 15466 15467 this.tabs = this.tablist.find( "> li:has(a[href])" ) 15468 .addClass( "ui-state-default ui-corner-top" ) 15469 .attr({ 15470 role: "tab", 15471 tabIndex: -1 15472 }); 15473 15474 this.anchors = this.tabs.map(function() { 15475 return $( "a", this )[ 0 ]; 15476 }) 15477 .addClass( "ui-tabs-anchor" ) 15478 .attr({ 15479 role: "presentation", 15480 tabIndex: -1 15481 }); 15482 15483 this.panels = $(); 15484 15485 this.anchors.each(function( i, anchor ) { 15486 var selector, panel, panelId, 15487 anchorId = $( anchor ).uniqueId().attr( "id" ), 15488 tab = $( anchor ).closest( "li" ), 15489 originalAriaControls = tab.attr( "aria-controls" ); 15490 15491 // inline tab 15492 if ( that._isLocal( anchor ) ) { 15493 selector = anchor.hash; 15494 panelId = selector.substring( 1 ); 15495 panel = that.element.find( that._sanitizeSelector( selector ) ); 15496 // remote tab 15497 } else { 15498 // If the tab doesn't already have aria-controls, 15499 // generate an id by using a throw-away element 15500 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; 15501 selector = "#" + panelId; 15502 panel = that.element.find( selector ); 15503 if ( !panel.length ) { 15504 panel = that._createPanel( panelId ); 15505 panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); 15506 } 15507 panel.attr( "aria-live", "polite" ); 15508 } 15509 15510 if ( panel.length) { 15511 that.panels = that.panels.add( panel ); 15512 } 15513 if ( originalAriaControls ) { 15514 tab.data( "ui-tabs-aria-controls", originalAriaControls ); 15515 } 15516 tab.attr({ 15517 "aria-controls": panelId, 15518 "aria-labelledby": anchorId 15519 }); 15520 panel.attr( "aria-labelledby", anchorId ); 15521 }); 15522 15523 this.panels 15524 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) 15525 .attr( "role", "tabpanel" ); 15526 }, 15527 15528 // allow overriding how to find the list for rare usage scenarios (#7715) 15529 _getList: function() { 15530 return this.tablist || this.element.find( "ol,ul" ).eq( 0 ); 15531 }, 15532 15533 _createPanel: function( id ) { 15534 return $( "<div>" ) 15535 .attr( "id", id ) 15536 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" ) 15537 .data( "ui-tabs-destroy", true ); 15538 }, 15539 15540 _setupDisabled: function( disabled ) { 15541 if ( $.isArray( disabled ) ) { 15542 if ( !disabled.length ) { 15543 disabled = false; 15544 } else if ( disabled.length === this.anchors.length ) { 15545 disabled = true; 15546 } 15547 } 15548 15549 // disable tabs 15550 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) { 15551 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { 15552 $( li ) 15553 .addClass( "ui-state-disabled" ) 15554 .attr( "aria-disabled", "true" ); 15555 } else { 15556 $( li ) 15557 .removeClass( "ui-state-disabled" ) 15558 .removeAttr( "aria-disabled" ); 15559 } 15560 } 15561 15562 this.options.disabled = disabled; 15563 }, 15564 15565 _setupEvents: function( event ) { 15566 var events = {}; 15567 if ( event ) { 15568 $.each( event.split(" "), function( index, eventName ) { 15569 events[ eventName ] = "_eventHandler"; 15570 }); 15571 } 15572 15573 this._off( this.anchors.add( this.tabs ).add( this.panels ) ); 15574 // Always prevent the default action, even when disabled 15575 this._on( true, this.anchors, { 15576 click: function( event ) { 15577 event.preventDefault(); 15578 } 15579 }); 15580 this._on( this.anchors, events ); 15581 this._on( this.tabs, { keydown: "_tabKeydown" } ); 15582 this._on( this.panels, { keydown: "_panelKeydown" } ); 15583 15584 this._focusable( this.tabs ); 15585 this._hoverable( this.tabs ); 15586 }, 15587 15588 _setupHeightStyle: function( heightStyle ) { 15589 var maxHeight, 15590 parent = this.element.parent(); 15591 15592 if ( heightStyle === "fill" ) { 15593 maxHeight = parent.height(); 15594 maxHeight -= this.element.outerHeight() - this.element.height(); 15595 15596 this.element.siblings( ":visible" ).each(function() { 15597 var elem = $( this ), 15598 position = elem.css( "position" ); 15599 15600 if ( position === "absolute" || position === "fixed" ) { 15601 return; 15602 } 15603 maxHeight -= elem.outerHeight( true ); 15604 }); 15605 15606 this.element.children().not( this.panels ).each(function() { 15607 maxHeight -= $( this ).outerHeight( true ); 15608 }); 15609 15610 this.panels.each(function() { 15611 $( this ).height( Math.max( 0, maxHeight - 15612 $( this ).innerHeight() + $( this ).height() ) ); 15613 }) 15614 .css( "overflow", "auto" ); 15615 } else if ( heightStyle === "auto" ) { 15616 maxHeight = 0; 15617 this.panels.each(function() { 15618 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); 15619 }).height( maxHeight ); 15620 } 15621 }, 15622 15623 _eventHandler: function( event ) { 15624 var options = this.options, 15625 active = this.active, 15626 anchor = $( event.currentTarget ), 15627 tab = anchor.closest( "li" ), 15628 clickedIsActive = tab[ 0 ] === active[ 0 ], 15629 collapsing = clickedIsActive && options.collapsible, 15630 toShow = collapsing ? $() : this._getPanelForTab( tab ), 15631 toHide = !active.length ? $() : this._getPanelForTab( active ), 15632 eventData = { 15633 oldTab: active, 15634 oldPanel: toHide, 15635 newTab: collapsing ? $() : tab, 15636 newPanel: toShow 15637 }; 15638 15639 event.preventDefault(); 15640 15641 if ( tab.hasClass( "ui-state-disabled" ) || 15642 // tab is already loading 15643 tab.hasClass( "ui-tabs-loading" ) || 15644 // can't switch durning an animation 15645 this.running || 15646 // click on active header, but not collapsible 15647 ( clickedIsActive && !options.collapsible ) || 15648 // allow canceling activation 15649 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { 15650 return; 15651 } 15652 15653 options.active = collapsing ? false : this.tabs.index( tab ); 15654 15655 this.active = clickedIsActive ? $() : tab; 15656 if ( this.xhr ) { 15657 this.xhr.abort(); 15658 } 15659 15660 if ( !toHide.length && !toShow.length ) { 15661 $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); 15662 } 15663 15664 if ( toShow.length ) { 15665 this.load( this.tabs.index( tab ), event ); 15666 } 15667 this._toggle( event, eventData ); 15668 }, 15669 15670 // handles show/hide for selecting tabs 15671 _toggle: function( event, eventData ) { 15672 var that = this, 15673 toShow = eventData.newPanel, 15674 toHide = eventData.oldPanel; 15675 15676 this.running = true; 15677 15678 function complete() { 15679 that.running = false; 15680 that._trigger( "activate", event, eventData ); 15681 } 15682 15683 function show() { 15684 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" ); 15685 15686 if ( toShow.length && that.options.show ) { 15687 that._show( toShow, that.options.show, complete ); 15688 } else { 15689 toShow.show(); 15690 complete(); 15691 } 15692 } 15693 15694 // start out by hiding, then showing, then completing 15695 if ( toHide.length && this.options.hide ) { 15696 this._hide( toHide, this.options.hide, function() { 15697 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); 15698 show(); 15699 }); 15700 } else { 15701 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" ); 15702 toHide.hide(); 15703 show(); 15704 } 15705 15706 toHide.attr( "aria-hidden", "true" ); 15707 eventData.oldTab.attr({ 15708 "aria-selected": "false", 15709 "aria-expanded": "false" 15710 }); 15711 // If we're switching tabs, remove the old tab from the tab order. 15712 // If we're opening from collapsed state, remove the previous tab from the tab order. 15713 // If we're collapsing, then keep the collapsing tab in the tab order. 15714 if ( toShow.length && toHide.length ) { 15715 eventData.oldTab.attr( "tabIndex", -1 ); 15716 } else if ( toShow.length ) { 15717 this.tabs.filter(function() { 15718 return $( this ).attr( "tabIndex" ) === 0; 15719 }) 15720 .attr( "tabIndex", -1 ); 15721 } 15722 15723 toShow.attr( "aria-hidden", "false" ); 15724 eventData.newTab.attr({ 15725 "aria-selected": "true", 15726 "aria-expanded": "true", 15727 tabIndex: 0 15728 }); 15729 }, 15730 15731 _activate: function( index ) { 15732 var anchor, 15733 active = this._findActive( index ); 15734 15735 // trying to activate the already active panel 15736 if ( active[ 0 ] === this.active[ 0 ] ) { 15737 return; 15738 } 15739 15740 // trying to collapse, simulate a click on the current active header 15741 if ( !active.length ) { 15742 active = this.active; 15743 } 15744 15745 anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; 15746 this._eventHandler({ 15747 target: anchor, 15748 currentTarget: anchor, 15749 preventDefault: $.noop 15750 }); 15751 }, 15752 15753 _findActive: function( index ) { 15754 return index === false ? $() : this.tabs.eq( index ); 15755 }, 15756 15757 _getIndex: function( index ) { 15758 // meta-function to give users option to provide a href string instead of a numerical index. 15759 if ( typeof index === "string" ) { 15760 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) ); 15761 } 15762 15763 return index; 15764 }, 15765 15766 _destroy: function() { 15767 if ( this.xhr ) { 15768 this.xhr.abort(); 15769 } 15770 15771 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" ); 15772 15773 this.tablist 15774 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" ) 15775 .removeAttr( "role" ); 15776 15777 this.anchors 15778 .removeClass( "ui-tabs-anchor" ) 15779 .removeAttr( "role" ) 15780 .removeAttr( "tabIndex" ) 15781 .removeUniqueId(); 15782 15783 this.tablist.unbind( this.eventNamespace ); 15784 15785 this.tabs.add( this.panels ).each(function() { 15786 if ( $.data( this, "ui-tabs-destroy" ) ) { 15787 $( this ).remove(); 15788 } else { 15789 $( this ) 15790 .removeClass( "ui-state-default ui-state-active ui-state-disabled " + 15791 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" ) 15792 .removeAttr( "tabIndex" ) 15793 .removeAttr( "aria-live" ) 15794 .removeAttr( "aria-busy" ) 15795 .removeAttr( "aria-selected" ) 15796 .removeAttr( "aria-labelledby" ) 15797 .removeAttr( "aria-hidden" ) 15798 .removeAttr( "aria-expanded" ) 15799 .removeAttr( "role" ); 15800 } 15801 }); 15802 15803 this.tabs.each(function() { 15804 var li = $( this ), 15805 prev = li.data( "ui-tabs-aria-controls" ); 15806 if ( prev ) { 15807 li 15808 .attr( "aria-controls", prev ) 15809 .removeData( "ui-tabs-aria-controls" ); 15810 } else { 15811 li.removeAttr( "aria-controls" ); 15812 } 15813 }); 15814 15815 this.panels.show(); 15816 15817 if ( this.options.heightStyle !== "content" ) { 15818 this.panels.css( "height", "" ); 15819 } 15820 }, 15821 15822 enable: function( index ) { 15823 var disabled = this.options.disabled; 15824 if ( disabled === false ) { 15825 return; 15826 } 15827 15828 if ( index === undefined ) { 15829 disabled = false; 15830 } else { 15831 index = this._getIndex( index ); 15832 if ( $.isArray( disabled ) ) { 15833 disabled = $.map( disabled, function( num ) { 15834 return num !== index ? num : null; 15835 }); 15836 } else { 15837 disabled = $.map( this.tabs, function( li, num ) { 15838 return num !== index ? num : null; 15839 }); 15840 } 15841 } 15842 this._setupDisabled( disabled ); 15843 }, 15844 15845 disable: function( index ) { 15846 var disabled = this.options.disabled; 15847 if ( disabled === true ) { 15848 return; 15849 } 15850 15851 if ( index === undefined ) { 15852 disabled = true; 15853 } else { 15854 index = this._getIndex( index ); 15855 if ( $.inArray( index, disabled ) !== -1 ) { 15856 return; 15857 } 15858 if ( $.isArray( disabled ) ) { 15859 disabled = $.merge( [ index ], disabled ).sort(); 15860 } else { 15861 disabled = [ index ]; 15862 } 15863 } 15864 this._setupDisabled( disabled ); 15865 }, 15866 15867 load: function( index, event ) { 15868 index = this._getIndex( index ); 15869 var that = this, 15870 tab = this.tabs.eq( index ), 15871 anchor = tab.find( ".ui-tabs-anchor" ), 15872 panel = this._getPanelForTab( tab ), 15873 eventData = { 15874 tab: tab, 15875 panel: panel 15876 }; 15877 15878 // not remote 15879 if ( this._isLocal( anchor[ 0 ] ) ) { 15880 return; 15881 } 15882 15883 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); 15884 15885 // support: jQuery <1.8 15886 // jQuery <1.8 returns false if the request is canceled in beforeSend, 15887 // but as of 1.8, $.ajax() always returns a jqXHR object. 15888 if ( this.xhr && this.xhr.statusText !== "canceled" ) { 15889 tab.addClass( "ui-tabs-loading" ); 15890 panel.attr( "aria-busy", "true" ); 15891 15892 this.xhr 15893 .success(function( response ) { 15894 // support: jQuery <1.8 15895 // http://bugs.jquery.com/ticket/11778 15896 setTimeout(function() { 15897 panel.html( response ); 15898 that._trigger( "load", event, eventData ); 15899 }, 1 ); 15900 }) 15901 .complete(function( jqXHR, status ) { 15902 // support: jQuery <1.8 15903 // http://bugs.jquery.com/ticket/11778 15904 setTimeout(function() { 15905 if ( status === "abort" ) { 15906 that.panels.stop( false, true ); 15907 } 15908 15909 tab.removeClass( "ui-tabs-loading" ); 15910 panel.removeAttr( "aria-busy" ); 15911 15912 if ( jqXHR === that.xhr ) { 15913 delete that.xhr; 15914 } 15915 }, 1 ); 15916 }); 15917 } 15918 }, 15919 15920 _ajaxSettings: function( anchor, event, eventData ) { 15921 var that = this; 15922 return { 15923 url: anchor.attr( "href" ), 15924 beforeSend: function( jqXHR, settings ) { 15925 return that._trigger( "beforeLoad", event, 15926 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); 15927 } 15928 }; 15929 }, 15930 15931 _getPanelForTab: function( tab ) { 15932 var id = $( tab ).attr( "aria-controls" ); 15933 return this.element.find( this._sanitizeSelector( "#" + id ) ); 15934 } 15935 }); 15936 15937 15938 /*! 15939 * jQuery UI Tooltip 1.11.1 15940 * http://jqueryui.com 15941 * 15942 * Copyright 2014 jQuery Foundation and other contributors 15943 * Released under the MIT license. 15944 * http://jquery.org/license 15945 * 15946 * http://api.jqueryui.com/tooltip/ 15947 */ 15948 15949 15950 var tooltip = $.widget( "ui.tooltip", { 15951 version: "1.11.1", 15952 options: { 15953 content: function() { 15954 // support: IE<9, Opera in jQuery <1.7 15955 // .text() can't accept undefined, so coerce to a string 15956 var title = $( this ).attr( "title" ) || ""; 15957 // Escape title, since we're going from an attribute to raw HTML 15958 return $( "<a>" ).text( title ).html(); 15959 }, 15960 hide: true, 15961 // Disabled elements have inconsistent behavior across browsers (#8661) 15962 items: "[title]:not([disabled])", 15963 position: { 15964 my: "left top+15", 15965 at: "left bottom", 15966 collision: "flipfit flip" 15967 }, 15968 show: true, 15969 tooltipClass: null, 15970 track: false, 15971 15972 // callbacks 15973 close: null, 15974 open: null 15975 }, 15976 15977 _addDescribedBy: function( elem, id ) { 15978 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ); 15979 describedby.push( id ); 15980 elem 15981 .data( "ui-tooltip-id", id ) 15982 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) ); 15983 }, 15984 15985 _removeDescribedBy: function( elem ) { 15986 var id = elem.data( "ui-tooltip-id" ), 15987 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ), 15988 index = $.inArray( id, describedby ); 15989 15990 if ( index !== -1 ) { 15991 describedby.splice( index, 1 ); 15992 } 15993 15994 elem.removeData( "ui-tooltip-id" ); 15995 describedby = $.trim( describedby.join( " " ) ); 15996 if ( describedby ) { 15997 elem.attr( "aria-describedby", describedby ); 15998 } else { 15999 elem.removeAttr( "aria-describedby" ); 16000 } 16001 }, 16002 16003 _create: function() { 16004 this._on({ 16005 mouseover: "open", 16006 focusin: "open" 16007 }); 16008 16009 // IDs of generated tooltips, needed for destroy 16010 this.tooltips = {}; 16011 // IDs of parent tooltips where we removed the title attribute 16012 this.parents = {}; 16013 16014 if ( this.options.disabled ) { 16015 this._disable(); 16016 } 16017 16018 // Append the aria-live region so tooltips announce correctly 16019 this.liveRegion = $( "<div>" ) 16020 .attr({ 16021 role: "log", 16022 "aria-live": "assertive", 16023 "aria-relevant": "additions" 16024 }) 16025 .addClass( "ui-helper-hidden-accessible" ) 16026 .appendTo( this.document[ 0 ].body ); 16027 }, 16028 16029 _setOption: function( key, value ) { 16030 var that = this; 16031 16032 if ( key === "disabled" ) { 16033 this[ value ? "_disable" : "_enable" ](); 16034 this.options[ key ] = value; 16035 // disable element style changes 16036 return; 16037 } 16038 16039 this._super( key, value ); 16040 16041 if ( key === "content" ) { 16042 $.each( this.tooltips, function( id, element ) { 16043 that._updateContent( element ); 16044 }); 16045 } 16046 }, 16047 16048 _disable: function() { 16049 var that = this; 16050 16051 // close open tooltips 16052 $.each( this.tooltips, function( id, element ) { 16053 var event = $.Event( "blur" ); 16054 event.target = event.currentTarget = element[0]; 16055 that.close( event, true ); 16056 }); 16057 16058 // remove title attributes to prevent native tooltips 16059 this.element.find( this.options.items ).addBack().each(function() { 16060 var element = $( this ); 16061 if ( element.is( "[title]" ) ) { 16062 element 16063 .data( "ui-tooltip-title", element.attr( "title" ) ) 16064 .removeAttr( "title" ); 16065 } 16066 }); 16067 }, 16068 16069 _enable: function() { 16070 // restore title attributes 16071 this.element.find( this.options.items ).addBack().each(function() { 16072 var element = $( this ); 16073 if ( element.data( "ui-tooltip-title" ) ) { 16074 element.attr( "title", element.data( "ui-tooltip-title" ) ); 16075 } 16076 }); 16077 }, 16078 16079 open: function( event ) { 16080 var that = this, 16081 target = $( event ? event.target : this.element ) 16082 // we need closest here due to mouseover bubbling, 16083 // but always pointing at the same event target 16084 .closest( this.options.items ); 16085 16086 // No element to show a tooltip for or the tooltip is already open 16087 if ( !target.length || target.data( "ui-tooltip-id" ) ) { 16088 return; 16089 } 16090 16091 if ( target.attr( "title" ) ) { 16092 target.data( "ui-tooltip-title", target.attr( "title" ) ); 16093 } 16094 16095 target.data( "ui-tooltip-open", true ); 16096 16097 // kill parent tooltips, custom or native, for hover 16098 if ( event && event.type === "mouseover" ) { 16099 target.parents().each(function() { 16100 var parent = $( this ), 16101 blurEvent; 16102 if ( parent.data( "ui-tooltip-open" ) ) { 16103 blurEvent = $.Event( "blur" ); 16104 blurEvent.target = blurEvent.currentTarget = this; 16105 that.close( blurEvent, true ); 16106 } 16107 if ( parent.attr( "title" ) ) { 16108 parent.uniqueId(); 16109 that.parents[ this.id ] = { 16110 element: this, 16111 title: parent.attr( "title" ) 16112 }; 16113 parent.attr( "title", "" ); 16114 } 16115 }); 16116 } 16117 16118 this._updateContent( target, event ); 16119 }, 16120 16121 _updateContent: function( target, event ) { 16122 var content, 16123 contentOption = this.options.content, 16124 that = this, 16125 eventType = event ? event.type : null; 16126 16127 if ( typeof contentOption === "string" ) { 16128 return this._open( event, target, contentOption ); 16129 } 16130 16131 content = contentOption.call( target[0], function( response ) { 16132 // ignore async response if tooltip was closed already 16133 if ( !target.data( "ui-tooltip-open" ) ) { 16134 return; 16135 } 16136 // IE may instantly serve a cached response for ajax requests 16137 // delay this call to _open so the other call to _open runs first 16138 that._delay(function() { 16139 // jQuery creates a special event for focusin when it doesn't 16140 // exist natively. To improve performance, the native event 16141 // object is reused and the type is changed. Therefore, we can't 16142 // rely on the type being correct after the event finished 16143 // bubbling, so we set it back to the previous value. (#8740) 16144 if ( event ) { 16145 event.type = eventType; 16146 } 16147 this._open( event, target, response ); 16148 }); 16149 }); 16150 if ( content ) { 16151 this._open( event, target, content ); 16152 } 16153 }, 16154 16155 _open: function( event, target, content ) { 16156 var tooltip, events, delayedShow, a11yContent, 16157 positionOption = $.extend( {}, this.options.position ); 16158 16159 if ( !content ) { 16160 return; 16161 } 16162 16163 // Content can be updated multiple times. If the tooltip already 16164 // exists, then just update the content and bail. 16165 tooltip = this._find( target ); 16166 if ( tooltip.length ) { 16167 tooltip.find( ".ui-tooltip-content" ).html( content ); 16168 return; 16169 } 16170 16171 // if we have a title, clear it to prevent the native tooltip 16172 // we have to check first to avoid defining a title if none exists 16173 // (we don't want to cause an element to start matching [title]) 16174 // 16175 // We use removeAttr only for key events, to allow IE to export the correct 16176 // accessible attributes. For mouse events, set to empty string to avoid 16177 // native tooltip showing up (happens only when removing inside mouseover). 16178 if ( target.is( "[title]" ) ) { 16179 if ( event && event.type === "mouseover" ) { 16180 target.attr( "title", "" ); 16181 } else { 16182 target.removeAttr( "title" ); 16183 } 16184 } 16185 16186 tooltip = this._tooltip( target ); 16187 this._addDescribedBy( target, tooltip.attr( "id" ) ); 16188 tooltip.find( ".ui-tooltip-content" ).html( content ); 16189 16190 // Support: Voiceover on OS X, JAWS on IE <= 9 16191 // JAWS announces deletions even when aria-relevant="additions" 16192 // Voiceover will sometimes re-read the entire log region's contents from the beginning 16193 this.liveRegion.children().hide(); 16194 if ( content.clone ) { 16195 a11yContent = content.clone(); 16196 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); 16197 } else { 16198 a11yContent = content; 16199 } 16200 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion ); 16201 16202 function position( event ) { 16203 positionOption.of = event; 16204 if ( tooltip.is( ":hidden" ) ) { 16205 return; 16206 } 16207 tooltip.position( positionOption ); 16208 } 16209 if ( this.options.track && event && /^mouse/.test( event.type ) ) { 16210 this._on( this.document, { 16211 mousemove: position 16212 }); 16213 // trigger once to override element-relative positioning 16214 position( event ); 16215 } else { 16216 tooltip.position( $.extend({ 16217 of: target 16218 }, this.options.position ) ); 16219 } 16220 16221 this.hiding = false; 16222 this.closing = false; 16223 tooltip.hide(); 16224 16225 this._show( tooltip, this.options.show ); 16226 // Handle tracking tooltips that are shown with a delay (#8644). As soon 16227 // as the tooltip is visible, position the tooltip using the most recent 16228 // event. 16229 if ( this.options.show && this.options.show.delay ) { 16230 delayedShow = this.delayedShow = setInterval(function() { 16231 if ( tooltip.is( ":visible" ) ) { 16232 position( positionOption.of ); 16233 clearInterval( delayedShow ); 16234 } 16235 }, $.fx.interval ); 16236 } 16237 16238 this._trigger( "open", event, { tooltip: tooltip } ); 16239 16240 events = { 16241 keyup: function( event ) { 16242 if ( event.keyCode === $.ui.keyCode.ESCAPE ) { 16243 var fakeEvent = $.Event(event); 16244 fakeEvent.currentTarget = target[0]; 16245 this.close( fakeEvent, true ); 16246 } 16247 } 16248 }; 16249 16250 // Only bind remove handler for delegated targets. Non-delegated 16251 // tooltips will handle this in destroy. 16252 if ( target[ 0 ] !== this.element[ 0 ] ) { 16253 events.remove = function() { 16254 this._removeTooltip( tooltip ); 16255 }; 16256 } 16257 16258 if ( !event || event.type === "mouseover" ) { 16259 events.mouseleave = "close"; 16260 } 16261 if ( !event || event.type === "focusin" ) { 16262 events.focusout = "close"; 16263 } 16264 this._on( true, target, events ); 16265 }, 16266 16267 close: function( event ) { 16268 var that = this, 16269 target = $( event ? event.currentTarget : this.element ), 16270 tooltip = this._find( target ); 16271 16272 // disabling closes the tooltip, so we need to track when we're closing 16273 // to avoid an infinite loop in case the tooltip becomes disabled on close 16274 if ( this.closing ) { 16275 return; 16276 } 16277 16278 // Clear the interval for delayed tracking tooltips 16279 clearInterval( this.delayedShow ); 16280 16281 // only set title if we had one before (see comment in _open()) 16282 // If the title attribute has changed since open(), don't restore 16283 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { 16284 target.attr( "title", target.data( "ui-tooltip-title" ) ); 16285 } 16286 16287 this._removeDescribedBy( target ); 16288 16289 this.hiding = true; 16290 tooltip.stop( true ); 16291 this._hide( tooltip, this.options.hide, function() { 16292 that._removeTooltip( $( this ) ); 16293 this.hiding = false; 16294 this.closing = false; 16295 }); 16296 16297 target.removeData( "ui-tooltip-open" ); 16298 this._off( target, "mouseleave focusout keyup" ); 16299 16300 // Remove 'remove' binding only on delegated targets 16301 if ( target[ 0 ] !== this.element[ 0 ] ) { 16302 this._off( target, "remove" ); 16303 } 16304 this._off( this.document, "mousemove" ); 16305 16306 if ( event && event.type === "mouseleave" ) { 16307 $.each( this.parents, function( id, parent ) { 16308 $( parent.element ).attr( "title", parent.title ); 16309 delete that.parents[ id ]; 16310 }); 16311 } 16312 16313 this.closing = true; 16314 this._trigger( "close", event, { tooltip: tooltip } ); 16315 if ( !this.hiding ) { 16316 this.closing = false; 16317 } 16318 }, 16319 16320 _tooltip: function( element ) { 16321 var tooltip = $( "<div>" ) 16322 .attr( "role", "tooltip" ) 16323 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " + 16324 ( this.options.tooltipClass || "" ) ), 16325 id = tooltip.uniqueId().attr( "id" ); 16326 16327 $( "<div>" ) 16328 .addClass( "ui-tooltip-content" ) 16329 .appendTo( tooltip ); 16330 16331 tooltip.appendTo( this.document[0].body ); 16332 this.tooltips[ id ] = element; 16333 return tooltip; 16334 }, 16335 16336 _find: function( target ) { 16337 var id = target.data( "ui-tooltip-id" ); 16338 return id ? $( "#" + id ) : $(); 16339 }, 16340 16341 _removeTooltip: function( tooltip ) { 16342 tooltip.remove(); 16343 delete this.tooltips[ tooltip.attr( "id" ) ]; 16344 }, 16345 16346 _destroy: function() { 16347 var that = this; 16348 16349 // close open tooltips 16350 $.each( this.tooltips, function( id, element ) { 16351 // Delegate to close method to handle common cleanup 16352 var event = $.Event( "blur" ); 16353 event.target = event.currentTarget = element[0]; 16354 that.close( event, true ); 16355 16356 // Remove immediately; destroying an open tooltip doesn't use the 16357 // hide animation 16358 $( "#" + id ).remove(); 16359 16360 // Restore the title 16361 if ( element.data( "ui-tooltip-title" ) ) { 16362 // If the title attribute has changed since open(), don't restore 16363 if ( !element.attr( "title" ) ) { 16364 element.attr( "title", element.data( "ui-tooltip-title" ) ); 16365 } 16366 element.removeData( "ui-tooltip-title" ); 16367 } 16368 }); 16369 this.liveRegion.remove(); 16370 } 16371 }); 16372 16373 16374 16375 }));
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |