annotate src/DML/VendorAssetsBundle/Resources/assets/jquery.ui/1.11.0-src/jquery-ui.js @ 1:f38015048f48 tip

Added GPL
author Daniel Wolff
date Sat, 13 Feb 2016 20:43:38 +0100
parents 493bcb69166c
children
rev   line source
Daniel@0 1 /*! jQuery UI - v1.11.0 - 2014-06-26
Daniel@0 2 * http://jqueryui.com
Daniel@0 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
Daniel@0 4 * Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
Daniel@0 5
Daniel@0 6 (function( factory ) {
Daniel@0 7 if ( typeof define === "function" && define.amd ) {
Daniel@0 8
Daniel@0 9 // AMD. Register as an anonymous module.
Daniel@0 10 define([ "jquery" ], factory );
Daniel@0 11 } else {
Daniel@0 12
Daniel@0 13 // Browser globals
Daniel@0 14 factory( jQuery );
Daniel@0 15 }
Daniel@0 16 }(function( $ ) {
Daniel@0 17 /*!
Daniel@0 18 * jQuery UI Core 1.11.0
Daniel@0 19 * http://jqueryui.com
Daniel@0 20 *
Daniel@0 21 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 22 * Released under the MIT license.
Daniel@0 23 * http://jquery.org/license
Daniel@0 24 *
Daniel@0 25 * http://api.jqueryui.com/category/ui-core/
Daniel@0 26 */
Daniel@0 27
Daniel@0 28
Daniel@0 29 // $.ui might exist from components with no dependencies, e.g., $.ui.position
Daniel@0 30 $.ui = $.ui || {};
Daniel@0 31
Daniel@0 32 $.extend( $.ui, {
Daniel@0 33 version: "1.11.0",
Daniel@0 34
Daniel@0 35 keyCode: {
Daniel@0 36 BACKSPACE: 8,
Daniel@0 37 COMMA: 188,
Daniel@0 38 DELETE: 46,
Daniel@0 39 DOWN: 40,
Daniel@0 40 END: 35,
Daniel@0 41 ENTER: 13,
Daniel@0 42 ESCAPE: 27,
Daniel@0 43 HOME: 36,
Daniel@0 44 LEFT: 37,
Daniel@0 45 PAGE_DOWN: 34,
Daniel@0 46 PAGE_UP: 33,
Daniel@0 47 PERIOD: 190,
Daniel@0 48 RIGHT: 39,
Daniel@0 49 SPACE: 32,
Daniel@0 50 TAB: 9,
Daniel@0 51 UP: 38
Daniel@0 52 }
Daniel@0 53 });
Daniel@0 54
Daniel@0 55 // plugins
Daniel@0 56 $.fn.extend({
Daniel@0 57 scrollParent: function() {
Daniel@0 58 var position = this.css( "position" ),
Daniel@0 59 excludeStaticParent = position === "absolute",
Daniel@0 60 scrollParent = this.parents().filter( function() {
Daniel@0 61 var parent = $( this );
Daniel@0 62 if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
Daniel@0 63 return false;
Daniel@0 64 }
Daniel@0 65 return (/(auto|scroll)/).test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
Daniel@0 66 }).eq( 0 );
Daniel@0 67
Daniel@0 68 return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
Daniel@0 69 },
Daniel@0 70
Daniel@0 71 uniqueId: (function() {
Daniel@0 72 var uuid = 0;
Daniel@0 73
Daniel@0 74 return function() {
Daniel@0 75 return this.each(function() {
Daniel@0 76 if ( !this.id ) {
Daniel@0 77 this.id = "ui-id-" + ( ++uuid );
Daniel@0 78 }
Daniel@0 79 });
Daniel@0 80 };
Daniel@0 81 })(),
Daniel@0 82
Daniel@0 83 removeUniqueId: function() {
Daniel@0 84 return this.each(function() {
Daniel@0 85 if ( /^ui-id-\d+$/.test( this.id ) ) {
Daniel@0 86 $( this ).removeAttr( "id" );
Daniel@0 87 }
Daniel@0 88 });
Daniel@0 89 }
Daniel@0 90 });
Daniel@0 91
Daniel@0 92 // selectors
Daniel@0 93 function focusable( element, isTabIndexNotNaN ) {
Daniel@0 94 var map, mapName, img,
Daniel@0 95 nodeName = element.nodeName.toLowerCase();
Daniel@0 96 if ( "area" === nodeName ) {
Daniel@0 97 map = element.parentNode;
Daniel@0 98 mapName = map.name;
Daniel@0 99 if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
Daniel@0 100 return false;
Daniel@0 101 }
Daniel@0 102 img = $( "img[usemap=#" + mapName + "]" )[0];
Daniel@0 103 return !!img && visible( img );
Daniel@0 104 }
Daniel@0 105 return ( /input|select|textarea|button|object/.test( nodeName ) ?
Daniel@0 106 !element.disabled :
Daniel@0 107 "a" === nodeName ?
Daniel@0 108 element.href || isTabIndexNotNaN :
Daniel@0 109 isTabIndexNotNaN) &&
Daniel@0 110 // the element and all of its ancestors must be visible
Daniel@0 111 visible( element );
Daniel@0 112 }
Daniel@0 113
Daniel@0 114 function visible( element ) {
Daniel@0 115 return $.expr.filters.visible( element ) &&
Daniel@0 116 !$( element ).parents().addBack().filter(function() {
Daniel@0 117 return $.css( this, "visibility" ) === "hidden";
Daniel@0 118 }).length;
Daniel@0 119 }
Daniel@0 120
Daniel@0 121 $.extend( $.expr[ ":" ], {
Daniel@0 122 data: $.expr.createPseudo ?
Daniel@0 123 $.expr.createPseudo(function( dataName ) {
Daniel@0 124 return function( elem ) {
Daniel@0 125 return !!$.data( elem, dataName );
Daniel@0 126 };
Daniel@0 127 }) :
Daniel@0 128 // support: jQuery <1.8
Daniel@0 129 function( elem, i, match ) {
Daniel@0 130 return !!$.data( elem, match[ 3 ] );
Daniel@0 131 },
Daniel@0 132
Daniel@0 133 focusable: function( element ) {
Daniel@0 134 return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
Daniel@0 135 },
Daniel@0 136
Daniel@0 137 tabbable: function( element ) {
Daniel@0 138 var tabIndex = $.attr( element, "tabindex" ),
Daniel@0 139 isTabIndexNaN = isNaN( tabIndex );
Daniel@0 140 return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
Daniel@0 141 }
Daniel@0 142 });
Daniel@0 143
Daniel@0 144 // support: jQuery <1.8
Daniel@0 145 if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
Daniel@0 146 $.each( [ "Width", "Height" ], function( i, name ) {
Daniel@0 147 var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
Daniel@0 148 type = name.toLowerCase(),
Daniel@0 149 orig = {
Daniel@0 150 innerWidth: $.fn.innerWidth,
Daniel@0 151 innerHeight: $.fn.innerHeight,
Daniel@0 152 outerWidth: $.fn.outerWidth,
Daniel@0 153 outerHeight: $.fn.outerHeight
Daniel@0 154 };
Daniel@0 155
Daniel@0 156 function reduce( elem, size, border, margin ) {
Daniel@0 157 $.each( side, function() {
Daniel@0 158 size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
Daniel@0 159 if ( border ) {
Daniel@0 160 size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
Daniel@0 161 }
Daniel@0 162 if ( margin ) {
Daniel@0 163 size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
Daniel@0 164 }
Daniel@0 165 });
Daniel@0 166 return size;
Daniel@0 167 }
Daniel@0 168
Daniel@0 169 $.fn[ "inner" + name ] = function( size ) {
Daniel@0 170 if ( size === undefined ) {
Daniel@0 171 return orig[ "inner" + name ].call( this );
Daniel@0 172 }
Daniel@0 173
Daniel@0 174 return this.each(function() {
Daniel@0 175 $( this ).css( type, reduce( this, size ) + "px" );
Daniel@0 176 });
Daniel@0 177 };
Daniel@0 178
Daniel@0 179 $.fn[ "outer" + name] = function( size, margin ) {
Daniel@0 180 if ( typeof size !== "number" ) {
Daniel@0 181 return orig[ "outer" + name ].call( this, size );
Daniel@0 182 }
Daniel@0 183
Daniel@0 184 return this.each(function() {
Daniel@0 185 $( this).css( type, reduce( this, size, true, margin ) + "px" );
Daniel@0 186 });
Daniel@0 187 };
Daniel@0 188 });
Daniel@0 189 }
Daniel@0 190
Daniel@0 191 // support: jQuery <1.8
Daniel@0 192 if ( !$.fn.addBack ) {
Daniel@0 193 $.fn.addBack = function( selector ) {
Daniel@0 194 return this.add( selector == null ?
Daniel@0 195 this.prevObject : this.prevObject.filter( selector )
Daniel@0 196 );
Daniel@0 197 };
Daniel@0 198 }
Daniel@0 199
Daniel@0 200 // support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
Daniel@0 201 if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
Daniel@0 202 $.fn.removeData = (function( removeData ) {
Daniel@0 203 return function( key ) {
Daniel@0 204 if ( arguments.length ) {
Daniel@0 205 return removeData.call( this, $.camelCase( key ) );
Daniel@0 206 } else {
Daniel@0 207 return removeData.call( this );
Daniel@0 208 }
Daniel@0 209 };
Daniel@0 210 })( $.fn.removeData );
Daniel@0 211 }
Daniel@0 212
Daniel@0 213 // deprecated
Daniel@0 214 $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
Daniel@0 215
Daniel@0 216 $.fn.extend({
Daniel@0 217 focus: (function( orig ) {
Daniel@0 218 return function( delay, fn ) {
Daniel@0 219 return typeof delay === "number" ?
Daniel@0 220 this.each(function() {
Daniel@0 221 var elem = this;
Daniel@0 222 setTimeout(function() {
Daniel@0 223 $( elem ).focus();
Daniel@0 224 if ( fn ) {
Daniel@0 225 fn.call( elem );
Daniel@0 226 }
Daniel@0 227 }, delay );
Daniel@0 228 }) :
Daniel@0 229 orig.apply( this, arguments );
Daniel@0 230 };
Daniel@0 231 })( $.fn.focus ),
Daniel@0 232
Daniel@0 233 disableSelection: (function() {
Daniel@0 234 var eventType = "onselectstart" in document.createElement( "div" ) ?
Daniel@0 235 "selectstart" :
Daniel@0 236 "mousedown";
Daniel@0 237
Daniel@0 238 return function() {
Daniel@0 239 return this.bind( eventType + ".ui-disableSelection", function( event ) {
Daniel@0 240 event.preventDefault();
Daniel@0 241 });
Daniel@0 242 };
Daniel@0 243 })(),
Daniel@0 244
Daniel@0 245 enableSelection: function() {
Daniel@0 246 return this.unbind( ".ui-disableSelection" );
Daniel@0 247 },
Daniel@0 248
Daniel@0 249 zIndex: function( zIndex ) {
Daniel@0 250 if ( zIndex !== undefined ) {
Daniel@0 251 return this.css( "zIndex", zIndex );
Daniel@0 252 }
Daniel@0 253
Daniel@0 254 if ( this.length ) {
Daniel@0 255 var elem = $( this[ 0 ] ), position, value;
Daniel@0 256 while ( elem.length && elem[ 0 ] !== document ) {
Daniel@0 257 // Ignore z-index if position is set to a value where z-index is ignored by the browser
Daniel@0 258 // This makes behavior of this function consistent across browsers
Daniel@0 259 // WebKit always returns auto if the element is positioned
Daniel@0 260 position = elem.css( "position" );
Daniel@0 261 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
Daniel@0 262 // IE returns 0 when zIndex is not specified
Daniel@0 263 // other browsers return a string
Daniel@0 264 // we ignore the case of nested elements with an explicit value of 0
Daniel@0 265 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
Daniel@0 266 value = parseInt( elem.css( "zIndex" ), 10 );
Daniel@0 267 if ( !isNaN( value ) && value !== 0 ) {
Daniel@0 268 return value;
Daniel@0 269 }
Daniel@0 270 }
Daniel@0 271 elem = elem.parent();
Daniel@0 272 }
Daniel@0 273 }
Daniel@0 274
Daniel@0 275 return 0;
Daniel@0 276 }
Daniel@0 277 });
Daniel@0 278
Daniel@0 279 // $.ui.plugin is deprecated. Use $.widget() extensions instead.
Daniel@0 280 $.ui.plugin = {
Daniel@0 281 add: function( module, option, set ) {
Daniel@0 282 var i,
Daniel@0 283 proto = $.ui[ module ].prototype;
Daniel@0 284 for ( i in set ) {
Daniel@0 285 proto.plugins[ i ] = proto.plugins[ i ] || [];
Daniel@0 286 proto.plugins[ i ].push( [ option, set[ i ] ] );
Daniel@0 287 }
Daniel@0 288 },
Daniel@0 289 call: function( instance, name, args, allowDisconnected ) {
Daniel@0 290 var i,
Daniel@0 291 set = instance.plugins[ name ];
Daniel@0 292
Daniel@0 293 if ( !set ) {
Daniel@0 294 return;
Daniel@0 295 }
Daniel@0 296
Daniel@0 297 if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
Daniel@0 298 return;
Daniel@0 299 }
Daniel@0 300
Daniel@0 301 for ( i = 0; i < set.length; i++ ) {
Daniel@0 302 if ( instance.options[ set[ i ][ 0 ] ] ) {
Daniel@0 303 set[ i ][ 1 ].apply( instance.element, args );
Daniel@0 304 }
Daniel@0 305 }
Daniel@0 306 }
Daniel@0 307 };
Daniel@0 308
Daniel@0 309
Daniel@0 310 /*!
Daniel@0 311 * jQuery UI Widget 1.11.0
Daniel@0 312 * http://jqueryui.com
Daniel@0 313 *
Daniel@0 314 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 315 * Released under the MIT license.
Daniel@0 316 * http://jquery.org/license
Daniel@0 317 *
Daniel@0 318 * http://api.jqueryui.com/jQuery.widget/
Daniel@0 319 */
Daniel@0 320
Daniel@0 321
Daniel@0 322 var widget_uuid = 0,
Daniel@0 323 widget_slice = Array.prototype.slice;
Daniel@0 324
Daniel@0 325 $.cleanData = (function( orig ) {
Daniel@0 326 return function( elems ) {
Daniel@0 327 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {
Daniel@0 328 try {
Daniel@0 329 $( elem ).triggerHandler( "remove" );
Daniel@0 330 // http://bugs.jquery.com/ticket/8235
Daniel@0 331 } catch( e ) {}
Daniel@0 332 }
Daniel@0 333 orig( elems );
Daniel@0 334 };
Daniel@0 335 })( $.cleanData );
Daniel@0 336
Daniel@0 337 $.widget = function( name, base, prototype ) {
Daniel@0 338 var fullName, existingConstructor, constructor, basePrototype,
Daniel@0 339 // proxiedPrototype allows the provided prototype to remain unmodified
Daniel@0 340 // so that it can be used as a mixin for multiple widgets (#8876)
Daniel@0 341 proxiedPrototype = {},
Daniel@0 342 namespace = name.split( "." )[ 0 ];
Daniel@0 343
Daniel@0 344 name = name.split( "." )[ 1 ];
Daniel@0 345 fullName = namespace + "-" + name;
Daniel@0 346
Daniel@0 347 if ( !prototype ) {
Daniel@0 348 prototype = base;
Daniel@0 349 base = $.Widget;
Daniel@0 350 }
Daniel@0 351
Daniel@0 352 // create selector for plugin
Daniel@0 353 $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
Daniel@0 354 return !!$.data( elem, fullName );
Daniel@0 355 };
Daniel@0 356
Daniel@0 357 $[ namespace ] = $[ namespace ] || {};
Daniel@0 358 existingConstructor = $[ namespace ][ name ];
Daniel@0 359 constructor = $[ namespace ][ name ] = function( options, element ) {
Daniel@0 360 // allow instantiation without "new" keyword
Daniel@0 361 if ( !this._createWidget ) {
Daniel@0 362 return new constructor( options, element );
Daniel@0 363 }
Daniel@0 364
Daniel@0 365 // allow instantiation without initializing for simple inheritance
Daniel@0 366 // must use "new" keyword (the code above always passes args)
Daniel@0 367 if ( arguments.length ) {
Daniel@0 368 this._createWidget( options, element );
Daniel@0 369 }
Daniel@0 370 };
Daniel@0 371 // extend with the existing constructor to carry over any static properties
Daniel@0 372 $.extend( constructor, existingConstructor, {
Daniel@0 373 version: prototype.version,
Daniel@0 374 // copy the object used to create the prototype in case we need to
Daniel@0 375 // redefine the widget later
Daniel@0 376 _proto: $.extend( {}, prototype ),
Daniel@0 377 // track widgets that inherit from this widget in case this widget is
Daniel@0 378 // redefined after a widget inherits from it
Daniel@0 379 _childConstructors: []
Daniel@0 380 });
Daniel@0 381
Daniel@0 382 basePrototype = new base();
Daniel@0 383 // we need to make the options hash a property directly on the new instance
Daniel@0 384 // otherwise we'll modify the options hash on the prototype that we're
Daniel@0 385 // inheriting from
Daniel@0 386 basePrototype.options = $.widget.extend( {}, basePrototype.options );
Daniel@0 387 $.each( prototype, function( prop, value ) {
Daniel@0 388 if ( !$.isFunction( value ) ) {
Daniel@0 389 proxiedPrototype[ prop ] = value;
Daniel@0 390 return;
Daniel@0 391 }
Daniel@0 392 proxiedPrototype[ prop ] = (function() {
Daniel@0 393 var _super = function() {
Daniel@0 394 return base.prototype[ prop ].apply( this, arguments );
Daniel@0 395 },
Daniel@0 396 _superApply = function( args ) {
Daniel@0 397 return base.prototype[ prop ].apply( this, args );
Daniel@0 398 };
Daniel@0 399 return function() {
Daniel@0 400 var __super = this._super,
Daniel@0 401 __superApply = this._superApply,
Daniel@0 402 returnValue;
Daniel@0 403
Daniel@0 404 this._super = _super;
Daniel@0 405 this._superApply = _superApply;
Daniel@0 406
Daniel@0 407 returnValue = value.apply( this, arguments );
Daniel@0 408
Daniel@0 409 this._super = __super;
Daniel@0 410 this._superApply = __superApply;
Daniel@0 411
Daniel@0 412 return returnValue;
Daniel@0 413 };
Daniel@0 414 })();
Daniel@0 415 });
Daniel@0 416 constructor.prototype = $.widget.extend( basePrototype, {
Daniel@0 417 // TODO: remove support for widgetEventPrefix
Daniel@0 418 // always use the name + a colon as the prefix, e.g., draggable:start
Daniel@0 419 // don't prefix for widgets that aren't DOM-based
Daniel@0 420 widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
Daniel@0 421 }, proxiedPrototype, {
Daniel@0 422 constructor: constructor,
Daniel@0 423 namespace: namespace,
Daniel@0 424 widgetName: name,
Daniel@0 425 widgetFullName: fullName
Daniel@0 426 });
Daniel@0 427
Daniel@0 428 // If this widget is being redefined then we need to find all widgets that
Daniel@0 429 // are inheriting from it and redefine all of them so that they inherit from
Daniel@0 430 // the new version of this widget. We're essentially trying to replace one
Daniel@0 431 // level in the prototype chain.
Daniel@0 432 if ( existingConstructor ) {
Daniel@0 433 $.each( existingConstructor._childConstructors, function( i, child ) {
Daniel@0 434 var childPrototype = child.prototype;
Daniel@0 435
Daniel@0 436 // redefine the child widget using the same prototype that was
Daniel@0 437 // originally used, but inherit from the new version of the base
Daniel@0 438 $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
Daniel@0 439 });
Daniel@0 440 // remove the list of existing child constructors from the old constructor
Daniel@0 441 // so the old child constructors can be garbage collected
Daniel@0 442 delete existingConstructor._childConstructors;
Daniel@0 443 } else {
Daniel@0 444 base._childConstructors.push( constructor );
Daniel@0 445 }
Daniel@0 446
Daniel@0 447 $.widget.bridge( name, constructor );
Daniel@0 448
Daniel@0 449 return constructor;
Daniel@0 450 };
Daniel@0 451
Daniel@0 452 $.widget.extend = function( target ) {
Daniel@0 453 var input = widget_slice.call( arguments, 1 ),
Daniel@0 454 inputIndex = 0,
Daniel@0 455 inputLength = input.length,
Daniel@0 456 key,
Daniel@0 457 value;
Daniel@0 458 for ( ; inputIndex < inputLength; inputIndex++ ) {
Daniel@0 459 for ( key in input[ inputIndex ] ) {
Daniel@0 460 value = input[ inputIndex ][ key ];
Daniel@0 461 if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
Daniel@0 462 // Clone objects
Daniel@0 463 if ( $.isPlainObject( value ) ) {
Daniel@0 464 target[ key ] = $.isPlainObject( target[ key ] ) ?
Daniel@0 465 $.widget.extend( {}, target[ key ], value ) :
Daniel@0 466 // Don't extend strings, arrays, etc. with objects
Daniel@0 467 $.widget.extend( {}, value );
Daniel@0 468 // Copy everything else by reference
Daniel@0 469 } else {
Daniel@0 470 target[ key ] = value;
Daniel@0 471 }
Daniel@0 472 }
Daniel@0 473 }
Daniel@0 474 }
Daniel@0 475 return target;
Daniel@0 476 };
Daniel@0 477
Daniel@0 478 $.widget.bridge = function( name, object ) {
Daniel@0 479 var fullName = object.prototype.widgetFullName || name;
Daniel@0 480 $.fn[ name ] = function( options ) {
Daniel@0 481 var isMethodCall = typeof options === "string",
Daniel@0 482 args = widget_slice.call( arguments, 1 ),
Daniel@0 483 returnValue = this;
Daniel@0 484
Daniel@0 485 // allow multiple hashes to be passed on init
Daniel@0 486 options = !isMethodCall && args.length ?
Daniel@0 487 $.widget.extend.apply( null, [ options ].concat(args) ) :
Daniel@0 488 options;
Daniel@0 489
Daniel@0 490 if ( isMethodCall ) {
Daniel@0 491 this.each(function() {
Daniel@0 492 var methodValue,
Daniel@0 493 instance = $.data( this, fullName );
Daniel@0 494 if ( options === "instance" ) {
Daniel@0 495 returnValue = instance;
Daniel@0 496 return false;
Daniel@0 497 }
Daniel@0 498 if ( !instance ) {
Daniel@0 499 return $.error( "cannot call methods on " + name + " prior to initialization; " +
Daniel@0 500 "attempted to call method '" + options + "'" );
Daniel@0 501 }
Daniel@0 502 if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
Daniel@0 503 return $.error( "no such method '" + options + "' for " + name + " widget instance" );
Daniel@0 504 }
Daniel@0 505 methodValue = instance[ options ].apply( instance, args );
Daniel@0 506 if ( methodValue !== instance && methodValue !== undefined ) {
Daniel@0 507 returnValue = methodValue && methodValue.jquery ?
Daniel@0 508 returnValue.pushStack( methodValue.get() ) :
Daniel@0 509 methodValue;
Daniel@0 510 return false;
Daniel@0 511 }
Daniel@0 512 });
Daniel@0 513 } else {
Daniel@0 514 this.each(function() {
Daniel@0 515 var instance = $.data( this, fullName );
Daniel@0 516 if ( instance ) {
Daniel@0 517 instance.option( options || {} );
Daniel@0 518 if ( instance._init ) {
Daniel@0 519 instance._init();
Daniel@0 520 }
Daniel@0 521 } else {
Daniel@0 522 $.data( this, fullName, new object( options, this ) );
Daniel@0 523 }
Daniel@0 524 });
Daniel@0 525 }
Daniel@0 526
Daniel@0 527 return returnValue;
Daniel@0 528 };
Daniel@0 529 };
Daniel@0 530
Daniel@0 531 $.Widget = function( /* options, element */ ) {};
Daniel@0 532 $.Widget._childConstructors = [];
Daniel@0 533
Daniel@0 534 $.Widget.prototype = {
Daniel@0 535 widgetName: "widget",
Daniel@0 536 widgetEventPrefix: "",
Daniel@0 537 defaultElement: "<div>",
Daniel@0 538 options: {
Daniel@0 539 disabled: false,
Daniel@0 540
Daniel@0 541 // callbacks
Daniel@0 542 create: null
Daniel@0 543 },
Daniel@0 544 _createWidget: function( options, element ) {
Daniel@0 545 element = $( element || this.defaultElement || this )[ 0 ];
Daniel@0 546 this.element = $( element );
Daniel@0 547 this.uuid = widget_uuid++;
Daniel@0 548 this.eventNamespace = "." + this.widgetName + this.uuid;
Daniel@0 549 this.options = $.widget.extend( {},
Daniel@0 550 this.options,
Daniel@0 551 this._getCreateOptions(),
Daniel@0 552 options );
Daniel@0 553
Daniel@0 554 this.bindings = $();
Daniel@0 555 this.hoverable = $();
Daniel@0 556 this.focusable = $();
Daniel@0 557
Daniel@0 558 if ( element !== this ) {
Daniel@0 559 $.data( element, this.widgetFullName, this );
Daniel@0 560 this._on( true, this.element, {
Daniel@0 561 remove: function( event ) {
Daniel@0 562 if ( event.target === element ) {
Daniel@0 563 this.destroy();
Daniel@0 564 }
Daniel@0 565 }
Daniel@0 566 });
Daniel@0 567 this.document = $( element.style ?
Daniel@0 568 // element within the document
Daniel@0 569 element.ownerDocument :
Daniel@0 570 // element is window or document
Daniel@0 571 element.document || element );
Daniel@0 572 this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
Daniel@0 573 }
Daniel@0 574
Daniel@0 575 this._create();
Daniel@0 576 this._trigger( "create", null, this._getCreateEventData() );
Daniel@0 577 this._init();
Daniel@0 578 },
Daniel@0 579 _getCreateOptions: $.noop,
Daniel@0 580 _getCreateEventData: $.noop,
Daniel@0 581 _create: $.noop,
Daniel@0 582 _init: $.noop,
Daniel@0 583
Daniel@0 584 destroy: function() {
Daniel@0 585 this._destroy();
Daniel@0 586 // we can probably remove the unbind calls in 2.0
Daniel@0 587 // all event bindings should go through this._on()
Daniel@0 588 this.element
Daniel@0 589 .unbind( this.eventNamespace )
Daniel@0 590 .removeData( this.widgetFullName )
Daniel@0 591 // support: jquery <1.6.3
Daniel@0 592 // http://bugs.jquery.com/ticket/9413
Daniel@0 593 .removeData( $.camelCase( this.widgetFullName ) );
Daniel@0 594 this.widget()
Daniel@0 595 .unbind( this.eventNamespace )
Daniel@0 596 .removeAttr( "aria-disabled" )
Daniel@0 597 .removeClass(
Daniel@0 598 this.widgetFullName + "-disabled " +
Daniel@0 599 "ui-state-disabled" );
Daniel@0 600
Daniel@0 601 // clean up events and states
Daniel@0 602 this.bindings.unbind( this.eventNamespace );
Daniel@0 603 this.hoverable.removeClass( "ui-state-hover" );
Daniel@0 604 this.focusable.removeClass( "ui-state-focus" );
Daniel@0 605 },
Daniel@0 606 _destroy: $.noop,
Daniel@0 607
Daniel@0 608 widget: function() {
Daniel@0 609 return this.element;
Daniel@0 610 },
Daniel@0 611
Daniel@0 612 option: function( key, value ) {
Daniel@0 613 var options = key,
Daniel@0 614 parts,
Daniel@0 615 curOption,
Daniel@0 616 i;
Daniel@0 617
Daniel@0 618 if ( arguments.length === 0 ) {
Daniel@0 619 // don't return a reference to the internal hash
Daniel@0 620 return $.widget.extend( {}, this.options );
Daniel@0 621 }
Daniel@0 622
Daniel@0 623 if ( typeof key === "string" ) {
Daniel@0 624 // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
Daniel@0 625 options = {};
Daniel@0 626 parts = key.split( "." );
Daniel@0 627 key = parts.shift();
Daniel@0 628 if ( parts.length ) {
Daniel@0 629 curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
Daniel@0 630 for ( i = 0; i < parts.length - 1; i++ ) {
Daniel@0 631 curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
Daniel@0 632 curOption = curOption[ parts[ i ] ];
Daniel@0 633 }
Daniel@0 634 key = parts.pop();
Daniel@0 635 if ( arguments.length === 1 ) {
Daniel@0 636 return curOption[ key ] === undefined ? null : curOption[ key ];
Daniel@0 637 }
Daniel@0 638 curOption[ key ] = value;
Daniel@0 639 } else {
Daniel@0 640 if ( arguments.length === 1 ) {
Daniel@0 641 return this.options[ key ] === undefined ? null : this.options[ key ];
Daniel@0 642 }
Daniel@0 643 options[ key ] = value;
Daniel@0 644 }
Daniel@0 645 }
Daniel@0 646
Daniel@0 647 this._setOptions( options );
Daniel@0 648
Daniel@0 649 return this;
Daniel@0 650 },
Daniel@0 651 _setOptions: function( options ) {
Daniel@0 652 var key;
Daniel@0 653
Daniel@0 654 for ( key in options ) {
Daniel@0 655 this._setOption( key, options[ key ] );
Daniel@0 656 }
Daniel@0 657
Daniel@0 658 return this;
Daniel@0 659 },
Daniel@0 660 _setOption: function( key, value ) {
Daniel@0 661 this.options[ key ] = value;
Daniel@0 662
Daniel@0 663 if ( key === "disabled" ) {
Daniel@0 664 this.widget()
Daniel@0 665 .toggleClass( this.widgetFullName + "-disabled", !!value );
Daniel@0 666
Daniel@0 667 // If the widget is becoming disabled, then nothing is interactive
Daniel@0 668 if ( value ) {
Daniel@0 669 this.hoverable.removeClass( "ui-state-hover" );
Daniel@0 670 this.focusable.removeClass( "ui-state-focus" );
Daniel@0 671 }
Daniel@0 672 }
Daniel@0 673
Daniel@0 674 return this;
Daniel@0 675 },
Daniel@0 676
Daniel@0 677 enable: function() {
Daniel@0 678 return this._setOptions({ disabled: false });
Daniel@0 679 },
Daniel@0 680 disable: function() {
Daniel@0 681 return this._setOptions({ disabled: true });
Daniel@0 682 },
Daniel@0 683
Daniel@0 684 _on: function( suppressDisabledCheck, element, handlers ) {
Daniel@0 685 var delegateElement,
Daniel@0 686 instance = this;
Daniel@0 687
Daniel@0 688 // no suppressDisabledCheck flag, shuffle arguments
Daniel@0 689 if ( typeof suppressDisabledCheck !== "boolean" ) {
Daniel@0 690 handlers = element;
Daniel@0 691 element = suppressDisabledCheck;
Daniel@0 692 suppressDisabledCheck = false;
Daniel@0 693 }
Daniel@0 694
Daniel@0 695 // no element argument, shuffle and use this.element
Daniel@0 696 if ( !handlers ) {
Daniel@0 697 handlers = element;
Daniel@0 698 element = this.element;
Daniel@0 699 delegateElement = this.widget();
Daniel@0 700 } else {
Daniel@0 701 element = delegateElement = $( element );
Daniel@0 702 this.bindings = this.bindings.add( element );
Daniel@0 703 }
Daniel@0 704
Daniel@0 705 $.each( handlers, function( event, handler ) {
Daniel@0 706 function handlerProxy() {
Daniel@0 707 // allow widgets to customize the disabled handling
Daniel@0 708 // - disabled as an array instead of boolean
Daniel@0 709 // - disabled class as method for disabling individual parts
Daniel@0 710 if ( !suppressDisabledCheck &&
Daniel@0 711 ( instance.options.disabled === true ||
Daniel@0 712 $( this ).hasClass( "ui-state-disabled" ) ) ) {
Daniel@0 713 return;
Daniel@0 714 }
Daniel@0 715 return ( typeof handler === "string" ? instance[ handler ] : handler )
Daniel@0 716 .apply( instance, arguments );
Daniel@0 717 }
Daniel@0 718
Daniel@0 719 // copy the guid so direct unbinding works
Daniel@0 720 if ( typeof handler !== "string" ) {
Daniel@0 721 handlerProxy.guid = handler.guid =
Daniel@0 722 handler.guid || handlerProxy.guid || $.guid++;
Daniel@0 723 }
Daniel@0 724
Daniel@0 725 var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
Daniel@0 726 eventName = match[1] + instance.eventNamespace,
Daniel@0 727 selector = match[2];
Daniel@0 728 if ( selector ) {
Daniel@0 729 delegateElement.delegate( selector, eventName, handlerProxy );
Daniel@0 730 } else {
Daniel@0 731 element.bind( eventName, handlerProxy );
Daniel@0 732 }
Daniel@0 733 });
Daniel@0 734 },
Daniel@0 735
Daniel@0 736 _off: function( element, eventName ) {
Daniel@0 737 eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace;
Daniel@0 738 element.unbind( eventName ).undelegate( eventName );
Daniel@0 739 },
Daniel@0 740
Daniel@0 741 _delay: function( handler, delay ) {
Daniel@0 742 function handlerProxy() {
Daniel@0 743 return ( typeof handler === "string" ? instance[ handler ] : handler )
Daniel@0 744 .apply( instance, arguments );
Daniel@0 745 }
Daniel@0 746 var instance = this;
Daniel@0 747 return setTimeout( handlerProxy, delay || 0 );
Daniel@0 748 },
Daniel@0 749
Daniel@0 750 _hoverable: function( element ) {
Daniel@0 751 this.hoverable = this.hoverable.add( element );
Daniel@0 752 this._on( element, {
Daniel@0 753 mouseenter: function( event ) {
Daniel@0 754 $( event.currentTarget ).addClass( "ui-state-hover" );
Daniel@0 755 },
Daniel@0 756 mouseleave: function( event ) {
Daniel@0 757 $( event.currentTarget ).removeClass( "ui-state-hover" );
Daniel@0 758 }
Daniel@0 759 });
Daniel@0 760 },
Daniel@0 761
Daniel@0 762 _focusable: function( element ) {
Daniel@0 763 this.focusable = this.focusable.add( element );
Daniel@0 764 this._on( element, {
Daniel@0 765 focusin: function( event ) {
Daniel@0 766 $( event.currentTarget ).addClass( "ui-state-focus" );
Daniel@0 767 },
Daniel@0 768 focusout: function( event ) {
Daniel@0 769 $( event.currentTarget ).removeClass( "ui-state-focus" );
Daniel@0 770 }
Daniel@0 771 });
Daniel@0 772 },
Daniel@0 773
Daniel@0 774 _trigger: function( type, event, data ) {
Daniel@0 775 var prop, orig,
Daniel@0 776 callback = this.options[ type ];
Daniel@0 777
Daniel@0 778 data = data || {};
Daniel@0 779 event = $.Event( event );
Daniel@0 780 event.type = ( type === this.widgetEventPrefix ?
Daniel@0 781 type :
Daniel@0 782 this.widgetEventPrefix + type ).toLowerCase();
Daniel@0 783 // the original event may come from any element
Daniel@0 784 // so we need to reset the target on the new event
Daniel@0 785 event.target = this.element[ 0 ];
Daniel@0 786
Daniel@0 787 // copy original event properties over to the new event
Daniel@0 788 orig = event.originalEvent;
Daniel@0 789 if ( orig ) {
Daniel@0 790 for ( prop in orig ) {
Daniel@0 791 if ( !( prop in event ) ) {
Daniel@0 792 event[ prop ] = orig[ prop ];
Daniel@0 793 }
Daniel@0 794 }
Daniel@0 795 }
Daniel@0 796
Daniel@0 797 this.element.trigger( event, data );
Daniel@0 798 return !( $.isFunction( callback ) &&
Daniel@0 799 callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
Daniel@0 800 event.isDefaultPrevented() );
Daniel@0 801 }
Daniel@0 802 };
Daniel@0 803
Daniel@0 804 $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
Daniel@0 805 $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
Daniel@0 806 if ( typeof options === "string" ) {
Daniel@0 807 options = { effect: options };
Daniel@0 808 }
Daniel@0 809 var hasOptions,
Daniel@0 810 effectName = !options ?
Daniel@0 811 method :
Daniel@0 812 options === true || typeof options === "number" ?
Daniel@0 813 defaultEffect :
Daniel@0 814 options.effect || defaultEffect;
Daniel@0 815 options = options || {};
Daniel@0 816 if ( typeof options === "number" ) {
Daniel@0 817 options = { duration: options };
Daniel@0 818 }
Daniel@0 819 hasOptions = !$.isEmptyObject( options );
Daniel@0 820 options.complete = callback;
Daniel@0 821 if ( options.delay ) {
Daniel@0 822 element.delay( options.delay );
Daniel@0 823 }
Daniel@0 824 if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
Daniel@0 825 element[ method ]( options );
Daniel@0 826 } else if ( effectName !== method && element[ effectName ] ) {
Daniel@0 827 element[ effectName ]( options.duration, options.easing, callback );
Daniel@0 828 } else {
Daniel@0 829 element.queue(function( next ) {
Daniel@0 830 $( this )[ method ]();
Daniel@0 831 if ( callback ) {
Daniel@0 832 callback.call( element[ 0 ] );
Daniel@0 833 }
Daniel@0 834 next();
Daniel@0 835 });
Daniel@0 836 }
Daniel@0 837 };
Daniel@0 838 });
Daniel@0 839
Daniel@0 840 var widget = $.widget;
Daniel@0 841
Daniel@0 842
Daniel@0 843 /*!
Daniel@0 844 * jQuery UI Mouse 1.11.0
Daniel@0 845 * http://jqueryui.com
Daniel@0 846 *
Daniel@0 847 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 848 * Released under the MIT license.
Daniel@0 849 * http://jquery.org/license
Daniel@0 850 *
Daniel@0 851 * http://api.jqueryui.com/mouse/
Daniel@0 852 */
Daniel@0 853
Daniel@0 854
Daniel@0 855 var mouseHandled = false;
Daniel@0 856 $( document ).mouseup( function() {
Daniel@0 857 mouseHandled = false;
Daniel@0 858 });
Daniel@0 859
Daniel@0 860 var mouse = $.widget("ui.mouse", {
Daniel@0 861 version: "1.11.0",
Daniel@0 862 options: {
Daniel@0 863 cancel: "input,textarea,button,select,option",
Daniel@0 864 distance: 1,
Daniel@0 865 delay: 0
Daniel@0 866 },
Daniel@0 867 _mouseInit: function() {
Daniel@0 868 var that = this;
Daniel@0 869
Daniel@0 870 this.element
Daniel@0 871 .bind("mousedown." + this.widgetName, function(event) {
Daniel@0 872 return that._mouseDown(event);
Daniel@0 873 })
Daniel@0 874 .bind("click." + this.widgetName, function(event) {
Daniel@0 875 if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
Daniel@0 876 $.removeData(event.target, that.widgetName + ".preventClickEvent");
Daniel@0 877 event.stopImmediatePropagation();
Daniel@0 878 return false;
Daniel@0 879 }
Daniel@0 880 });
Daniel@0 881
Daniel@0 882 this.started = false;
Daniel@0 883 },
Daniel@0 884
Daniel@0 885 // TODO: make sure destroying one instance of mouse doesn't mess with
Daniel@0 886 // other instances of mouse
Daniel@0 887 _mouseDestroy: function() {
Daniel@0 888 this.element.unbind("." + this.widgetName);
Daniel@0 889 if ( this._mouseMoveDelegate ) {
Daniel@0 890 this.document
Daniel@0 891 .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
Daniel@0 892 .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
Daniel@0 893 }
Daniel@0 894 },
Daniel@0 895
Daniel@0 896 _mouseDown: function(event) {
Daniel@0 897 // don't let more than one widget handle mouseStart
Daniel@0 898 if ( mouseHandled ) {
Daniel@0 899 return;
Daniel@0 900 }
Daniel@0 901
Daniel@0 902 // we may have missed mouseup (out of window)
Daniel@0 903 (this._mouseStarted && this._mouseUp(event));
Daniel@0 904
Daniel@0 905 this._mouseDownEvent = event;
Daniel@0 906
Daniel@0 907 var that = this,
Daniel@0 908 btnIsLeft = (event.which === 1),
Daniel@0 909 // event.target.nodeName works around a bug in IE 8 with
Daniel@0 910 // disabled inputs (#7620)
Daniel@0 911 elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
Daniel@0 912 if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
Daniel@0 913 return true;
Daniel@0 914 }
Daniel@0 915
Daniel@0 916 this.mouseDelayMet = !this.options.delay;
Daniel@0 917 if (!this.mouseDelayMet) {
Daniel@0 918 this._mouseDelayTimer = setTimeout(function() {
Daniel@0 919 that.mouseDelayMet = true;
Daniel@0 920 }, this.options.delay);
Daniel@0 921 }
Daniel@0 922
Daniel@0 923 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
Daniel@0 924 this._mouseStarted = (this._mouseStart(event) !== false);
Daniel@0 925 if (!this._mouseStarted) {
Daniel@0 926 event.preventDefault();
Daniel@0 927 return true;
Daniel@0 928 }
Daniel@0 929 }
Daniel@0 930
Daniel@0 931 // Click event may never have fired (Gecko & Opera)
Daniel@0 932 if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
Daniel@0 933 $.removeData(event.target, this.widgetName + ".preventClickEvent");
Daniel@0 934 }
Daniel@0 935
Daniel@0 936 // these delegates are required to keep context
Daniel@0 937 this._mouseMoveDelegate = function(event) {
Daniel@0 938 return that._mouseMove(event);
Daniel@0 939 };
Daniel@0 940 this._mouseUpDelegate = function(event) {
Daniel@0 941 return that._mouseUp(event);
Daniel@0 942 };
Daniel@0 943
Daniel@0 944 this.document
Daniel@0 945 .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
Daniel@0 946 .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
Daniel@0 947
Daniel@0 948 event.preventDefault();
Daniel@0 949
Daniel@0 950 mouseHandled = true;
Daniel@0 951 return true;
Daniel@0 952 },
Daniel@0 953
Daniel@0 954 _mouseMove: function(event) {
Daniel@0 955 // IE mouseup check - mouseup happened when mouse was out of window
Daniel@0 956 if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
Daniel@0 957 return this._mouseUp(event);
Daniel@0 958
Daniel@0 959 // Iframe mouseup check - mouseup occurred in another document
Daniel@0 960 } else if ( !event.which ) {
Daniel@0 961 return this._mouseUp( event );
Daniel@0 962 }
Daniel@0 963
Daniel@0 964 if (this._mouseStarted) {
Daniel@0 965 this._mouseDrag(event);
Daniel@0 966 return event.preventDefault();
Daniel@0 967 }
Daniel@0 968
Daniel@0 969 if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
Daniel@0 970 this._mouseStarted =
Daniel@0 971 (this._mouseStart(this._mouseDownEvent, event) !== false);
Daniel@0 972 (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
Daniel@0 973 }
Daniel@0 974
Daniel@0 975 return !this._mouseStarted;
Daniel@0 976 },
Daniel@0 977
Daniel@0 978 _mouseUp: function(event) {
Daniel@0 979 this.document
Daniel@0 980 .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
Daniel@0 981 .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
Daniel@0 982
Daniel@0 983 if (this._mouseStarted) {
Daniel@0 984 this._mouseStarted = false;
Daniel@0 985
Daniel@0 986 if (event.target === this._mouseDownEvent.target) {
Daniel@0 987 $.data(event.target, this.widgetName + ".preventClickEvent", true);
Daniel@0 988 }
Daniel@0 989
Daniel@0 990 this._mouseStop(event);
Daniel@0 991 }
Daniel@0 992
Daniel@0 993 mouseHandled = false;
Daniel@0 994 return false;
Daniel@0 995 },
Daniel@0 996
Daniel@0 997 _mouseDistanceMet: function(event) {
Daniel@0 998 return (Math.max(
Daniel@0 999 Math.abs(this._mouseDownEvent.pageX - event.pageX),
Daniel@0 1000 Math.abs(this._mouseDownEvent.pageY - event.pageY)
Daniel@0 1001 ) >= this.options.distance
Daniel@0 1002 );
Daniel@0 1003 },
Daniel@0 1004
Daniel@0 1005 _mouseDelayMet: function(/* event */) {
Daniel@0 1006 return this.mouseDelayMet;
Daniel@0 1007 },
Daniel@0 1008
Daniel@0 1009 // These are placeholder methods, to be overriden by extending plugin
Daniel@0 1010 _mouseStart: function(/* event */) {},
Daniel@0 1011 _mouseDrag: function(/* event */) {},
Daniel@0 1012 _mouseStop: function(/* event */) {},
Daniel@0 1013 _mouseCapture: function(/* event */) { return true; }
Daniel@0 1014 });
Daniel@0 1015
Daniel@0 1016
Daniel@0 1017 /*!
Daniel@0 1018 * jQuery UI Position 1.11.0
Daniel@0 1019 * http://jqueryui.com
Daniel@0 1020 *
Daniel@0 1021 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 1022 * Released under the MIT license.
Daniel@0 1023 * http://jquery.org/license
Daniel@0 1024 *
Daniel@0 1025 * http://api.jqueryui.com/position/
Daniel@0 1026 */
Daniel@0 1027
Daniel@0 1028 (function() {
Daniel@0 1029
Daniel@0 1030 $.ui = $.ui || {};
Daniel@0 1031
Daniel@0 1032 var cachedScrollbarWidth, supportsOffsetFractions,
Daniel@0 1033 max = Math.max,
Daniel@0 1034 abs = Math.abs,
Daniel@0 1035 round = Math.round,
Daniel@0 1036 rhorizontal = /left|center|right/,
Daniel@0 1037 rvertical = /top|center|bottom/,
Daniel@0 1038 roffset = /[\+\-]\d+(\.[\d]+)?%?/,
Daniel@0 1039 rposition = /^\w+/,
Daniel@0 1040 rpercent = /%$/,
Daniel@0 1041 _position = $.fn.position;
Daniel@0 1042
Daniel@0 1043 function getOffsets( offsets, width, height ) {
Daniel@0 1044 return [
Daniel@0 1045 parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
Daniel@0 1046 parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
Daniel@0 1047 ];
Daniel@0 1048 }
Daniel@0 1049
Daniel@0 1050 function parseCss( element, property ) {
Daniel@0 1051 return parseInt( $.css( element, property ), 10 ) || 0;
Daniel@0 1052 }
Daniel@0 1053
Daniel@0 1054 function getDimensions( elem ) {
Daniel@0 1055 var raw = elem[0];
Daniel@0 1056 if ( raw.nodeType === 9 ) {
Daniel@0 1057 return {
Daniel@0 1058 width: elem.width(),
Daniel@0 1059 height: elem.height(),
Daniel@0 1060 offset: { top: 0, left: 0 }
Daniel@0 1061 };
Daniel@0 1062 }
Daniel@0 1063 if ( $.isWindow( raw ) ) {
Daniel@0 1064 return {
Daniel@0 1065 width: elem.width(),
Daniel@0 1066 height: elem.height(),
Daniel@0 1067 offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
Daniel@0 1068 };
Daniel@0 1069 }
Daniel@0 1070 if ( raw.preventDefault ) {
Daniel@0 1071 return {
Daniel@0 1072 width: 0,
Daniel@0 1073 height: 0,
Daniel@0 1074 offset: { top: raw.pageY, left: raw.pageX }
Daniel@0 1075 };
Daniel@0 1076 }
Daniel@0 1077 return {
Daniel@0 1078 width: elem.outerWidth(),
Daniel@0 1079 height: elem.outerHeight(),
Daniel@0 1080 offset: elem.offset()
Daniel@0 1081 };
Daniel@0 1082 }
Daniel@0 1083
Daniel@0 1084 $.position = {
Daniel@0 1085 scrollbarWidth: function() {
Daniel@0 1086 if ( cachedScrollbarWidth !== undefined ) {
Daniel@0 1087 return cachedScrollbarWidth;
Daniel@0 1088 }
Daniel@0 1089 var w1, w2,
Daniel@0 1090 div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
Daniel@0 1091 innerDiv = div.children()[0];
Daniel@0 1092
Daniel@0 1093 $( "body" ).append( div );
Daniel@0 1094 w1 = innerDiv.offsetWidth;
Daniel@0 1095 div.css( "overflow", "scroll" );
Daniel@0 1096
Daniel@0 1097 w2 = innerDiv.offsetWidth;
Daniel@0 1098
Daniel@0 1099 if ( w1 === w2 ) {
Daniel@0 1100 w2 = div[0].clientWidth;
Daniel@0 1101 }
Daniel@0 1102
Daniel@0 1103 div.remove();
Daniel@0 1104
Daniel@0 1105 return (cachedScrollbarWidth = w1 - w2);
Daniel@0 1106 },
Daniel@0 1107 getScrollInfo: function( within ) {
Daniel@0 1108 var overflowX = within.isWindow || within.isDocument ? "" :
Daniel@0 1109 within.element.css( "overflow-x" ),
Daniel@0 1110 overflowY = within.isWindow || within.isDocument ? "" :
Daniel@0 1111 within.element.css( "overflow-y" ),
Daniel@0 1112 hasOverflowX = overflowX === "scroll" ||
Daniel@0 1113 ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
Daniel@0 1114 hasOverflowY = overflowY === "scroll" ||
Daniel@0 1115 ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
Daniel@0 1116 return {
Daniel@0 1117 width: hasOverflowY ? $.position.scrollbarWidth() : 0,
Daniel@0 1118 height: hasOverflowX ? $.position.scrollbarWidth() : 0
Daniel@0 1119 };
Daniel@0 1120 },
Daniel@0 1121 getWithinInfo: function( element ) {
Daniel@0 1122 var withinElement = $( element || window ),
Daniel@0 1123 isWindow = $.isWindow( withinElement[0] ),
Daniel@0 1124 isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
Daniel@0 1125 return {
Daniel@0 1126 element: withinElement,
Daniel@0 1127 isWindow: isWindow,
Daniel@0 1128 isDocument: isDocument,
Daniel@0 1129 offset: withinElement.offset() || { left: 0, top: 0 },
Daniel@0 1130 scrollLeft: withinElement.scrollLeft(),
Daniel@0 1131 scrollTop: withinElement.scrollTop(),
Daniel@0 1132 width: isWindow ? withinElement.width() : withinElement.outerWidth(),
Daniel@0 1133 height: isWindow ? withinElement.height() : withinElement.outerHeight()
Daniel@0 1134 };
Daniel@0 1135 }
Daniel@0 1136 };
Daniel@0 1137
Daniel@0 1138 $.fn.position = function( options ) {
Daniel@0 1139 if ( !options || !options.of ) {
Daniel@0 1140 return _position.apply( this, arguments );
Daniel@0 1141 }
Daniel@0 1142
Daniel@0 1143 // make a copy, we don't want to modify arguments
Daniel@0 1144 options = $.extend( {}, options );
Daniel@0 1145
Daniel@0 1146 var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
Daniel@0 1147 target = $( options.of ),
Daniel@0 1148 within = $.position.getWithinInfo( options.within ),
Daniel@0 1149 scrollInfo = $.position.getScrollInfo( within ),
Daniel@0 1150 collision = ( options.collision || "flip" ).split( " " ),
Daniel@0 1151 offsets = {};
Daniel@0 1152
Daniel@0 1153 dimensions = getDimensions( target );
Daniel@0 1154 if ( target[0].preventDefault ) {
Daniel@0 1155 // force left top to allow flipping
Daniel@0 1156 options.at = "left top";
Daniel@0 1157 }
Daniel@0 1158 targetWidth = dimensions.width;
Daniel@0 1159 targetHeight = dimensions.height;
Daniel@0 1160 targetOffset = dimensions.offset;
Daniel@0 1161 // clone to reuse original targetOffset later
Daniel@0 1162 basePosition = $.extend( {}, targetOffset );
Daniel@0 1163
Daniel@0 1164 // force my and at to have valid horizontal and vertical positions
Daniel@0 1165 // if a value is missing or invalid, it will be converted to center
Daniel@0 1166 $.each( [ "my", "at" ], function() {
Daniel@0 1167 var pos = ( options[ this ] || "" ).split( " " ),
Daniel@0 1168 horizontalOffset,
Daniel@0 1169 verticalOffset;
Daniel@0 1170
Daniel@0 1171 if ( pos.length === 1) {
Daniel@0 1172 pos = rhorizontal.test( pos[ 0 ] ) ?
Daniel@0 1173 pos.concat( [ "center" ] ) :
Daniel@0 1174 rvertical.test( pos[ 0 ] ) ?
Daniel@0 1175 [ "center" ].concat( pos ) :
Daniel@0 1176 [ "center", "center" ];
Daniel@0 1177 }
Daniel@0 1178 pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
Daniel@0 1179 pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
Daniel@0 1180
Daniel@0 1181 // calculate offsets
Daniel@0 1182 horizontalOffset = roffset.exec( pos[ 0 ] );
Daniel@0 1183 verticalOffset = roffset.exec( pos[ 1 ] );
Daniel@0 1184 offsets[ this ] = [
Daniel@0 1185 horizontalOffset ? horizontalOffset[ 0 ] : 0,
Daniel@0 1186 verticalOffset ? verticalOffset[ 0 ] : 0
Daniel@0 1187 ];
Daniel@0 1188
Daniel@0 1189 // reduce to just the positions without the offsets
Daniel@0 1190 options[ this ] = [
Daniel@0 1191 rposition.exec( pos[ 0 ] )[ 0 ],
Daniel@0 1192 rposition.exec( pos[ 1 ] )[ 0 ]
Daniel@0 1193 ];
Daniel@0 1194 });
Daniel@0 1195
Daniel@0 1196 // normalize collision option
Daniel@0 1197 if ( collision.length === 1 ) {
Daniel@0 1198 collision[ 1 ] = collision[ 0 ];
Daniel@0 1199 }
Daniel@0 1200
Daniel@0 1201 if ( options.at[ 0 ] === "right" ) {
Daniel@0 1202 basePosition.left += targetWidth;
Daniel@0 1203 } else if ( options.at[ 0 ] === "center" ) {
Daniel@0 1204 basePosition.left += targetWidth / 2;
Daniel@0 1205 }
Daniel@0 1206
Daniel@0 1207 if ( options.at[ 1 ] === "bottom" ) {
Daniel@0 1208 basePosition.top += targetHeight;
Daniel@0 1209 } else if ( options.at[ 1 ] === "center" ) {
Daniel@0 1210 basePosition.top += targetHeight / 2;
Daniel@0 1211 }
Daniel@0 1212
Daniel@0 1213 atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
Daniel@0 1214 basePosition.left += atOffset[ 0 ];
Daniel@0 1215 basePosition.top += atOffset[ 1 ];
Daniel@0 1216
Daniel@0 1217 return this.each(function() {
Daniel@0 1218 var collisionPosition, using,
Daniel@0 1219 elem = $( this ),
Daniel@0 1220 elemWidth = elem.outerWidth(),
Daniel@0 1221 elemHeight = elem.outerHeight(),
Daniel@0 1222 marginLeft = parseCss( this, "marginLeft" ),
Daniel@0 1223 marginTop = parseCss( this, "marginTop" ),
Daniel@0 1224 collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
Daniel@0 1225 collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
Daniel@0 1226 position = $.extend( {}, basePosition ),
Daniel@0 1227 myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
Daniel@0 1228
Daniel@0 1229 if ( options.my[ 0 ] === "right" ) {
Daniel@0 1230 position.left -= elemWidth;
Daniel@0 1231 } else if ( options.my[ 0 ] === "center" ) {
Daniel@0 1232 position.left -= elemWidth / 2;
Daniel@0 1233 }
Daniel@0 1234
Daniel@0 1235 if ( options.my[ 1 ] === "bottom" ) {
Daniel@0 1236 position.top -= elemHeight;
Daniel@0 1237 } else if ( options.my[ 1 ] === "center" ) {
Daniel@0 1238 position.top -= elemHeight / 2;
Daniel@0 1239 }
Daniel@0 1240
Daniel@0 1241 position.left += myOffset[ 0 ];
Daniel@0 1242 position.top += myOffset[ 1 ];
Daniel@0 1243
Daniel@0 1244 // if the browser doesn't support fractions, then round for consistent results
Daniel@0 1245 if ( !supportsOffsetFractions ) {
Daniel@0 1246 position.left = round( position.left );
Daniel@0 1247 position.top = round( position.top );
Daniel@0 1248 }
Daniel@0 1249
Daniel@0 1250 collisionPosition = {
Daniel@0 1251 marginLeft: marginLeft,
Daniel@0 1252 marginTop: marginTop
Daniel@0 1253 };
Daniel@0 1254
Daniel@0 1255 $.each( [ "left", "top" ], function( i, dir ) {
Daniel@0 1256 if ( $.ui.position[ collision[ i ] ] ) {
Daniel@0 1257 $.ui.position[ collision[ i ] ][ dir ]( position, {
Daniel@0 1258 targetWidth: targetWidth,
Daniel@0 1259 targetHeight: targetHeight,
Daniel@0 1260 elemWidth: elemWidth,
Daniel@0 1261 elemHeight: elemHeight,
Daniel@0 1262 collisionPosition: collisionPosition,
Daniel@0 1263 collisionWidth: collisionWidth,
Daniel@0 1264 collisionHeight: collisionHeight,
Daniel@0 1265 offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
Daniel@0 1266 my: options.my,
Daniel@0 1267 at: options.at,
Daniel@0 1268 within: within,
Daniel@0 1269 elem: elem
Daniel@0 1270 });
Daniel@0 1271 }
Daniel@0 1272 });
Daniel@0 1273
Daniel@0 1274 if ( options.using ) {
Daniel@0 1275 // adds feedback as second argument to using callback, if present
Daniel@0 1276 using = function( props ) {
Daniel@0 1277 var left = targetOffset.left - position.left,
Daniel@0 1278 right = left + targetWidth - elemWidth,
Daniel@0 1279 top = targetOffset.top - position.top,
Daniel@0 1280 bottom = top + targetHeight - elemHeight,
Daniel@0 1281 feedback = {
Daniel@0 1282 target: {
Daniel@0 1283 element: target,
Daniel@0 1284 left: targetOffset.left,
Daniel@0 1285 top: targetOffset.top,
Daniel@0 1286 width: targetWidth,
Daniel@0 1287 height: targetHeight
Daniel@0 1288 },
Daniel@0 1289 element: {
Daniel@0 1290 element: elem,
Daniel@0 1291 left: position.left,
Daniel@0 1292 top: position.top,
Daniel@0 1293 width: elemWidth,
Daniel@0 1294 height: elemHeight
Daniel@0 1295 },
Daniel@0 1296 horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
Daniel@0 1297 vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
Daniel@0 1298 };
Daniel@0 1299 if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
Daniel@0 1300 feedback.horizontal = "center";
Daniel@0 1301 }
Daniel@0 1302 if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
Daniel@0 1303 feedback.vertical = "middle";
Daniel@0 1304 }
Daniel@0 1305 if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
Daniel@0 1306 feedback.important = "horizontal";
Daniel@0 1307 } else {
Daniel@0 1308 feedback.important = "vertical";
Daniel@0 1309 }
Daniel@0 1310 options.using.call( this, props, feedback );
Daniel@0 1311 };
Daniel@0 1312 }
Daniel@0 1313
Daniel@0 1314 elem.offset( $.extend( position, { using: using } ) );
Daniel@0 1315 });
Daniel@0 1316 };
Daniel@0 1317
Daniel@0 1318 $.ui.position = {
Daniel@0 1319 fit: {
Daniel@0 1320 left: function( position, data ) {
Daniel@0 1321 var within = data.within,
Daniel@0 1322 withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
Daniel@0 1323 outerWidth = within.width,
Daniel@0 1324 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
Daniel@0 1325 overLeft = withinOffset - collisionPosLeft,
Daniel@0 1326 overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
Daniel@0 1327 newOverRight;
Daniel@0 1328
Daniel@0 1329 // element is wider than within
Daniel@0 1330 if ( data.collisionWidth > outerWidth ) {
Daniel@0 1331 // element is initially over the left side of within
Daniel@0 1332 if ( overLeft > 0 && overRight <= 0 ) {
Daniel@0 1333 newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
Daniel@0 1334 position.left += overLeft - newOverRight;
Daniel@0 1335 // element is initially over right side of within
Daniel@0 1336 } else if ( overRight > 0 && overLeft <= 0 ) {
Daniel@0 1337 position.left = withinOffset;
Daniel@0 1338 // element is initially over both left and right sides of within
Daniel@0 1339 } else {
Daniel@0 1340 if ( overLeft > overRight ) {
Daniel@0 1341 position.left = withinOffset + outerWidth - data.collisionWidth;
Daniel@0 1342 } else {
Daniel@0 1343 position.left = withinOffset;
Daniel@0 1344 }
Daniel@0 1345 }
Daniel@0 1346 // too far left -> align with left edge
Daniel@0 1347 } else if ( overLeft > 0 ) {
Daniel@0 1348 position.left += overLeft;
Daniel@0 1349 // too far right -> align with right edge
Daniel@0 1350 } else if ( overRight > 0 ) {
Daniel@0 1351 position.left -= overRight;
Daniel@0 1352 // adjust based on position and margin
Daniel@0 1353 } else {
Daniel@0 1354 position.left = max( position.left - collisionPosLeft, position.left );
Daniel@0 1355 }
Daniel@0 1356 },
Daniel@0 1357 top: function( position, data ) {
Daniel@0 1358 var within = data.within,
Daniel@0 1359 withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
Daniel@0 1360 outerHeight = data.within.height,
Daniel@0 1361 collisionPosTop = position.top - data.collisionPosition.marginTop,
Daniel@0 1362 overTop = withinOffset - collisionPosTop,
Daniel@0 1363 overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
Daniel@0 1364 newOverBottom;
Daniel@0 1365
Daniel@0 1366 // element is taller than within
Daniel@0 1367 if ( data.collisionHeight > outerHeight ) {
Daniel@0 1368 // element is initially over the top of within
Daniel@0 1369 if ( overTop > 0 && overBottom <= 0 ) {
Daniel@0 1370 newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
Daniel@0 1371 position.top += overTop - newOverBottom;
Daniel@0 1372 // element is initially over bottom of within
Daniel@0 1373 } else if ( overBottom > 0 && overTop <= 0 ) {
Daniel@0 1374 position.top = withinOffset;
Daniel@0 1375 // element is initially over both top and bottom of within
Daniel@0 1376 } else {
Daniel@0 1377 if ( overTop > overBottom ) {
Daniel@0 1378 position.top = withinOffset + outerHeight - data.collisionHeight;
Daniel@0 1379 } else {
Daniel@0 1380 position.top = withinOffset;
Daniel@0 1381 }
Daniel@0 1382 }
Daniel@0 1383 // too far up -> align with top
Daniel@0 1384 } else if ( overTop > 0 ) {
Daniel@0 1385 position.top += overTop;
Daniel@0 1386 // too far down -> align with bottom edge
Daniel@0 1387 } else if ( overBottom > 0 ) {
Daniel@0 1388 position.top -= overBottom;
Daniel@0 1389 // adjust based on position and margin
Daniel@0 1390 } else {
Daniel@0 1391 position.top = max( position.top - collisionPosTop, position.top );
Daniel@0 1392 }
Daniel@0 1393 }
Daniel@0 1394 },
Daniel@0 1395 flip: {
Daniel@0 1396 left: function( position, data ) {
Daniel@0 1397 var within = data.within,
Daniel@0 1398 withinOffset = within.offset.left + within.scrollLeft,
Daniel@0 1399 outerWidth = within.width,
Daniel@0 1400 offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
Daniel@0 1401 collisionPosLeft = position.left - data.collisionPosition.marginLeft,
Daniel@0 1402 overLeft = collisionPosLeft - offsetLeft,
Daniel@0 1403 overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
Daniel@0 1404 myOffset = data.my[ 0 ] === "left" ?
Daniel@0 1405 -data.elemWidth :
Daniel@0 1406 data.my[ 0 ] === "right" ?
Daniel@0 1407 data.elemWidth :
Daniel@0 1408 0,
Daniel@0 1409 atOffset = data.at[ 0 ] === "left" ?
Daniel@0 1410 data.targetWidth :
Daniel@0 1411 data.at[ 0 ] === "right" ?
Daniel@0 1412 -data.targetWidth :
Daniel@0 1413 0,
Daniel@0 1414 offset = -2 * data.offset[ 0 ],
Daniel@0 1415 newOverRight,
Daniel@0 1416 newOverLeft;
Daniel@0 1417
Daniel@0 1418 if ( overLeft < 0 ) {
Daniel@0 1419 newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
Daniel@0 1420 if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
Daniel@0 1421 position.left += myOffset + atOffset + offset;
Daniel@0 1422 }
Daniel@0 1423 } else if ( overRight > 0 ) {
Daniel@0 1424 newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
Daniel@0 1425 if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
Daniel@0 1426 position.left += myOffset + atOffset + offset;
Daniel@0 1427 }
Daniel@0 1428 }
Daniel@0 1429 },
Daniel@0 1430 top: function( position, data ) {
Daniel@0 1431 var within = data.within,
Daniel@0 1432 withinOffset = within.offset.top + within.scrollTop,
Daniel@0 1433 outerHeight = within.height,
Daniel@0 1434 offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
Daniel@0 1435 collisionPosTop = position.top - data.collisionPosition.marginTop,
Daniel@0 1436 overTop = collisionPosTop - offsetTop,
Daniel@0 1437 overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
Daniel@0 1438 top = data.my[ 1 ] === "top",
Daniel@0 1439 myOffset = top ?
Daniel@0 1440 -data.elemHeight :
Daniel@0 1441 data.my[ 1 ] === "bottom" ?
Daniel@0 1442 data.elemHeight :
Daniel@0 1443 0,
Daniel@0 1444 atOffset = data.at[ 1 ] === "top" ?
Daniel@0 1445 data.targetHeight :
Daniel@0 1446 data.at[ 1 ] === "bottom" ?
Daniel@0 1447 -data.targetHeight :
Daniel@0 1448 0,
Daniel@0 1449 offset = -2 * data.offset[ 1 ],
Daniel@0 1450 newOverTop,
Daniel@0 1451 newOverBottom;
Daniel@0 1452 if ( overTop < 0 ) {
Daniel@0 1453 newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
Daniel@0 1454 if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
Daniel@0 1455 position.top += myOffset + atOffset + offset;
Daniel@0 1456 }
Daniel@0 1457 } else if ( overBottom > 0 ) {
Daniel@0 1458 newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
Daniel@0 1459 if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
Daniel@0 1460 position.top += myOffset + atOffset + offset;
Daniel@0 1461 }
Daniel@0 1462 }
Daniel@0 1463 }
Daniel@0 1464 },
Daniel@0 1465 flipfit: {
Daniel@0 1466 left: function() {
Daniel@0 1467 $.ui.position.flip.left.apply( this, arguments );
Daniel@0 1468 $.ui.position.fit.left.apply( this, arguments );
Daniel@0 1469 },
Daniel@0 1470 top: function() {
Daniel@0 1471 $.ui.position.flip.top.apply( this, arguments );
Daniel@0 1472 $.ui.position.fit.top.apply( this, arguments );
Daniel@0 1473 }
Daniel@0 1474 }
Daniel@0 1475 };
Daniel@0 1476
Daniel@0 1477 // fraction support test
Daniel@0 1478 (function() {
Daniel@0 1479 var testElement, testElementParent, testElementStyle, offsetLeft, i,
Daniel@0 1480 body = document.getElementsByTagName( "body" )[ 0 ],
Daniel@0 1481 div = document.createElement( "div" );
Daniel@0 1482
Daniel@0 1483 //Create a "fake body" for testing based on method used in jQuery.support
Daniel@0 1484 testElement = document.createElement( body ? "div" : "body" );
Daniel@0 1485 testElementStyle = {
Daniel@0 1486 visibility: "hidden",
Daniel@0 1487 width: 0,
Daniel@0 1488 height: 0,
Daniel@0 1489 border: 0,
Daniel@0 1490 margin: 0,
Daniel@0 1491 background: "none"
Daniel@0 1492 };
Daniel@0 1493 if ( body ) {
Daniel@0 1494 $.extend( testElementStyle, {
Daniel@0 1495 position: "absolute",
Daniel@0 1496 left: "-1000px",
Daniel@0 1497 top: "-1000px"
Daniel@0 1498 });
Daniel@0 1499 }
Daniel@0 1500 for ( i in testElementStyle ) {
Daniel@0 1501 testElement.style[ i ] = testElementStyle[ i ];
Daniel@0 1502 }
Daniel@0 1503 testElement.appendChild( div );
Daniel@0 1504 testElementParent = body || document.documentElement;
Daniel@0 1505 testElementParent.insertBefore( testElement, testElementParent.firstChild );
Daniel@0 1506
Daniel@0 1507 div.style.cssText = "position: absolute; left: 10.7432222px;";
Daniel@0 1508
Daniel@0 1509 offsetLeft = $( div ).offset().left;
Daniel@0 1510 supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
Daniel@0 1511
Daniel@0 1512 testElement.innerHTML = "";
Daniel@0 1513 testElementParent.removeChild( testElement );
Daniel@0 1514 })();
Daniel@0 1515
Daniel@0 1516 })();
Daniel@0 1517
Daniel@0 1518 var position = $.ui.position;
Daniel@0 1519
Daniel@0 1520
Daniel@0 1521 /*!
Daniel@0 1522 * jQuery UI Accordion 1.11.0
Daniel@0 1523 * http://jqueryui.com
Daniel@0 1524 *
Daniel@0 1525 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 1526 * Released under the MIT license.
Daniel@0 1527 * http://jquery.org/license
Daniel@0 1528 *
Daniel@0 1529 * http://api.jqueryui.com/accordion/
Daniel@0 1530 */
Daniel@0 1531
Daniel@0 1532
Daniel@0 1533 var accordion = $.widget( "ui.accordion", {
Daniel@0 1534 version: "1.11.0",
Daniel@0 1535 options: {
Daniel@0 1536 active: 0,
Daniel@0 1537 animate: {},
Daniel@0 1538 collapsible: false,
Daniel@0 1539 event: "click",
Daniel@0 1540 header: "> li > :first-child,> :not(li):even",
Daniel@0 1541 heightStyle: "auto",
Daniel@0 1542 icons: {
Daniel@0 1543 activeHeader: "ui-icon-triangle-1-s",
Daniel@0 1544 header: "ui-icon-triangle-1-e"
Daniel@0 1545 },
Daniel@0 1546
Daniel@0 1547 // callbacks
Daniel@0 1548 activate: null,
Daniel@0 1549 beforeActivate: null
Daniel@0 1550 },
Daniel@0 1551
Daniel@0 1552 hideProps: {
Daniel@0 1553 borderTopWidth: "hide",
Daniel@0 1554 borderBottomWidth: "hide",
Daniel@0 1555 paddingTop: "hide",
Daniel@0 1556 paddingBottom: "hide",
Daniel@0 1557 height: "hide"
Daniel@0 1558 },
Daniel@0 1559
Daniel@0 1560 showProps: {
Daniel@0 1561 borderTopWidth: "show",
Daniel@0 1562 borderBottomWidth: "show",
Daniel@0 1563 paddingTop: "show",
Daniel@0 1564 paddingBottom: "show",
Daniel@0 1565 height: "show"
Daniel@0 1566 },
Daniel@0 1567
Daniel@0 1568 _create: function() {
Daniel@0 1569 var options = this.options;
Daniel@0 1570 this.prevShow = this.prevHide = $();
Daniel@0 1571 this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
Daniel@0 1572 // ARIA
Daniel@0 1573 .attr( "role", "tablist" );
Daniel@0 1574
Daniel@0 1575 // don't allow collapsible: false and active: false / null
Daniel@0 1576 if ( !options.collapsible && (options.active === false || options.active == null) ) {
Daniel@0 1577 options.active = 0;
Daniel@0 1578 }
Daniel@0 1579
Daniel@0 1580 this._processPanels();
Daniel@0 1581 // handle negative values
Daniel@0 1582 if ( options.active < 0 ) {
Daniel@0 1583 options.active += this.headers.length;
Daniel@0 1584 }
Daniel@0 1585 this._refresh();
Daniel@0 1586 },
Daniel@0 1587
Daniel@0 1588 _getCreateEventData: function() {
Daniel@0 1589 return {
Daniel@0 1590 header: this.active,
Daniel@0 1591 panel: !this.active.length ? $() : this.active.next()
Daniel@0 1592 };
Daniel@0 1593 },
Daniel@0 1594
Daniel@0 1595 _createIcons: function() {
Daniel@0 1596 var icons = this.options.icons;
Daniel@0 1597 if ( icons ) {
Daniel@0 1598 $( "<span>" )
Daniel@0 1599 .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
Daniel@0 1600 .prependTo( this.headers );
Daniel@0 1601 this.active.children( ".ui-accordion-header-icon" )
Daniel@0 1602 .removeClass( icons.header )
Daniel@0 1603 .addClass( icons.activeHeader );
Daniel@0 1604 this.headers.addClass( "ui-accordion-icons" );
Daniel@0 1605 }
Daniel@0 1606 },
Daniel@0 1607
Daniel@0 1608 _destroyIcons: function() {
Daniel@0 1609 this.headers
Daniel@0 1610 .removeClass( "ui-accordion-icons" )
Daniel@0 1611 .children( ".ui-accordion-header-icon" )
Daniel@0 1612 .remove();
Daniel@0 1613 },
Daniel@0 1614
Daniel@0 1615 _destroy: function() {
Daniel@0 1616 var contents;
Daniel@0 1617
Daniel@0 1618 // clean up main element
Daniel@0 1619 this.element
Daniel@0 1620 .removeClass( "ui-accordion ui-widget ui-helper-reset" )
Daniel@0 1621 .removeAttr( "role" );
Daniel@0 1622
Daniel@0 1623 // clean up headers
Daniel@0 1624 this.headers
Daniel@0 1625 .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
Daniel@0 1626 "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
Daniel@0 1627 .removeAttr( "role" )
Daniel@0 1628 .removeAttr( "aria-expanded" )
Daniel@0 1629 .removeAttr( "aria-selected" )
Daniel@0 1630 .removeAttr( "aria-controls" )
Daniel@0 1631 .removeAttr( "tabIndex" )
Daniel@0 1632 .removeUniqueId();
Daniel@0 1633
Daniel@0 1634 this._destroyIcons();
Daniel@0 1635
Daniel@0 1636 // clean up content panels
Daniel@0 1637 contents = this.headers.next()
Daniel@0 1638 .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
Daniel@0 1639 "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
Daniel@0 1640 .css( "display", "" )
Daniel@0 1641 .removeAttr( "role" )
Daniel@0 1642 .removeAttr( "aria-hidden" )
Daniel@0 1643 .removeAttr( "aria-labelledby" )
Daniel@0 1644 .removeUniqueId();
Daniel@0 1645
Daniel@0 1646 if ( this.options.heightStyle !== "content" ) {
Daniel@0 1647 contents.css( "height", "" );
Daniel@0 1648 }
Daniel@0 1649 },
Daniel@0 1650
Daniel@0 1651 _setOption: function( key, value ) {
Daniel@0 1652 if ( key === "active" ) {
Daniel@0 1653 // _activate() will handle invalid values and update this.options
Daniel@0 1654 this._activate( value );
Daniel@0 1655 return;
Daniel@0 1656 }
Daniel@0 1657
Daniel@0 1658 if ( key === "event" ) {
Daniel@0 1659 if ( this.options.event ) {
Daniel@0 1660 this._off( this.headers, this.options.event );
Daniel@0 1661 }
Daniel@0 1662 this._setupEvents( value );
Daniel@0 1663 }
Daniel@0 1664
Daniel@0 1665 this._super( key, value );
Daniel@0 1666
Daniel@0 1667 // setting collapsible: false while collapsed; open first panel
Daniel@0 1668 if ( key === "collapsible" && !value && this.options.active === false ) {
Daniel@0 1669 this._activate( 0 );
Daniel@0 1670 }
Daniel@0 1671
Daniel@0 1672 if ( key === "icons" ) {
Daniel@0 1673 this._destroyIcons();
Daniel@0 1674 if ( value ) {
Daniel@0 1675 this._createIcons();
Daniel@0 1676 }
Daniel@0 1677 }
Daniel@0 1678
Daniel@0 1679 // #5332 - opacity doesn't cascade to positioned elements in IE
Daniel@0 1680 // so we need to add the disabled class to the headers and panels
Daniel@0 1681 if ( key === "disabled" ) {
Daniel@0 1682 this.element
Daniel@0 1683 .toggleClass( "ui-state-disabled", !!value )
Daniel@0 1684 .attr( "aria-disabled", value );
Daniel@0 1685 this.headers.add( this.headers.next() )
Daniel@0 1686 .toggleClass( "ui-state-disabled", !!value );
Daniel@0 1687 }
Daniel@0 1688 },
Daniel@0 1689
Daniel@0 1690 _keydown: function( event ) {
Daniel@0 1691 if ( event.altKey || event.ctrlKey ) {
Daniel@0 1692 return;
Daniel@0 1693 }
Daniel@0 1694
Daniel@0 1695 var keyCode = $.ui.keyCode,
Daniel@0 1696 length = this.headers.length,
Daniel@0 1697 currentIndex = this.headers.index( event.target ),
Daniel@0 1698 toFocus = false;
Daniel@0 1699
Daniel@0 1700 switch ( event.keyCode ) {
Daniel@0 1701 case keyCode.RIGHT:
Daniel@0 1702 case keyCode.DOWN:
Daniel@0 1703 toFocus = this.headers[ ( currentIndex + 1 ) % length ];
Daniel@0 1704 break;
Daniel@0 1705 case keyCode.LEFT:
Daniel@0 1706 case keyCode.UP:
Daniel@0 1707 toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
Daniel@0 1708 break;
Daniel@0 1709 case keyCode.SPACE:
Daniel@0 1710 case keyCode.ENTER:
Daniel@0 1711 this._eventHandler( event );
Daniel@0 1712 break;
Daniel@0 1713 case keyCode.HOME:
Daniel@0 1714 toFocus = this.headers[ 0 ];
Daniel@0 1715 break;
Daniel@0 1716 case keyCode.END:
Daniel@0 1717 toFocus = this.headers[ length - 1 ];
Daniel@0 1718 break;
Daniel@0 1719 }
Daniel@0 1720
Daniel@0 1721 if ( toFocus ) {
Daniel@0 1722 $( event.target ).attr( "tabIndex", -1 );
Daniel@0 1723 $( toFocus ).attr( "tabIndex", 0 );
Daniel@0 1724 toFocus.focus();
Daniel@0 1725 event.preventDefault();
Daniel@0 1726 }
Daniel@0 1727 },
Daniel@0 1728
Daniel@0 1729 _panelKeyDown: function( event ) {
Daniel@0 1730 if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
Daniel@0 1731 $( event.currentTarget ).prev().focus();
Daniel@0 1732 }
Daniel@0 1733 },
Daniel@0 1734
Daniel@0 1735 refresh: function() {
Daniel@0 1736 var options = this.options;
Daniel@0 1737 this._processPanels();
Daniel@0 1738
Daniel@0 1739 // was collapsed or no panel
Daniel@0 1740 if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
Daniel@0 1741 options.active = false;
Daniel@0 1742 this.active = $();
Daniel@0 1743 // active false only when collapsible is true
Daniel@0 1744 } else if ( options.active === false ) {
Daniel@0 1745 this._activate( 0 );
Daniel@0 1746 // was active, but active panel is gone
Daniel@0 1747 } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
Daniel@0 1748 // all remaining panel are disabled
Daniel@0 1749 if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
Daniel@0 1750 options.active = false;
Daniel@0 1751 this.active = $();
Daniel@0 1752 // activate previous panel
Daniel@0 1753 } else {
Daniel@0 1754 this._activate( Math.max( 0, options.active - 1 ) );
Daniel@0 1755 }
Daniel@0 1756 // was active, active panel still exists
Daniel@0 1757 } else {
Daniel@0 1758 // make sure active index is correct
Daniel@0 1759 options.active = this.headers.index( this.active );
Daniel@0 1760 }
Daniel@0 1761
Daniel@0 1762 this._destroyIcons();
Daniel@0 1763
Daniel@0 1764 this._refresh();
Daniel@0 1765 },
Daniel@0 1766
Daniel@0 1767 _processPanels: function() {
Daniel@0 1768 this.headers = this.element.find( this.options.header )
Daniel@0 1769 .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
Daniel@0 1770
Daniel@0 1771 this.headers.next()
Daniel@0 1772 .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
Daniel@0 1773 .filter( ":not(.ui-accordion-content-active)" )
Daniel@0 1774 .hide();
Daniel@0 1775 },
Daniel@0 1776
Daniel@0 1777 _refresh: function() {
Daniel@0 1778 var maxHeight,
Daniel@0 1779 options = this.options,
Daniel@0 1780 heightStyle = options.heightStyle,
Daniel@0 1781 parent = this.element.parent();
Daniel@0 1782
Daniel@0 1783 this.active = this._findActive( options.active )
Daniel@0 1784 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
Daniel@0 1785 .removeClass( "ui-corner-all" );
Daniel@0 1786 this.active.next()
Daniel@0 1787 .addClass( "ui-accordion-content-active" )
Daniel@0 1788 .show();
Daniel@0 1789
Daniel@0 1790 this.headers
Daniel@0 1791 .attr( "role", "tab" )
Daniel@0 1792 .each(function() {
Daniel@0 1793 var header = $( this ),
Daniel@0 1794 headerId = header.uniqueId().attr( "id" ),
Daniel@0 1795 panel = header.next(),
Daniel@0 1796 panelId = panel.uniqueId().attr( "id" );
Daniel@0 1797 header.attr( "aria-controls", panelId );
Daniel@0 1798 panel.attr( "aria-labelledby", headerId );
Daniel@0 1799 })
Daniel@0 1800 .next()
Daniel@0 1801 .attr( "role", "tabpanel" );
Daniel@0 1802
Daniel@0 1803 this.headers
Daniel@0 1804 .not( this.active )
Daniel@0 1805 .attr({
Daniel@0 1806 "aria-selected": "false",
Daniel@0 1807 "aria-expanded": "false",
Daniel@0 1808 tabIndex: -1
Daniel@0 1809 })
Daniel@0 1810 .next()
Daniel@0 1811 .attr({
Daniel@0 1812 "aria-hidden": "true"
Daniel@0 1813 })
Daniel@0 1814 .hide();
Daniel@0 1815
Daniel@0 1816 // make sure at least one header is in the tab order
Daniel@0 1817 if ( !this.active.length ) {
Daniel@0 1818 this.headers.eq( 0 ).attr( "tabIndex", 0 );
Daniel@0 1819 } else {
Daniel@0 1820 this.active.attr({
Daniel@0 1821 "aria-selected": "true",
Daniel@0 1822 "aria-expanded": "true",
Daniel@0 1823 tabIndex: 0
Daniel@0 1824 })
Daniel@0 1825 .next()
Daniel@0 1826 .attr({
Daniel@0 1827 "aria-hidden": "false"
Daniel@0 1828 });
Daniel@0 1829 }
Daniel@0 1830
Daniel@0 1831 this._createIcons();
Daniel@0 1832
Daniel@0 1833 this._setupEvents( options.event );
Daniel@0 1834
Daniel@0 1835 if ( heightStyle === "fill" ) {
Daniel@0 1836 maxHeight = parent.height();
Daniel@0 1837 this.element.siblings( ":visible" ).each(function() {
Daniel@0 1838 var elem = $( this ),
Daniel@0 1839 position = elem.css( "position" );
Daniel@0 1840
Daniel@0 1841 if ( position === "absolute" || position === "fixed" ) {
Daniel@0 1842 return;
Daniel@0 1843 }
Daniel@0 1844 maxHeight -= elem.outerHeight( true );
Daniel@0 1845 });
Daniel@0 1846
Daniel@0 1847 this.headers.each(function() {
Daniel@0 1848 maxHeight -= $( this ).outerHeight( true );
Daniel@0 1849 });
Daniel@0 1850
Daniel@0 1851 this.headers.next()
Daniel@0 1852 .each(function() {
Daniel@0 1853 $( this ).height( Math.max( 0, maxHeight -
Daniel@0 1854 $( this ).innerHeight() + $( this ).height() ) );
Daniel@0 1855 })
Daniel@0 1856 .css( "overflow", "auto" );
Daniel@0 1857 } else if ( heightStyle === "auto" ) {
Daniel@0 1858 maxHeight = 0;
Daniel@0 1859 this.headers.next()
Daniel@0 1860 .each(function() {
Daniel@0 1861 maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
Daniel@0 1862 })
Daniel@0 1863 .height( maxHeight );
Daniel@0 1864 }
Daniel@0 1865 },
Daniel@0 1866
Daniel@0 1867 _activate: function( index ) {
Daniel@0 1868 var active = this._findActive( index )[ 0 ];
Daniel@0 1869
Daniel@0 1870 // trying to activate the already active panel
Daniel@0 1871 if ( active === this.active[ 0 ] ) {
Daniel@0 1872 return;
Daniel@0 1873 }
Daniel@0 1874
Daniel@0 1875 // trying to collapse, simulate a click on the currently active header
Daniel@0 1876 active = active || this.active[ 0 ];
Daniel@0 1877
Daniel@0 1878 this._eventHandler({
Daniel@0 1879 target: active,
Daniel@0 1880 currentTarget: active,
Daniel@0 1881 preventDefault: $.noop
Daniel@0 1882 });
Daniel@0 1883 },
Daniel@0 1884
Daniel@0 1885 _findActive: function( selector ) {
Daniel@0 1886 return typeof selector === "number" ? this.headers.eq( selector ) : $();
Daniel@0 1887 },
Daniel@0 1888
Daniel@0 1889 _setupEvents: function( event ) {
Daniel@0 1890 var events = {
Daniel@0 1891 keydown: "_keydown"
Daniel@0 1892 };
Daniel@0 1893 if ( event ) {
Daniel@0 1894 $.each( event.split( " " ), function( index, eventName ) {
Daniel@0 1895 events[ eventName ] = "_eventHandler";
Daniel@0 1896 });
Daniel@0 1897 }
Daniel@0 1898
Daniel@0 1899 this._off( this.headers.add( this.headers.next() ) );
Daniel@0 1900 this._on( this.headers, events );
Daniel@0 1901 this._on( this.headers.next(), { keydown: "_panelKeyDown" });
Daniel@0 1902 this._hoverable( this.headers );
Daniel@0 1903 this._focusable( this.headers );
Daniel@0 1904 },
Daniel@0 1905
Daniel@0 1906 _eventHandler: function( event ) {
Daniel@0 1907 var options = this.options,
Daniel@0 1908 active = this.active,
Daniel@0 1909 clicked = $( event.currentTarget ),
Daniel@0 1910 clickedIsActive = clicked[ 0 ] === active[ 0 ],
Daniel@0 1911 collapsing = clickedIsActive && options.collapsible,
Daniel@0 1912 toShow = collapsing ? $() : clicked.next(),
Daniel@0 1913 toHide = active.next(),
Daniel@0 1914 eventData = {
Daniel@0 1915 oldHeader: active,
Daniel@0 1916 oldPanel: toHide,
Daniel@0 1917 newHeader: collapsing ? $() : clicked,
Daniel@0 1918 newPanel: toShow
Daniel@0 1919 };
Daniel@0 1920
Daniel@0 1921 event.preventDefault();
Daniel@0 1922
Daniel@0 1923 if (
Daniel@0 1924 // click on active header, but not collapsible
Daniel@0 1925 ( clickedIsActive && !options.collapsible ) ||
Daniel@0 1926 // allow canceling activation
Daniel@0 1927 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
Daniel@0 1928 return;
Daniel@0 1929 }
Daniel@0 1930
Daniel@0 1931 options.active = collapsing ? false : this.headers.index( clicked );
Daniel@0 1932
Daniel@0 1933 // when the call to ._toggle() comes after the class changes
Daniel@0 1934 // it causes a very odd bug in IE 8 (see #6720)
Daniel@0 1935 this.active = clickedIsActive ? $() : clicked;
Daniel@0 1936 this._toggle( eventData );
Daniel@0 1937
Daniel@0 1938 // switch classes
Daniel@0 1939 // corner classes on the previously active header stay after the animation
Daniel@0 1940 active.removeClass( "ui-accordion-header-active ui-state-active" );
Daniel@0 1941 if ( options.icons ) {
Daniel@0 1942 active.children( ".ui-accordion-header-icon" )
Daniel@0 1943 .removeClass( options.icons.activeHeader )
Daniel@0 1944 .addClass( options.icons.header );
Daniel@0 1945 }
Daniel@0 1946
Daniel@0 1947 if ( !clickedIsActive ) {
Daniel@0 1948 clicked
Daniel@0 1949 .removeClass( "ui-corner-all" )
Daniel@0 1950 .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
Daniel@0 1951 if ( options.icons ) {
Daniel@0 1952 clicked.children( ".ui-accordion-header-icon" )
Daniel@0 1953 .removeClass( options.icons.header )
Daniel@0 1954 .addClass( options.icons.activeHeader );
Daniel@0 1955 }
Daniel@0 1956
Daniel@0 1957 clicked
Daniel@0 1958 .next()
Daniel@0 1959 .addClass( "ui-accordion-content-active" );
Daniel@0 1960 }
Daniel@0 1961 },
Daniel@0 1962
Daniel@0 1963 _toggle: function( data ) {
Daniel@0 1964 var toShow = data.newPanel,
Daniel@0 1965 toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
Daniel@0 1966
Daniel@0 1967 // handle activating a panel during the animation for another activation
Daniel@0 1968 this.prevShow.add( this.prevHide ).stop( true, true );
Daniel@0 1969 this.prevShow = toShow;
Daniel@0 1970 this.prevHide = toHide;
Daniel@0 1971
Daniel@0 1972 if ( this.options.animate ) {
Daniel@0 1973 this._animate( toShow, toHide, data );
Daniel@0 1974 } else {
Daniel@0 1975 toHide.hide();
Daniel@0 1976 toShow.show();
Daniel@0 1977 this._toggleComplete( data );
Daniel@0 1978 }
Daniel@0 1979
Daniel@0 1980 toHide.attr({
Daniel@0 1981 "aria-hidden": "true"
Daniel@0 1982 });
Daniel@0 1983 toHide.prev().attr( "aria-selected", "false" );
Daniel@0 1984 // if we're switching panels, remove the old header from the tab order
Daniel@0 1985 // if we're opening from collapsed state, remove the previous header from the tab order
Daniel@0 1986 // if we're collapsing, then keep the collapsing header in the tab order
Daniel@0 1987 if ( toShow.length && toHide.length ) {
Daniel@0 1988 toHide.prev().attr({
Daniel@0 1989 "tabIndex": -1,
Daniel@0 1990 "aria-expanded": "false"
Daniel@0 1991 });
Daniel@0 1992 } else if ( toShow.length ) {
Daniel@0 1993 this.headers.filter(function() {
Daniel@0 1994 return $( this ).attr( "tabIndex" ) === 0;
Daniel@0 1995 })
Daniel@0 1996 .attr( "tabIndex", -1 );
Daniel@0 1997 }
Daniel@0 1998
Daniel@0 1999 toShow
Daniel@0 2000 .attr( "aria-hidden", "false" )
Daniel@0 2001 .prev()
Daniel@0 2002 .attr({
Daniel@0 2003 "aria-selected": "true",
Daniel@0 2004 tabIndex: 0,
Daniel@0 2005 "aria-expanded": "true"
Daniel@0 2006 });
Daniel@0 2007 },
Daniel@0 2008
Daniel@0 2009 _animate: function( toShow, toHide, data ) {
Daniel@0 2010 var total, easing, duration,
Daniel@0 2011 that = this,
Daniel@0 2012 adjust = 0,
Daniel@0 2013 down = toShow.length &&
Daniel@0 2014 ( !toHide.length || ( toShow.index() < toHide.index() ) ),
Daniel@0 2015 animate = this.options.animate || {},
Daniel@0 2016 options = down && animate.down || animate,
Daniel@0 2017 complete = function() {
Daniel@0 2018 that._toggleComplete( data );
Daniel@0 2019 };
Daniel@0 2020
Daniel@0 2021 if ( typeof options === "number" ) {
Daniel@0 2022 duration = options;
Daniel@0 2023 }
Daniel@0 2024 if ( typeof options === "string" ) {
Daniel@0 2025 easing = options;
Daniel@0 2026 }
Daniel@0 2027 // fall back from options to animation in case of partial down settings
Daniel@0 2028 easing = easing || options.easing || animate.easing;
Daniel@0 2029 duration = duration || options.duration || animate.duration;
Daniel@0 2030
Daniel@0 2031 if ( !toHide.length ) {
Daniel@0 2032 return toShow.animate( this.showProps, duration, easing, complete );
Daniel@0 2033 }
Daniel@0 2034 if ( !toShow.length ) {
Daniel@0 2035 return toHide.animate( this.hideProps, duration, easing, complete );
Daniel@0 2036 }
Daniel@0 2037
Daniel@0 2038 total = toShow.show().outerHeight();
Daniel@0 2039 toHide.animate( this.hideProps, {
Daniel@0 2040 duration: duration,
Daniel@0 2041 easing: easing,
Daniel@0 2042 step: function( now, fx ) {
Daniel@0 2043 fx.now = Math.round( now );
Daniel@0 2044 }
Daniel@0 2045 });
Daniel@0 2046 toShow
Daniel@0 2047 .hide()
Daniel@0 2048 .animate( this.showProps, {
Daniel@0 2049 duration: duration,
Daniel@0 2050 easing: easing,
Daniel@0 2051 complete: complete,
Daniel@0 2052 step: function( now, fx ) {
Daniel@0 2053 fx.now = Math.round( now );
Daniel@0 2054 if ( fx.prop !== "height" ) {
Daniel@0 2055 adjust += fx.now;
Daniel@0 2056 } else if ( that.options.heightStyle !== "content" ) {
Daniel@0 2057 fx.now = Math.round( total - toHide.outerHeight() - adjust );
Daniel@0 2058 adjust = 0;
Daniel@0 2059 }
Daniel@0 2060 }
Daniel@0 2061 });
Daniel@0 2062 },
Daniel@0 2063
Daniel@0 2064 _toggleComplete: function( data ) {
Daniel@0 2065 var toHide = data.oldPanel;
Daniel@0 2066
Daniel@0 2067 toHide
Daniel@0 2068 .removeClass( "ui-accordion-content-active" )
Daniel@0 2069 .prev()
Daniel@0 2070 .removeClass( "ui-corner-top" )
Daniel@0 2071 .addClass( "ui-corner-all" );
Daniel@0 2072
Daniel@0 2073 // Work around for rendering bug in IE (#5421)
Daniel@0 2074 if ( toHide.length ) {
Daniel@0 2075 toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
Daniel@0 2076 }
Daniel@0 2077 this._trigger( "activate", null, data );
Daniel@0 2078 }
Daniel@0 2079 });
Daniel@0 2080
Daniel@0 2081
Daniel@0 2082 /*!
Daniel@0 2083 * jQuery UI Menu 1.11.0
Daniel@0 2084 * http://jqueryui.com
Daniel@0 2085 *
Daniel@0 2086 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 2087 * Released under the MIT license.
Daniel@0 2088 * http://jquery.org/license
Daniel@0 2089 *
Daniel@0 2090 * http://api.jqueryui.com/menu/
Daniel@0 2091 */
Daniel@0 2092
Daniel@0 2093
Daniel@0 2094 var menu = $.widget( "ui.menu", {
Daniel@0 2095 version: "1.11.0",
Daniel@0 2096 defaultElement: "<ul>",
Daniel@0 2097 delay: 300,
Daniel@0 2098 options: {
Daniel@0 2099 icons: {
Daniel@0 2100 submenu: "ui-icon-carat-1-e"
Daniel@0 2101 },
Daniel@0 2102 items: "> *",
Daniel@0 2103 menus: "ul",
Daniel@0 2104 position: {
Daniel@0 2105 my: "left-1 top",
Daniel@0 2106 at: "right top"
Daniel@0 2107 },
Daniel@0 2108 role: "menu",
Daniel@0 2109
Daniel@0 2110 // callbacks
Daniel@0 2111 blur: null,
Daniel@0 2112 focus: null,
Daniel@0 2113 select: null
Daniel@0 2114 },
Daniel@0 2115
Daniel@0 2116 _create: function() {
Daniel@0 2117 this.activeMenu = this.element;
Daniel@0 2118
Daniel@0 2119 // Flag used to prevent firing of the click handler
Daniel@0 2120 // as the event bubbles up through nested menus
Daniel@0 2121 this.mouseHandled = false;
Daniel@0 2122 this.element
Daniel@0 2123 .uniqueId()
Daniel@0 2124 .addClass( "ui-menu ui-widget ui-widget-content" )
Daniel@0 2125 .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
Daniel@0 2126 .attr({
Daniel@0 2127 role: this.options.role,
Daniel@0 2128 tabIndex: 0
Daniel@0 2129 });
Daniel@0 2130
Daniel@0 2131 if ( this.options.disabled ) {
Daniel@0 2132 this.element
Daniel@0 2133 .addClass( "ui-state-disabled" )
Daniel@0 2134 .attr( "aria-disabled", "true" );
Daniel@0 2135 }
Daniel@0 2136
Daniel@0 2137 this._on({
Daniel@0 2138 // Prevent focus from sticking to links inside menu after clicking
Daniel@0 2139 // them (focus should always stay on UL during navigation).
Daniel@0 2140 "mousedown .ui-menu-item": function( event ) {
Daniel@0 2141 event.preventDefault();
Daniel@0 2142 },
Daniel@0 2143 "click .ui-menu-item": function( event ) {
Daniel@0 2144 var target = $( event.target );
Daniel@0 2145 if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
Daniel@0 2146 this.select( event );
Daniel@0 2147
Daniel@0 2148 // Only set the mouseHandled flag if the event will bubble, see #9469.
Daniel@0 2149 if ( !event.isPropagationStopped() ) {
Daniel@0 2150 this.mouseHandled = true;
Daniel@0 2151 }
Daniel@0 2152
Daniel@0 2153 // Open submenu on click
Daniel@0 2154 if ( target.has( ".ui-menu" ).length ) {
Daniel@0 2155 this.expand( event );
Daniel@0 2156 } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
Daniel@0 2157
Daniel@0 2158 // Redirect focus to the menu
Daniel@0 2159 this.element.trigger( "focus", [ true ] );
Daniel@0 2160
Daniel@0 2161 // If the active item is on the top level, let it stay active.
Daniel@0 2162 // Otherwise, blur the active item since it is no longer visible.
Daniel@0 2163 if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
Daniel@0 2164 clearTimeout( this.timer );
Daniel@0 2165 }
Daniel@0 2166 }
Daniel@0 2167 }
Daniel@0 2168 },
Daniel@0 2169 "mouseenter .ui-menu-item": function( event ) {
Daniel@0 2170 var target = $( event.currentTarget );
Daniel@0 2171 // Remove ui-state-active class from siblings of the newly focused menu item
Daniel@0 2172 // to avoid a jump caused by adjacent elements both having a class with a border
Daniel@0 2173 target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
Daniel@0 2174 this.focus( event, target );
Daniel@0 2175 },
Daniel@0 2176 mouseleave: "collapseAll",
Daniel@0 2177 "mouseleave .ui-menu": "collapseAll",
Daniel@0 2178 focus: function( event, keepActiveItem ) {
Daniel@0 2179 // If there's already an active item, keep it active
Daniel@0 2180 // If not, activate the first item
Daniel@0 2181 var item = this.active || this.element.find( this.options.items ).eq( 0 );
Daniel@0 2182
Daniel@0 2183 if ( !keepActiveItem ) {
Daniel@0 2184 this.focus( event, item );
Daniel@0 2185 }
Daniel@0 2186 },
Daniel@0 2187 blur: function( event ) {
Daniel@0 2188 this._delay(function() {
Daniel@0 2189 if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
Daniel@0 2190 this.collapseAll( event );
Daniel@0 2191 }
Daniel@0 2192 });
Daniel@0 2193 },
Daniel@0 2194 keydown: "_keydown"
Daniel@0 2195 });
Daniel@0 2196
Daniel@0 2197 this.refresh();
Daniel@0 2198
Daniel@0 2199 // Clicks outside of a menu collapse any open menus
Daniel@0 2200 this._on( this.document, {
Daniel@0 2201 click: function( event ) {
Daniel@0 2202 if ( this._closeOnDocumentClick( event ) ) {
Daniel@0 2203 this.collapseAll( event );
Daniel@0 2204 }
Daniel@0 2205
Daniel@0 2206 // Reset the mouseHandled flag
Daniel@0 2207 this.mouseHandled = false;
Daniel@0 2208 }
Daniel@0 2209 });
Daniel@0 2210 },
Daniel@0 2211
Daniel@0 2212 _destroy: function() {
Daniel@0 2213 // Destroy (sub)menus
Daniel@0 2214 this.element
Daniel@0 2215 .removeAttr( "aria-activedescendant" )
Daniel@0 2216 .find( ".ui-menu" ).addBack()
Daniel@0 2217 .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
Daniel@0 2218 .removeAttr( "role" )
Daniel@0 2219 .removeAttr( "tabIndex" )
Daniel@0 2220 .removeAttr( "aria-labelledby" )
Daniel@0 2221 .removeAttr( "aria-expanded" )
Daniel@0 2222 .removeAttr( "aria-hidden" )
Daniel@0 2223 .removeAttr( "aria-disabled" )
Daniel@0 2224 .removeUniqueId()
Daniel@0 2225 .show();
Daniel@0 2226
Daniel@0 2227 // Destroy menu items
Daniel@0 2228 this.element.find( ".ui-menu-item" )
Daniel@0 2229 .removeClass( "ui-menu-item" )
Daniel@0 2230 .removeAttr( "role" )
Daniel@0 2231 .removeAttr( "aria-disabled" )
Daniel@0 2232 .removeUniqueId()
Daniel@0 2233 .removeClass( "ui-state-hover" )
Daniel@0 2234 .removeAttr( "tabIndex" )
Daniel@0 2235 .removeAttr( "role" )
Daniel@0 2236 .removeAttr( "aria-haspopup" )
Daniel@0 2237 .children().each( function() {
Daniel@0 2238 var elem = $( this );
Daniel@0 2239 if ( elem.data( "ui-menu-submenu-carat" ) ) {
Daniel@0 2240 elem.remove();
Daniel@0 2241 }
Daniel@0 2242 });
Daniel@0 2243
Daniel@0 2244 // Destroy menu dividers
Daniel@0 2245 this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
Daniel@0 2246 },
Daniel@0 2247
Daniel@0 2248 _keydown: function( event ) {
Daniel@0 2249 var match, prev, character, skip, regex,
Daniel@0 2250 preventDefault = true;
Daniel@0 2251
Daniel@0 2252 function escape( value ) {
Daniel@0 2253 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
Daniel@0 2254 }
Daniel@0 2255
Daniel@0 2256 switch ( event.keyCode ) {
Daniel@0 2257 case $.ui.keyCode.PAGE_UP:
Daniel@0 2258 this.previousPage( event );
Daniel@0 2259 break;
Daniel@0 2260 case $.ui.keyCode.PAGE_DOWN:
Daniel@0 2261 this.nextPage( event );
Daniel@0 2262 break;
Daniel@0 2263 case $.ui.keyCode.HOME:
Daniel@0 2264 this._move( "first", "first", event );
Daniel@0 2265 break;
Daniel@0 2266 case $.ui.keyCode.END:
Daniel@0 2267 this._move( "last", "last", event );
Daniel@0 2268 break;
Daniel@0 2269 case $.ui.keyCode.UP:
Daniel@0 2270 this.previous( event );
Daniel@0 2271 break;
Daniel@0 2272 case $.ui.keyCode.DOWN:
Daniel@0 2273 this.next( event );
Daniel@0 2274 break;
Daniel@0 2275 case $.ui.keyCode.LEFT:
Daniel@0 2276 this.collapse( event );
Daniel@0 2277 break;
Daniel@0 2278 case $.ui.keyCode.RIGHT:
Daniel@0 2279 if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
Daniel@0 2280 this.expand( event );
Daniel@0 2281 }
Daniel@0 2282 break;
Daniel@0 2283 case $.ui.keyCode.ENTER:
Daniel@0 2284 case $.ui.keyCode.SPACE:
Daniel@0 2285 this._activate( event );
Daniel@0 2286 break;
Daniel@0 2287 case $.ui.keyCode.ESCAPE:
Daniel@0 2288 this.collapse( event );
Daniel@0 2289 break;
Daniel@0 2290 default:
Daniel@0 2291 preventDefault = false;
Daniel@0 2292 prev = this.previousFilter || "";
Daniel@0 2293 character = String.fromCharCode( event.keyCode );
Daniel@0 2294 skip = false;
Daniel@0 2295
Daniel@0 2296 clearTimeout( this.filterTimer );
Daniel@0 2297
Daniel@0 2298 if ( character === prev ) {
Daniel@0 2299 skip = true;
Daniel@0 2300 } else {
Daniel@0 2301 character = prev + character;
Daniel@0 2302 }
Daniel@0 2303
Daniel@0 2304 regex = new RegExp( "^" + escape( character ), "i" );
Daniel@0 2305 match = this.activeMenu.find( this.options.items ).filter(function() {
Daniel@0 2306 return regex.test( $( this ).text() );
Daniel@0 2307 });
Daniel@0 2308 match = skip && match.index( this.active.next() ) !== -1 ?
Daniel@0 2309 this.active.nextAll( ".ui-menu-item" ) :
Daniel@0 2310 match;
Daniel@0 2311
Daniel@0 2312 // If no matches on the current filter, reset to the last character pressed
Daniel@0 2313 // to move down the menu to the first item that starts with that character
Daniel@0 2314 if ( !match.length ) {
Daniel@0 2315 character = String.fromCharCode( event.keyCode );
Daniel@0 2316 regex = new RegExp( "^" + escape( character ), "i" );
Daniel@0 2317 match = this.activeMenu.find( this.options.items ).filter(function() {
Daniel@0 2318 return regex.test( $( this ).text() );
Daniel@0 2319 });
Daniel@0 2320 }
Daniel@0 2321
Daniel@0 2322 if ( match.length ) {
Daniel@0 2323 this.focus( event, match );
Daniel@0 2324 if ( match.length > 1 ) {
Daniel@0 2325 this.previousFilter = character;
Daniel@0 2326 this.filterTimer = this._delay(function() {
Daniel@0 2327 delete this.previousFilter;
Daniel@0 2328 }, 1000 );
Daniel@0 2329 } else {
Daniel@0 2330 delete this.previousFilter;
Daniel@0 2331 }
Daniel@0 2332 } else {
Daniel@0 2333 delete this.previousFilter;
Daniel@0 2334 }
Daniel@0 2335 }
Daniel@0 2336
Daniel@0 2337 if ( preventDefault ) {
Daniel@0 2338 event.preventDefault();
Daniel@0 2339 }
Daniel@0 2340 },
Daniel@0 2341
Daniel@0 2342 _activate: function( event ) {
Daniel@0 2343 if ( !this.active.is( ".ui-state-disabled" ) ) {
Daniel@0 2344 if ( this.active.is( "[aria-haspopup='true']" ) ) {
Daniel@0 2345 this.expand( event );
Daniel@0 2346 } else {
Daniel@0 2347 this.select( event );
Daniel@0 2348 }
Daniel@0 2349 }
Daniel@0 2350 },
Daniel@0 2351
Daniel@0 2352 refresh: function() {
Daniel@0 2353 var menus, items,
Daniel@0 2354 that = this,
Daniel@0 2355 icon = this.options.icons.submenu,
Daniel@0 2356 submenus = this.element.find( this.options.menus );
Daniel@0 2357
Daniel@0 2358 this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
Daniel@0 2359
Daniel@0 2360 // Initialize nested menus
Daniel@0 2361 submenus.filter( ":not(.ui-menu)" )
Daniel@0 2362 .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
Daniel@0 2363 .hide()
Daniel@0 2364 .attr({
Daniel@0 2365 role: this.options.role,
Daniel@0 2366 "aria-hidden": "true",
Daniel@0 2367 "aria-expanded": "false"
Daniel@0 2368 })
Daniel@0 2369 .each(function() {
Daniel@0 2370 var menu = $( this ),
Daniel@0 2371 item = menu.parent(),
Daniel@0 2372 submenuCarat = $( "<span>" )
Daniel@0 2373 .addClass( "ui-menu-icon ui-icon " + icon )
Daniel@0 2374 .data( "ui-menu-submenu-carat", true );
Daniel@0 2375
Daniel@0 2376 item
Daniel@0 2377 .attr( "aria-haspopup", "true" )
Daniel@0 2378 .prepend( submenuCarat );
Daniel@0 2379 menu.attr( "aria-labelledby", item.attr( "id" ) );
Daniel@0 2380 });
Daniel@0 2381
Daniel@0 2382 menus = submenus.add( this.element );
Daniel@0 2383 items = menus.find( this.options.items );
Daniel@0 2384
Daniel@0 2385 // Initialize menu-items containing spaces and/or dashes only as dividers
Daniel@0 2386 items.not( ".ui-menu-item" ).each(function() {
Daniel@0 2387 var item = $( this );
Daniel@0 2388 if ( that._isDivider( item ) ) {
Daniel@0 2389 item.addClass( "ui-widget-content ui-menu-divider" );
Daniel@0 2390 }
Daniel@0 2391 });
Daniel@0 2392
Daniel@0 2393 // Don't refresh list items that are already adapted
Daniel@0 2394 items.not( ".ui-menu-item, .ui-menu-divider" )
Daniel@0 2395 .addClass( "ui-menu-item" )
Daniel@0 2396 .uniqueId()
Daniel@0 2397 .attr({
Daniel@0 2398 tabIndex: -1,
Daniel@0 2399 role: this._itemRole()
Daniel@0 2400 });
Daniel@0 2401
Daniel@0 2402 // Add aria-disabled attribute to any disabled menu item
Daniel@0 2403 items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
Daniel@0 2404
Daniel@0 2405 // If the active item has been removed, blur the menu
Daniel@0 2406 if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
Daniel@0 2407 this.blur();
Daniel@0 2408 }
Daniel@0 2409 },
Daniel@0 2410
Daniel@0 2411 _itemRole: function() {
Daniel@0 2412 return {
Daniel@0 2413 menu: "menuitem",
Daniel@0 2414 listbox: "option"
Daniel@0 2415 }[ this.options.role ];
Daniel@0 2416 },
Daniel@0 2417
Daniel@0 2418 _setOption: function( key, value ) {
Daniel@0 2419 if ( key === "icons" ) {
Daniel@0 2420 this.element.find( ".ui-menu-icon" )
Daniel@0 2421 .removeClass( this.options.icons.submenu )
Daniel@0 2422 .addClass( value.submenu );
Daniel@0 2423 }
Daniel@0 2424 if ( key === "disabled" ) {
Daniel@0 2425 this.element
Daniel@0 2426 .toggleClass( "ui-state-disabled", !!value )
Daniel@0 2427 .attr( "aria-disabled", value );
Daniel@0 2428 }
Daniel@0 2429 this._super( key, value );
Daniel@0 2430 },
Daniel@0 2431
Daniel@0 2432 focus: function( event, item ) {
Daniel@0 2433 var nested, focused;
Daniel@0 2434 this.blur( event, event && event.type === "focus" );
Daniel@0 2435
Daniel@0 2436 this._scrollIntoView( item );
Daniel@0 2437
Daniel@0 2438 this.active = item.first();
Daniel@0 2439 focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
Daniel@0 2440 // Only update aria-activedescendant if there's a role
Daniel@0 2441 // otherwise we assume focus is managed elsewhere
Daniel@0 2442 if ( this.options.role ) {
Daniel@0 2443 this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
Daniel@0 2444 }
Daniel@0 2445
Daniel@0 2446 // Highlight active parent menu item, if any
Daniel@0 2447 this.active
Daniel@0 2448 .parent()
Daniel@0 2449 .closest( ".ui-menu-item" )
Daniel@0 2450 .addClass( "ui-state-active" );
Daniel@0 2451
Daniel@0 2452 if ( event && event.type === "keydown" ) {
Daniel@0 2453 this._close();
Daniel@0 2454 } else {
Daniel@0 2455 this.timer = this._delay(function() {
Daniel@0 2456 this._close();
Daniel@0 2457 }, this.delay );
Daniel@0 2458 }
Daniel@0 2459
Daniel@0 2460 nested = item.children( ".ui-menu" );
Daniel@0 2461 if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
Daniel@0 2462 this._startOpening(nested);
Daniel@0 2463 }
Daniel@0 2464 this.activeMenu = item.parent();
Daniel@0 2465
Daniel@0 2466 this._trigger( "focus", event, { item: item } );
Daniel@0 2467 },
Daniel@0 2468
Daniel@0 2469 _scrollIntoView: function( item ) {
Daniel@0 2470 var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
Daniel@0 2471 if ( this._hasScroll() ) {
Daniel@0 2472 borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
Daniel@0 2473 paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
Daniel@0 2474 offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
Daniel@0 2475 scroll = this.activeMenu.scrollTop();
Daniel@0 2476 elementHeight = this.activeMenu.height();
Daniel@0 2477 itemHeight = item.outerHeight();
Daniel@0 2478
Daniel@0 2479 if ( offset < 0 ) {
Daniel@0 2480 this.activeMenu.scrollTop( scroll + offset );
Daniel@0 2481 } else if ( offset + itemHeight > elementHeight ) {
Daniel@0 2482 this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
Daniel@0 2483 }
Daniel@0 2484 }
Daniel@0 2485 },
Daniel@0 2486
Daniel@0 2487 blur: function( event, fromFocus ) {
Daniel@0 2488 if ( !fromFocus ) {
Daniel@0 2489 clearTimeout( this.timer );
Daniel@0 2490 }
Daniel@0 2491
Daniel@0 2492 if ( !this.active ) {
Daniel@0 2493 return;
Daniel@0 2494 }
Daniel@0 2495
Daniel@0 2496 this.active.removeClass( "ui-state-focus" );
Daniel@0 2497 this.active = null;
Daniel@0 2498
Daniel@0 2499 this._trigger( "blur", event, { item: this.active } );
Daniel@0 2500 },
Daniel@0 2501
Daniel@0 2502 _startOpening: function( submenu ) {
Daniel@0 2503 clearTimeout( this.timer );
Daniel@0 2504
Daniel@0 2505 // Don't open if already open fixes a Firefox bug that caused a .5 pixel
Daniel@0 2506 // shift in the submenu position when mousing over the carat icon
Daniel@0 2507 if ( submenu.attr( "aria-hidden" ) !== "true" ) {
Daniel@0 2508 return;
Daniel@0 2509 }
Daniel@0 2510
Daniel@0 2511 this.timer = this._delay(function() {
Daniel@0 2512 this._close();
Daniel@0 2513 this._open( submenu );
Daniel@0 2514 }, this.delay );
Daniel@0 2515 },
Daniel@0 2516
Daniel@0 2517 _open: function( submenu ) {
Daniel@0 2518 var position = $.extend({
Daniel@0 2519 of: this.active
Daniel@0 2520 }, this.options.position );
Daniel@0 2521
Daniel@0 2522 clearTimeout( this.timer );
Daniel@0 2523 this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
Daniel@0 2524 .hide()
Daniel@0 2525 .attr( "aria-hidden", "true" );
Daniel@0 2526
Daniel@0 2527 submenu
Daniel@0 2528 .show()
Daniel@0 2529 .removeAttr( "aria-hidden" )
Daniel@0 2530 .attr( "aria-expanded", "true" )
Daniel@0 2531 .position( position );
Daniel@0 2532 },
Daniel@0 2533
Daniel@0 2534 collapseAll: function( event, all ) {
Daniel@0 2535 clearTimeout( this.timer );
Daniel@0 2536 this.timer = this._delay(function() {
Daniel@0 2537 // If we were passed an event, look for the submenu that contains the event
Daniel@0 2538 var currentMenu = all ? this.element :
Daniel@0 2539 $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
Daniel@0 2540
Daniel@0 2541 // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
Daniel@0 2542 if ( !currentMenu.length ) {
Daniel@0 2543 currentMenu = this.element;
Daniel@0 2544 }
Daniel@0 2545
Daniel@0 2546 this._close( currentMenu );
Daniel@0 2547
Daniel@0 2548 this.blur( event );
Daniel@0 2549 this.activeMenu = currentMenu;
Daniel@0 2550 }, this.delay );
Daniel@0 2551 },
Daniel@0 2552
Daniel@0 2553 // With no arguments, closes the currently active menu - if nothing is active
Daniel@0 2554 // it closes all menus. If passed an argument, it will search for menus BELOW
Daniel@0 2555 _close: function( startMenu ) {
Daniel@0 2556 if ( !startMenu ) {
Daniel@0 2557 startMenu = this.active ? this.active.parent() : this.element;
Daniel@0 2558 }
Daniel@0 2559
Daniel@0 2560 startMenu
Daniel@0 2561 .find( ".ui-menu" )
Daniel@0 2562 .hide()
Daniel@0 2563 .attr( "aria-hidden", "true" )
Daniel@0 2564 .attr( "aria-expanded", "false" )
Daniel@0 2565 .end()
Daniel@0 2566 .find( ".ui-state-active" ).not( ".ui-state-focus" )
Daniel@0 2567 .removeClass( "ui-state-active" );
Daniel@0 2568 },
Daniel@0 2569
Daniel@0 2570 _closeOnDocumentClick: function( event ) {
Daniel@0 2571 return !$( event.target ).closest( ".ui-menu" ).length;
Daniel@0 2572 },
Daniel@0 2573
Daniel@0 2574 _isDivider: function( item ) {
Daniel@0 2575
Daniel@0 2576 // Match hyphen, em dash, en dash
Daniel@0 2577 return !/[^\-\u2014\u2013\s]/.test( item.text() );
Daniel@0 2578 },
Daniel@0 2579
Daniel@0 2580 collapse: function( event ) {
Daniel@0 2581 var newItem = this.active &&
Daniel@0 2582 this.active.parent().closest( ".ui-menu-item", this.element );
Daniel@0 2583 if ( newItem && newItem.length ) {
Daniel@0 2584 this._close();
Daniel@0 2585 this.focus( event, newItem );
Daniel@0 2586 }
Daniel@0 2587 },
Daniel@0 2588
Daniel@0 2589 expand: function( event ) {
Daniel@0 2590 var newItem = this.active &&
Daniel@0 2591 this.active
Daniel@0 2592 .children( ".ui-menu " )
Daniel@0 2593 .find( this.options.items )
Daniel@0 2594 .first();
Daniel@0 2595
Daniel@0 2596 if ( newItem && newItem.length ) {
Daniel@0 2597 this._open( newItem.parent() );
Daniel@0 2598
Daniel@0 2599 // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
Daniel@0 2600 this._delay(function() {
Daniel@0 2601 this.focus( event, newItem );
Daniel@0 2602 });
Daniel@0 2603 }
Daniel@0 2604 },
Daniel@0 2605
Daniel@0 2606 next: function( event ) {
Daniel@0 2607 this._move( "next", "first", event );
Daniel@0 2608 },
Daniel@0 2609
Daniel@0 2610 previous: function( event ) {
Daniel@0 2611 this._move( "prev", "last", event );
Daniel@0 2612 },
Daniel@0 2613
Daniel@0 2614 isFirstItem: function() {
Daniel@0 2615 return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
Daniel@0 2616 },
Daniel@0 2617
Daniel@0 2618 isLastItem: function() {
Daniel@0 2619 return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
Daniel@0 2620 },
Daniel@0 2621
Daniel@0 2622 _move: function( direction, filter, event ) {
Daniel@0 2623 var next;
Daniel@0 2624 if ( this.active ) {
Daniel@0 2625 if ( direction === "first" || direction === "last" ) {
Daniel@0 2626 next = this.active
Daniel@0 2627 [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
Daniel@0 2628 .eq( -1 );
Daniel@0 2629 } else {
Daniel@0 2630 next = this.active
Daniel@0 2631 [ direction + "All" ]( ".ui-menu-item" )
Daniel@0 2632 .eq( 0 );
Daniel@0 2633 }
Daniel@0 2634 }
Daniel@0 2635 if ( !next || !next.length || !this.active ) {
Daniel@0 2636 next = this.activeMenu.find( this.options.items )[ filter ]();
Daniel@0 2637 }
Daniel@0 2638
Daniel@0 2639 this.focus( event, next );
Daniel@0 2640 },
Daniel@0 2641
Daniel@0 2642 nextPage: function( event ) {
Daniel@0 2643 var item, base, height;
Daniel@0 2644
Daniel@0 2645 if ( !this.active ) {
Daniel@0 2646 this.next( event );
Daniel@0 2647 return;
Daniel@0 2648 }
Daniel@0 2649 if ( this.isLastItem() ) {
Daniel@0 2650 return;
Daniel@0 2651 }
Daniel@0 2652 if ( this._hasScroll() ) {
Daniel@0 2653 base = this.active.offset().top;
Daniel@0 2654 height = this.element.height();
Daniel@0 2655 this.active.nextAll( ".ui-menu-item" ).each(function() {
Daniel@0 2656 item = $( this );
Daniel@0 2657 return item.offset().top - base - height < 0;
Daniel@0 2658 });
Daniel@0 2659
Daniel@0 2660 this.focus( event, item );
Daniel@0 2661 } else {
Daniel@0 2662 this.focus( event, this.activeMenu.find( this.options.items )
Daniel@0 2663 [ !this.active ? "first" : "last" ]() );
Daniel@0 2664 }
Daniel@0 2665 },
Daniel@0 2666
Daniel@0 2667 previousPage: function( event ) {
Daniel@0 2668 var item, base, height;
Daniel@0 2669 if ( !this.active ) {
Daniel@0 2670 this.next( event );
Daniel@0 2671 return;
Daniel@0 2672 }
Daniel@0 2673 if ( this.isFirstItem() ) {
Daniel@0 2674 return;
Daniel@0 2675 }
Daniel@0 2676 if ( this._hasScroll() ) {
Daniel@0 2677 base = this.active.offset().top;
Daniel@0 2678 height = this.element.height();
Daniel@0 2679 this.active.prevAll( ".ui-menu-item" ).each(function() {
Daniel@0 2680 item = $( this );
Daniel@0 2681 return item.offset().top - base + height > 0;
Daniel@0 2682 });
Daniel@0 2683
Daniel@0 2684 this.focus( event, item );
Daniel@0 2685 } else {
Daniel@0 2686 this.focus( event, this.activeMenu.find( this.options.items ).first() );
Daniel@0 2687 }
Daniel@0 2688 },
Daniel@0 2689
Daniel@0 2690 _hasScroll: function() {
Daniel@0 2691 return this.element.outerHeight() < this.element.prop( "scrollHeight" );
Daniel@0 2692 },
Daniel@0 2693
Daniel@0 2694 select: function( event ) {
Daniel@0 2695 // TODO: It should never be possible to not have an active item at this
Daniel@0 2696 // point, but the tests don't trigger mouseenter before click.
Daniel@0 2697 this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
Daniel@0 2698 var ui = { item: this.active };
Daniel@0 2699 if ( !this.active.has( ".ui-menu" ).length ) {
Daniel@0 2700 this.collapseAll( event, true );
Daniel@0 2701 }
Daniel@0 2702 this._trigger( "select", event, ui );
Daniel@0 2703 }
Daniel@0 2704 });
Daniel@0 2705
Daniel@0 2706
Daniel@0 2707 /*!
Daniel@0 2708 * jQuery UI Autocomplete 1.11.0
Daniel@0 2709 * http://jqueryui.com
Daniel@0 2710 *
Daniel@0 2711 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 2712 * Released under the MIT license.
Daniel@0 2713 * http://jquery.org/license
Daniel@0 2714 *
Daniel@0 2715 * http://api.jqueryui.com/autocomplete/
Daniel@0 2716 */
Daniel@0 2717
Daniel@0 2718
Daniel@0 2719 $.widget( "ui.autocomplete", {
Daniel@0 2720 version: "1.11.0",
Daniel@0 2721 defaultElement: "<input>",
Daniel@0 2722 options: {
Daniel@0 2723 appendTo: null,
Daniel@0 2724 autoFocus: false,
Daniel@0 2725 delay: 300,
Daniel@0 2726 minLength: 1,
Daniel@0 2727 position: {
Daniel@0 2728 my: "left top",
Daniel@0 2729 at: "left bottom",
Daniel@0 2730 collision: "none"
Daniel@0 2731 },
Daniel@0 2732 source: null,
Daniel@0 2733
Daniel@0 2734 // callbacks
Daniel@0 2735 change: null,
Daniel@0 2736 close: null,
Daniel@0 2737 focus: null,
Daniel@0 2738 open: null,
Daniel@0 2739 response: null,
Daniel@0 2740 search: null,
Daniel@0 2741 select: null
Daniel@0 2742 },
Daniel@0 2743
Daniel@0 2744 requestIndex: 0,
Daniel@0 2745 pending: 0,
Daniel@0 2746
Daniel@0 2747 _create: function() {
Daniel@0 2748 // Some browsers only repeat keydown events, not keypress events,
Daniel@0 2749 // so we use the suppressKeyPress flag to determine if we've already
Daniel@0 2750 // handled the keydown event. #7269
Daniel@0 2751 // Unfortunately the code for & in keypress is the same as the up arrow,
Daniel@0 2752 // so we use the suppressKeyPressRepeat flag to avoid handling keypress
Daniel@0 2753 // events when we know the keydown event was used to modify the
Daniel@0 2754 // search term. #7799
Daniel@0 2755 var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
Daniel@0 2756 nodeName = this.element[ 0 ].nodeName.toLowerCase(),
Daniel@0 2757 isTextarea = nodeName === "textarea",
Daniel@0 2758 isInput = nodeName === "input";
Daniel@0 2759
Daniel@0 2760 this.isMultiLine =
Daniel@0 2761 // Textareas are always multi-line
Daniel@0 2762 isTextarea ? true :
Daniel@0 2763 // Inputs are always single-line, even if inside a contentEditable element
Daniel@0 2764 // IE also treats inputs as contentEditable
Daniel@0 2765 isInput ? false :
Daniel@0 2766 // All other element types are determined by whether or not they're contentEditable
Daniel@0 2767 this.element.prop( "isContentEditable" );
Daniel@0 2768
Daniel@0 2769 this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
Daniel@0 2770 this.isNewMenu = true;
Daniel@0 2771
Daniel@0 2772 this.element
Daniel@0 2773 .addClass( "ui-autocomplete-input" )
Daniel@0 2774 .attr( "autocomplete", "off" );
Daniel@0 2775
Daniel@0 2776 this._on( this.element, {
Daniel@0 2777 keydown: function( event ) {
Daniel@0 2778 if ( this.element.prop( "readOnly" ) ) {
Daniel@0 2779 suppressKeyPress = true;
Daniel@0 2780 suppressInput = true;
Daniel@0 2781 suppressKeyPressRepeat = true;
Daniel@0 2782 return;
Daniel@0 2783 }
Daniel@0 2784
Daniel@0 2785 suppressKeyPress = false;
Daniel@0 2786 suppressInput = false;
Daniel@0 2787 suppressKeyPressRepeat = false;
Daniel@0 2788 var keyCode = $.ui.keyCode;
Daniel@0 2789 switch ( event.keyCode ) {
Daniel@0 2790 case keyCode.PAGE_UP:
Daniel@0 2791 suppressKeyPress = true;
Daniel@0 2792 this._move( "previousPage", event );
Daniel@0 2793 break;
Daniel@0 2794 case keyCode.PAGE_DOWN:
Daniel@0 2795 suppressKeyPress = true;
Daniel@0 2796 this._move( "nextPage", event );
Daniel@0 2797 break;
Daniel@0 2798 case keyCode.UP:
Daniel@0 2799 suppressKeyPress = true;
Daniel@0 2800 this._keyEvent( "previous", event );
Daniel@0 2801 break;
Daniel@0 2802 case keyCode.DOWN:
Daniel@0 2803 suppressKeyPress = true;
Daniel@0 2804 this._keyEvent( "next", event );
Daniel@0 2805 break;
Daniel@0 2806 case keyCode.ENTER:
Daniel@0 2807 // when menu is open and has focus
Daniel@0 2808 if ( this.menu.active ) {
Daniel@0 2809 // #6055 - Opera still allows the keypress to occur
Daniel@0 2810 // which causes forms to submit
Daniel@0 2811 suppressKeyPress = true;
Daniel@0 2812 event.preventDefault();
Daniel@0 2813 this.menu.select( event );
Daniel@0 2814 }
Daniel@0 2815 break;
Daniel@0 2816 case keyCode.TAB:
Daniel@0 2817 if ( this.menu.active ) {
Daniel@0 2818 this.menu.select( event );
Daniel@0 2819 }
Daniel@0 2820 break;
Daniel@0 2821 case keyCode.ESCAPE:
Daniel@0 2822 if ( this.menu.element.is( ":visible" ) ) {
Daniel@0 2823 this._value( this.term );
Daniel@0 2824 this.close( event );
Daniel@0 2825 // Different browsers have different default behavior for escape
Daniel@0 2826 // Single press can mean undo or clear
Daniel@0 2827 // Double press in IE means clear the whole form
Daniel@0 2828 event.preventDefault();
Daniel@0 2829 }
Daniel@0 2830 break;
Daniel@0 2831 default:
Daniel@0 2832 suppressKeyPressRepeat = true;
Daniel@0 2833 // search timeout should be triggered before the input value is changed
Daniel@0 2834 this._searchTimeout( event );
Daniel@0 2835 break;
Daniel@0 2836 }
Daniel@0 2837 },
Daniel@0 2838 keypress: function( event ) {
Daniel@0 2839 if ( suppressKeyPress ) {
Daniel@0 2840 suppressKeyPress = false;
Daniel@0 2841 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
Daniel@0 2842 event.preventDefault();
Daniel@0 2843 }
Daniel@0 2844 return;
Daniel@0 2845 }
Daniel@0 2846 if ( suppressKeyPressRepeat ) {
Daniel@0 2847 return;
Daniel@0 2848 }
Daniel@0 2849
Daniel@0 2850 // replicate some key handlers to allow them to repeat in Firefox and Opera
Daniel@0 2851 var keyCode = $.ui.keyCode;
Daniel@0 2852 switch ( event.keyCode ) {
Daniel@0 2853 case keyCode.PAGE_UP:
Daniel@0 2854 this._move( "previousPage", event );
Daniel@0 2855 break;
Daniel@0 2856 case keyCode.PAGE_DOWN:
Daniel@0 2857 this._move( "nextPage", event );
Daniel@0 2858 break;
Daniel@0 2859 case keyCode.UP:
Daniel@0 2860 this._keyEvent( "previous", event );
Daniel@0 2861 break;
Daniel@0 2862 case keyCode.DOWN:
Daniel@0 2863 this._keyEvent( "next", event );
Daniel@0 2864 break;
Daniel@0 2865 }
Daniel@0 2866 },
Daniel@0 2867 input: function( event ) {
Daniel@0 2868 if ( suppressInput ) {
Daniel@0 2869 suppressInput = false;
Daniel@0 2870 event.preventDefault();
Daniel@0 2871 return;
Daniel@0 2872 }
Daniel@0 2873 this._searchTimeout( event );
Daniel@0 2874 },
Daniel@0 2875 focus: function() {
Daniel@0 2876 this.selectedItem = null;
Daniel@0 2877 this.previous = this._value();
Daniel@0 2878 },
Daniel@0 2879 blur: function( event ) {
Daniel@0 2880 if ( this.cancelBlur ) {
Daniel@0 2881 delete this.cancelBlur;
Daniel@0 2882 return;
Daniel@0 2883 }
Daniel@0 2884
Daniel@0 2885 clearTimeout( this.searching );
Daniel@0 2886 this.close( event );
Daniel@0 2887 this._change( event );
Daniel@0 2888 }
Daniel@0 2889 });
Daniel@0 2890
Daniel@0 2891 this._initSource();
Daniel@0 2892 this.menu = $( "<ul>" )
Daniel@0 2893 .addClass( "ui-autocomplete ui-front" )
Daniel@0 2894 .appendTo( this._appendTo() )
Daniel@0 2895 .menu({
Daniel@0 2896 // disable ARIA support, the live region takes care of that
Daniel@0 2897 role: null
Daniel@0 2898 })
Daniel@0 2899 .hide()
Daniel@0 2900 .menu( "instance" );
Daniel@0 2901
Daniel@0 2902 this._on( this.menu.element, {
Daniel@0 2903 mousedown: function( event ) {
Daniel@0 2904 // prevent moving focus out of the text field
Daniel@0 2905 event.preventDefault();
Daniel@0 2906
Daniel@0 2907 // IE doesn't prevent moving focus even with event.preventDefault()
Daniel@0 2908 // so we set a flag to know when we should ignore the blur event
Daniel@0 2909 this.cancelBlur = true;
Daniel@0 2910 this._delay(function() {
Daniel@0 2911 delete this.cancelBlur;
Daniel@0 2912 });
Daniel@0 2913
Daniel@0 2914 // clicking on the scrollbar causes focus to shift to the body
Daniel@0 2915 // but we can't detect a mouseup or a click immediately afterward
Daniel@0 2916 // so we have to track the next mousedown and close the menu if
Daniel@0 2917 // the user clicks somewhere outside of the autocomplete
Daniel@0 2918 var menuElement = this.menu.element[ 0 ];
Daniel@0 2919 if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
Daniel@0 2920 this._delay(function() {
Daniel@0 2921 var that = this;
Daniel@0 2922 this.document.one( "mousedown", function( event ) {
Daniel@0 2923 if ( event.target !== that.element[ 0 ] &&
Daniel@0 2924 event.target !== menuElement &&
Daniel@0 2925 !$.contains( menuElement, event.target ) ) {
Daniel@0 2926 that.close();
Daniel@0 2927 }
Daniel@0 2928 });
Daniel@0 2929 });
Daniel@0 2930 }
Daniel@0 2931 },
Daniel@0 2932 menufocus: function( event, ui ) {
Daniel@0 2933 var label, item;
Daniel@0 2934 // support: Firefox
Daniel@0 2935 // Prevent accidental activation of menu items in Firefox (#7024 #9118)
Daniel@0 2936 if ( this.isNewMenu ) {
Daniel@0 2937 this.isNewMenu = false;
Daniel@0 2938 if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
Daniel@0 2939 this.menu.blur();
Daniel@0 2940
Daniel@0 2941 this.document.one( "mousemove", function() {
Daniel@0 2942 $( event.target ).trigger( event.originalEvent );
Daniel@0 2943 });
Daniel@0 2944
Daniel@0 2945 return;
Daniel@0 2946 }
Daniel@0 2947 }
Daniel@0 2948
Daniel@0 2949 item = ui.item.data( "ui-autocomplete-item" );
Daniel@0 2950 if ( false !== this._trigger( "focus", event, { item: item } ) ) {
Daniel@0 2951 // use value to match what will end up in the input, if it was a key event
Daniel@0 2952 if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
Daniel@0 2953 this._value( item.value );
Daniel@0 2954 }
Daniel@0 2955 }
Daniel@0 2956
Daniel@0 2957 // Announce the value in the liveRegion
Daniel@0 2958 label = ui.item.attr( "aria-label" ) || item.value;
Daniel@0 2959 if ( label && jQuery.trim( label ).length ) {
Daniel@0 2960 this.liveRegion.children().hide();
Daniel@0 2961 $( "<div>" ).text( label ).appendTo( this.liveRegion );
Daniel@0 2962 }
Daniel@0 2963 },
Daniel@0 2964 menuselect: function( event, ui ) {
Daniel@0 2965 var item = ui.item.data( "ui-autocomplete-item" ),
Daniel@0 2966 previous = this.previous;
Daniel@0 2967
Daniel@0 2968 // only trigger when focus was lost (click on menu)
Daniel@0 2969 if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
Daniel@0 2970 this.element.focus();
Daniel@0 2971 this.previous = previous;
Daniel@0 2972 // #6109 - IE triggers two focus events and the second
Daniel@0 2973 // is asynchronous, so we need to reset the previous
Daniel@0 2974 // term synchronously and asynchronously :-(
Daniel@0 2975 this._delay(function() {
Daniel@0 2976 this.previous = previous;
Daniel@0 2977 this.selectedItem = item;
Daniel@0 2978 });
Daniel@0 2979 }
Daniel@0 2980
Daniel@0 2981 if ( false !== this._trigger( "select", event, { item: item } ) ) {
Daniel@0 2982 this._value( item.value );
Daniel@0 2983 }
Daniel@0 2984 // reset the term after the select event
Daniel@0 2985 // this allows custom select handling to work properly
Daniel@0 2986 this.term = this._value();
Daniel@0 2987
Daniel@0 2988 this.close( event );
Daniel@0 2989 this.selectedItem = item;
Daniel@0 2990 }
Daniel@0 2991 });
Daniel@0 2992
Daniel@0 2993 this.liveRegion = $( "<span>", {
Daniel@0 2994 role: "status",
Daniel@0 2995 "aria-live": "assertive",
Daniel@0 2996 "aria-relevant": "additions"
Daniel@0 2997 })
Daniel@0 2998 .addClass( "ui-helper-hidden-accessible" )
Daniel@0 2999 .appendTo( this.document[ 0 ].body );
Daniel@0 3000
Daniel@0 3001 // turning off autocomplete prevents the browser from remembering the
Daniel@0 3002 // value when navigating through history, so we re-enable autocomplete
Daniel@0 3003 // if the page is unloaded before the widget is destroyed. #7790
Daniel@0 3004 this._on( this.window, {
Daniel@0 3005 beforeunload: function() {
Daniel@0 3006 this.element.removeAttr( "autocomplete" );
Daniel@0 3007 }
Daniel@0 3008 });
Daniel@0 3009 },
Daniel@0 3010
Daniel@0 3011 _destroy: function() {
Daniel@0 3012 clearTimeout( this.searching );
Daniel@0 3013 this.element
Daniel@0 3014 .removeClass( "ui-autocomplete-input" )
Daniel@0 3015 .removeAttr( "autocomplete" );
Daniel@0 3016 this.menu.element.remove();
Daniel@0 3017 this.liveRegion.remove();
Daniel@0 3018 },
Daniel@0 3019
Daniel@0 3020 _setOption: function( key, value ) {
Daniel@0 3021 this._super( key, value );
Daniel@0 3022 if ( key === "source" ) {
Daniel@0 3023 this._initSource();
Daniel@0 3024 }
Daniel@0 3025 if ( key === "appendTo" ) {
Daniel@0 3026 this.menu.element.appendTo( this._appendTo() );
Daniel@0 3027 }
Daniel@0 3028 if ( key === "disabled" && value && this.xhr ) {
Daniel@0 3029 this.xhr.abort();
Daniel@0 3030 }
Daniel@0 3031 },
Daniel@0 3032
Daniel@0 3033 _appendTo: function() {
Daniel@0 3034 var element = this.options.appendTo;
Daniel@0 3035
Daniel@0 3036 if ( element ) {
Daniel@0 3037 element = element.jquery || element.nodeType ?
Daniel@0 3038 $( element ) :
Daniel@0 3039 this.document.find( element ).eq( 0 );
Daniel@0 3040 }
Daniel@0 3041
Daniel@0 3042 if ( !element || !element[ 0 ] ) {
Daniel@0 3043 element = this.element.closest( ".ui-front" );
Daniel@0 3044 }
Daniel@0 3045
Daniel@0 3046 if ( !element.length ) {
Daniel@0 3047 element = this.document[ 0 ].body;
Daniel@0 3048 }
Daniel@0 3049
Daniel@0 3050 return element;
Daniel@0 3051 },
Daniel@0 3052
Daniel@0 3053 _initSource: function() {
Daniel@0 3054 var array, url,
Daniel@0 3055 that = this;
Daniel@0 3056 if ( $.isArray( this.options.source ) ) {
Daniel@0 3057 array = this.options.source;
Daniel@0 3058 this.source = function( request, response ) {
Daniel@0 3059 response( $.ui.autocomplete.filter( array, request.term ) );
Daniel@0 3060 };
Daniel@0 3061 } else if ( typeof this.options.source === "string" ) {
Daniel@0 3062 url = this.options.source;
Daniel@0 3063 this.source = function( request, response ) {
Daniel@0 3064 if ( that.xhr ) {
Daniel@0 3065 that.xhr.abort();
Daniel@0 3066 }
Daniel@0 3067 that.xhr = $.ajax({
Daniel@0 3068 url: url,
Daniel@0 3069 data: request,
Daniel@0 3070 dataType: "json",
Daniel@0 3071 success: function( data ) {
Daniel@0 3072 response( data );
Daniel@0 3073 },
Daniel@0 3074 error: function() {
Daniel@0 3075 response([]);
Daniel@0 3076 }
Daniel@0 3077 });
Daniel@0 3078 };
Daniel@0 3079 } else {
Daniel@0 3080 this.source = this.options.source;
Daniel@0 3081 }
Daniel@0 3082 },
Daniel@0 3083
Daniel@0 3084 _searchTimeout: function( event ) {
Daniel@0 3085 clearTimeout( this.searching );
Daniel@0 3086 this.searching = this._delay(function() {
Daniel@0 3087
Daniel@0 3088 // Search if the value has changed, or if the user retypes the same value (see #7434)
Daniel@0 3089 var equalValues = this.term === this._value(),
Daniel@0 3090 menuVisible = this.menu.element.is( ":visible" ),
Daniel@0 3091 modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
Daniel@0 3092
Daniel@0 3093 if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
Daniel@0 3094 this.selectedItem = null;
Daniel@0 3095 this.search( null, event );
Daniel@0 3096 }
Daniel@0 3097 }, this.options.delay );
Daniel@0 3098 },
Daniel@0 3099
Daniel@0 3100 search: function( value, event ) {
Daniel@0 3101 value = value != null ? value : this._value();
Daniel@0 3102
Daniel@0 3103 // always save the actual value, not the one passed as an argument
Daniel@0 3104 this.term = this._value();
Daniel@0 3105
Daniel@0 3106 if ( value.length < this.options.minLength ) {
Daniel@0 3107 return this.close( event );
Daniel@0 3108 }
Daniel@0 3109
Daniel@0 3110 if ( this._trigger( "search", event ) === false ) {
Daniel@0 3111 return;
Daniel@0 3112 }
Daniel@0 3113
Daniel@0 3114 return this._search( value );
Daniel@0 3115 },
Daniel@0 3116
Daniel@0 3117 _search: function( value ) {
Daniel@0 3118 this.pending++;
Daniel@0 3119 this.element.addClass( "ui-autocomplete-loading" );
Daniel@0 3120 this.cancelSearch = false;
Daniel@0 3121
Daniel@0 3122 this.source( { term: value }, this._response() );
Daniel@0 3123 },
Daniel@0 3124
Daniel@0 3125 _response: function() {
Daniel@0 3126 var index = ++this.requestIndex;
Daniel@0 3127
Daniel@0 3128 return $.proxy(function( content ) {
Daniel@0 3129 if ( index === this.requestIndex ) {
Daniel@0 3130 this.__response( content );
Daniel@0 3131 }
Daniel@0 3132
Daniel@0 3133 this.pending--;
Daniel@0 3134 if ( !this.pending ) {
Daniel@0 3135 this.element.removeClass( "ui-autocomplete-loading" );
Daniel@0 3136 }
Daniel@0 3137 }, this );
Daniel@0 3138 },
Daniel@0 3139
Daniel@0 3140 __response: function( content ) {
Daniel@0 3141 if ( content ) {
Daniel@0 3142 content = this._normalize( content );
Daniel@0 3143 }
Daniel@0 3144 this._trigger( "response", null, { content: content } );
Daniel@0 3145 if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
Daniel@0 3146 this._suggest( content );
Daniel@0 3147 this._trigger( "open" );
Daniel@0 3148 } else {
Daniel@0 3149 // use ._close() instead of .close() so we don't cancel future searches
Daniel@0 3150 this._close();
Daniel@0 3151 }
Daniel@0 3152 },
Daniel@0 3153
Daniel@0 3154 close: function( event ) {
Daniel@0 3155 this.cancelSearch = true;
Daniel@0 3156 this._close( event );
Daniel@0 3157 },
Daniel@0 3158
Daniel@0 3159 _close: function( event ) {
Daniel@0 3160 if ( this.menu.element.is( ":visible" ) ) {
Daniel@0 3161 this.menu.element.hide();
Daniel@0 3162 this.menu.blur();
Daniel@0 3163 this.isNewMenu = true;
Daniel@0 3164 this._trigger( "close", event );
Daniel@0 3165 }
Daniel@0 3166 },
Daniel@0 3167
Daniel@0 3168 _change: function( event ) {
Daniel@0 3169 if ( this.previous !== this._value() ) {
Daniel@0 3170 this._trigger( "change", event, { item: this.selectedItem } );
Daniel@0 3171 }
Daniel@0 3172 },
Daniel@0 3173
Daniel@0 3174 _normalize: function( items ) {
Daniel@0 3175 // assume all items have the right format when the first item is complete
Daniel@0 3176 if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
Daniel@0 3177 return items;
Daniel@0 3178 }
Daniel@0 3179 return $.map( items, function( item ) {
Daniel@0 3180 if ( typeof item === "string" ) {
Daniel@0 3181 return {
Daniel@0 3182 label: item,
Daniel@0 3183 value: item
Daniel@0 3184 };
Daniel@0 3185 }
Daniel@0 3186 return $.extend( {}, item, {
Daniel@0 3187 label: item.label || item.value,
Daniel@0 3188 value: item.value || item.label
Daniel@0 3189 });
Daniel@0 3190 });
Daniel@0 3191 },
Daniel@0 3192
Daniel@0 3193 _suggest: function( items ) {
Daniel@0 3194 var ul = this.menu.element.empty();
Daniel@0 3195 this._renderMenu( ul, items );
Daniel@0 3196 this.isNewMenu = true;
Daniel@0 3197 this.menu.refresh();
Daniel@0 3198
Daniel@0 3199 // size and position menu
Daniel@0 3200 ul.show();
Daniel@0 3201 this._resizeMenu();
Daniel@0 3202 ul.position( $.extend({
Daniel@0 3203 of: this.element
Daniel@0 3204 }, this.options.position ) );
Daniel@0 3205
Daniel@0 3206 if ( this.options.autoFocus ) {
Daniel@0 3207 this.menu.next();
Daniel@0 3208 }
Daniel@0 3209 },
Daniel@0 3210
Daniel@0 3211 _resizeMenu: function() {
Daniel@0 3212 var ul = this.menu.element;
Daniel@0 3213 ul.outerWidth( Math.max(
Daniel@0 3214 // Firefox wraps long text (possibly a rounding bug)
Daniel@0 3215 // so we add 1px to avoid the wrapping (#7513)
Daniel@0 3216 ul.width( "" ).outerWidth() + 1,
Daniel@0 3217 this.element.outerWidth()
Daniel@0 3218 ) );
Daniel@0 3219 },
Daniel@0 3220
Daniel@0 3221 _renderMenu: function( ul, items ) {
Daniel@0 3222 var that = this;
Daniel@0 3223 $.each( items, function( index, item ) {
Daniel@0 3224 that._renderItemData( ul, item );
Daniel@0 3225 });
Daniel@0 3226 },
Daniel@0 3227
Daniel@0 3228 _renderItemData: function( ul, item ) {
Daniel@0 3229 return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
Daniel@0 3230 },
Daniel@0 3231
Daniel@0 3232 _renderItem: function( ul, item ) {
Daniel@0 3233 return $( "<li>" ).text( item.label ).appendTo( ul );
Daniel@0 3234 },
Daniel@0 3235
Daniel@0 3236 _move: function( direction, event ) {
Daniel@0 3237 if ( !this.menu.element.is( ":visible" ) ) {
Daniel@0 3238 this.search( null, event );
Daniel@0 3239 return;
Daniel@0 3240 }
Daniel@0 3241 if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
Daniel@0 3242 this.menu.isLastItem() && /^next/.test( direction ) ) {
Daniel@0 3243
Daniel@0 3244 if ( !this.isMultiLine ) {
Daniel@0 3245 this._value( this.term );
Daniel@0 3246 }
Daniel@0 3247
Daniel@0 3248 this.menu.blur();
Daniel@0 3249 return;
Daniel@0 3250 }
Daniel@0 3251 this.menu[ direction ]( event );
Daniel@0 3252 },
Daniel@0 3253
Daniel@0 3254 widget: function() {
Daniel@0 3255 return this.menu.element;
Daniel@0 3256 },
Daniel@0 3257
Daniel@0 3258 _value: function() {
Daniel@0 3259 return this.valueMethod.apply( this.element, arguments );
Daniel@0 3260 },
Daniel@0 3261
Daniel@0 3262 _keyEvent: function( keyEvent, event ) {
Daniel@0 3263 if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
Daniel@0 3264 this._move( keyEvent, event );
Daniel@0 3265
Daniel@0 3266 // prevents moving cursor to beginning/end of the text field in some browsers
Daniel@0 3267 event.preventDefault();
Daniel@0 3268 }
Daniel@0 3269 }
Daniel@0 3270 });
Daniel@0 3271
Daniel@0 3272 $.extend( $.ui.autocomplete, {
Daniel@0 3273 escapeRegex: function( value ) {
Daniel@0 3274 return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
Daniel@0 3275 },
Daniel@0 3276 filter: function( array, term ) {
Daniel@0 3277 var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
Daniel@0 3278 return $.grep( array, function( value ) {
Daniel@0 3279 return matcher.test( value.label || value.value || value );
Daniel@0 3280 });
Daniel@0 3281 }
Daniel@0 3282 });
Daniel@0 3283
Daniel@0 3284 // live region extension, adding a `messages` option
Daniel@0 3285 // NOTE: This is an experimental API. We are still investigating
Daniel@0 3286 // a full solution for string manipulation and internationalization.
Daniel@0 3287 $.widget( "ui.autocomplete", $.ui.autocomplete, {
Daniel@0 3288 options: {
Daniel@0 3289 messages: {
Daniel@0 3290 noResults: "No search results.",
Daniel@0 3291 results: function( amount ) {
Daniel@0 3292 return amount + ( amount > 1 ? " results are" : " result is" ) +
Daniel@0 3293 " available, use up and down arrow keys to navigate.";
Daniel@0 3294 }
Daniel@0 3295 }
Daniel@0 3296 },
Daniel@0 3297
Daniel@0 3298 __response: function( content ) {
Daniel@0 3299 var message;
Daniel@0 3300 this._superApply( arguments );
Daniel@0 3301 if ( this.options.disabled || this.cancelSearch ) {
Daniel@0 3302 return;
Daniel@0 3303 }
Daniel@0 3304 if ( content && content.length ) {
Daniel@0 3305 message = this.options.messages.results( content.length );
Daniel@0 3306 } else {
Daniel@0 3307 message = this.options.messages.noResults;
Daniel@0 3308 }
Daniel@0 3309 this.liveRegion.children().hide();
Daniel@0 3310 $( "<div>" ).text( message ).appendTo( this.liveRegion );
Daniel@0 3311 }
Daniel@0 3312 });
Daniel@0 3313
Daniel@0 3314 var autocomplete = $.ui.autocomplete;
Daniel@0 3315
Daniel@0 3316
Daniel@0 3317 /*!
Daniel@0 3318 * jQuery UI Button 1.11.0
Daniel@0 3319 * http://jqueryui.com
Daniel@0 3320 *
Daniel@0 3321 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 3322 * Released under the MIT license.
Daniel@0 3323 * http://jquery.org/license
Daniel@0 3324 *
Daniel@0 3325 * http://api.jqueryui.com/button/
Daniel@0 3326 */
Daniel@0 3327
Daniel@0 3328
Daniel@0 3329 var lastActive,
Daniel@0 3330 baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
Daniel@0 3331 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",
Daniel@0 3332 formResetHandler = function() {
Daniel@0 3333 var form = $( this );
Daniel@0 3334 setTimeout(function() {
Daniel@0 3335 form.find( ":ui-button" ).button( "refresh" );
Daniel@0 3336 }, 1 );
Daniel@0 3337 },
Daniel@0 3338 radioGroup = function( radio ) {
Daniel@0 3339 var name = radio.name,
Daniel@0 3340 form = radio.form,
Daniel@0 3341 radios = $( [] );
Daniel@0 3342 if ( name ) {
Daniel@0 3343 name = name.replace( /'/g, "\\'" );
Daniel@0 3344 if ( form ) {
Daniel@0 3345 radios = $( form ).find( "[name='" + name + "'][type=radio]" );
Daniel@0 3346 } else {
Daniel@0 3347 radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
Daniel@0 3348 .filter(function() {
Daniel@0 3349 return !this.form;
Daniel@0 3350 });
Daniel@0 3351 }
Daniel@0 3352 }
Daniel@0 3353 return radios;
Daniel@0 3354 };
Daniel@0 3355
Daniel@0 3356 $.widget( "ui.button", {
Daniel@0 3357 version: "1.11.0",
Daniel@0 3358 defaultElement: "<button>",
Daniel@0 3359 options: {
Daniel@0 3360 disabled: null,
Daniel@0 3361 text: true,
Daniel@0 3362 label: null,
Daniel@0 3363 icons: {
Daniel@0 3364 primary: null,
Daniel@0 3365 secondary: null
Daniel@0 3366 }
Daniel@0 3367 },
Daniel@0 3368 _create: function() {
Daniel@0 3369 this.element.closest( "form" )
Daniel@0 3370 .unbind( "reset" + this.eventNamespace )
Daniel@0 3371 .bind( "reset" + this.eventNamespace, formResetHandler );
Daniel@0 3372
Daniel@0 3373 if ( typeof this.options.disabled !== "boolean" ) {
Daniel@0 3374 this.options.disabled = !!this.element.prop( "disabled" );
Daniel@0 3375 } else {
Daniel@0 3376 this.element.prop( "disabled", this.options.disabled );
Daniel@0 3377 }
Daniel@0 3378
Daniel@0 3379 this._determineButtonType();
Daniel@0 3380 this.hasTitle = !!this.buttonElement.attr( "title" );
Daniel@0 3381
Daniel@0 3382 var that = this,
Daniel@0 3383 options = this.options,
Daniel@0 3384 toggleButton = this.type === "checkbox" || this.type === "radio",
Daniel@0 3385 activeClass = !toggleButton ? "ui-state-active" : "";
Daniel@0 3386
Daniel@0 3387 if ( options.label === null ) {
Daniel@0 3388 options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
Daniel@0 3389 }
Daniel@0 3390
Daniel@0 3391 this._hoverable( this.buttonElement );
Daniel@0 3392
Daniel@0 3393 this.buttonElement
Daniel@0 3394 .addClass( baseClasses )
Daniel@0 3395 .attr( "role", "button" )
Daniel@0 3396 .bind( "mouseenter" + this.eventNamespace, function() {
Daniel@0 3397 if ( options.disabled ) {
Daniel@0 3398 return;
Daniel@0 3399 }
Daniel@0 3400 if ( this === lastActive ) {
Daniel@0 3401 $( this ).addClass( "ui-state-active" );
Daniel@0 3402 }
Daniel@0 3403 })
Daniel@0 3404 .bind( "mouseleave" + this.eventNamespace, function() {
Daniel@0 3405 if ( options.disabled ) {
Daniel@0 3406 return;
Daniel@0 3407 }
Daniel@0 3408 $( this ).removeClass( activeClass );
Daniel@0 3409 })
Daniel@0 3410 .bind( "click" + this.eventNamespace, function( event ) {
Daniel@0 3411 if ( options.disabled ) {
Daniel@0 3412 event.preventDefault();
Daniel@0 3413 event.stopImmediatePropagation();
Daniel@0 3414 }
Daniel@0 3415 });
Daniel@0 3416
Daniel@0 3417 // Can't use _focusable() because the element that receives focus
Daniel@0 3418 // and the element that gets the ui-state-focus class are different
Daniel@0 3419 this._on({
Daniel@0 3420 focus: function() {
Daniel@0 3421 this.buttonElement.addClass( "ui-state-focus" );
Daniel@0 3422 },
Daniel@0 3423 blur: function() {
Daniel@0 3424 this.buttonElement.removeClass( "ui-state-focus" );
Daniel@0 3425 }
Daniel@0 3426 });
Daniel@0 3427
Daniel@0 3428 if ( toggleButton ) {
Daniel@0 3429 this.element.bind( "change" + this.eventNamespace, function() {
Daniel@0 3430 that.refresh();
Daniel@0 3431 });
Daniel@0 3432 }
Daniel@0 3433
Daniel@0 3434 if ( this.type === "checkbox" ) {
Daniel@0 3435 this.buttonElement.bind( "click" + this.eventNamespace, function() {
Daniel@0 3436 if ( options.disabled ) {
Daniel@0 3437 return false;
Daniel@0 3438 }
Daniel@0 3439 });
Daniel@0 3440 } else if ( this.type === "radio" ) {
Daniel@0 3441 this.buttonElement.bind( "click" + this.eventNamespace, function() {
Daniel@0 3442 if ( options.disabled ) {
Daniel@0 3443 return false;
Daniel@0 3444 }
Daniel@0 3445 $( this ).addClass( "ui-state-active" );
Daniel@0 3446 that.buttonElement.attr( "aria-pressed", "true" );
Daniel@0 3447
Daniel@0 3448 var radio = that.element[ 0 ];
Daniel@0 3449 radioGroup( radio )
Daniel@0 3450 .not( radio )
Daniel@0 3451 .map(function() {
Daniel@0 3452 return $( this ).button( "widget" )[ 0 ];
Daniel@0 3453 })
Daniel@0 3454 .removeClass( "ui-state-active" )
Daniel@0 3455 .attr( "aria-pressed", "false" );
Daniel@0 3456 });
Daniel@0 3457 } else {
Daniel@0 3458 this.buttonElement
Daniel@0 3459 .bind( "mousedown" + this.eventNamespace, function() {
Daniel@0 3460 if ( options.disabled ) {
Daniel@0 3461 return false;
Daniel@0 3462 }
Daniel@0 3463 $( this ).addClass( "ui-state-active" );
Daniel@0 3464 lastActive = this;
Daniel@0 3465 that.document.one( "mouseup", function() {
Daniel@0 3466 lastActive = null;
Daniel@0 3467 });
Daniel@0 3468 })
Daniel@0 3469 .bind( "mouseup" + this.eventNamespace, function() {
Daniel@0 3470 if ( options.disabled ) {
Daniel@0 3471 return false;
Daniel@0 3472 }
Daniel@0 3473 $( this ).removeClass( "ui-state-active" );
Daniel@0 3474 })
Daniel@0 3475 .bind( "keydown" + this.eventNamespace, function(event) {
Daniel@0 3476 if ( options.disabled ) {
Daniel@0 3477 return false;
Daniel@0 3478 }
Daniel@0 3479 if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
Daniel@0 3480 $( this ).addClass( "ui-state-active" );
Daniel@0 3481 }
Daniel@0 3482 })
Daniel@0 3483 // see #8559, we bind to blur here in case the button element loses
Daniel@0 3484 // focus between keydown and keyup, it would be left in an "active" state
Daniel@0 3485 .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
Daniel@0 3486 $( this ).removeClass( "ui-state-active" );
Daniel@0 3487 });
Daniel@0 3488
Daniel@0 3489 if ( this.buttonElement.is("a") ) {
Daniel@0 3490 this.buttonElement.keyup(function(event) {
Daniel@0 3491 if ( event.keyCode === $.ui.keyCode.SPACE ) {
Daniel@0 3492 // TODO pass through original event correctly (just as 2nd argument doesn't work)
Daniel@0 3493 $( this ).click();
Daniel@0 3494 }
Daniel@0 3495 });
Daniel@0 3496 }
Daniel@0 3497 }
Daniel@0 3498
Daniel@0 3499 this._setOption( "disabled", options.disabled );
Daniel@0 3500 this._resetButton();
Daniel@0 3501 },
Daniel@0 3502
Daniel@0 3503 _determineButtonType: function() {
Daniel@0 3504 var ancestor, labelSelector, checked;
Daniel@0 3505
Daniel@0 3506 if ( this.element.is("[type=checkbox]") ) {
Daniel@0 3507 this.type = "checkbox";
Daniel@0 3508 } else if ( this.element.is("[type=radio]") ) {
Daniel@0 3509 this.type = "radio";
Daniel@0 3510 } else if ( this.element.is("input") ) {
Daniel@0 3511 this.type = "input";
Daniel@0 3512 } else {
Daniel@0 3513 this.type = "button";
Daniel@0 3514 }
Daniel@0 3515
Daniel@0 3516 if ( this.type === "checkbox" || this.type === "radio" ) {
Daniel@0 3517 // we don't search against the document in case the element
Daniel@0 3518 // is disconnected from the DOM
Daniel@0 3519 ancestor = this.element.parents().last();
Daniel@0 3520 labelSelector = "label[for='" + this.element.attr("id") + "']";
Daniel@0 3521 this.buttonElement = ancestor.find( labelSelector );
Daniel@0 3522 if ( !this.buttonElement.length ) {
Daniel@0 3523 ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
Daniel@0 3524 this.buttonElement = ancestor.filter( labelSelector );
Daniel@0 3525 if ( !this.buttonElement.length ) {
Daniel@0 3526 this.buttonElement = ancestor.find( labelSelector );
Daniel@0 3527 }
Daniel@0 3528 }
Daniel@0 3529 this.element.addClass( "ui-helper-hidden-accessible" );
Daniel@0 3530
Daniel@0 3531 checked = this.element.is( ":checked" );
Daniel@0 3532 if ( checked ) {
Daniel@0 3533 this.buttonElement.addClass( "ui-state-active" );
Daniel@0 3534 }
Daniel@0 3535 this.buttonElement.prop( "aria-pressed", checked );
Daniel@0 3536 } else {
Daniel@0 3537 this.buttonElement = this.element;
Daniel@0 3538 }
Daniel@0 3539 },
Daniel@0 3540
Daniel@0 3541 widget: function() {
Daniel@0 3542 return this.buttonElement;
Daniel@0 3543 },
Daniel@0 3544
Daniel@0 3545 _destroy: function() {
Daniel@0 3546 this.element
Daniel@0 3547 .removeClass( "ui-helper-hidden-accessible" );
Daniel@0 3548 this.buttonElement
Daniel@0 3549 .removeClass( baseClasses + " ui-state-active " + typeClasses )
Daniel@0 3550 .removeAttr( "role" )
Daniel@0 3551 .removeAttr( "aria-pressed" )
Daniel@0 3552 .html( this.buttonElement.find(".ui-button-text").html() );
Daniel@0 3553
Daniel@0 3554 if ( !this.hasTitle ) {
Daniel@0 3555 this.buttonElement.removeAttr( "title" );
Daniel@0 3556 }
Daniel@0 3557 },
Daniel@0 3558
Daniel@0 3559 _setOption: function( key, value ) {
Daniel@0 3560 this._super( key, value );
Daniel@0 3561 if ( key === "disabled" ) {
Daniel@0 3562 this.widget().toggleClass( "ui-state-disabled", !!value );
Daniel@0 3563 this.element.prop( "disabled", !!value );
Daniel@0 3564 if ( value ) {
Daniel@0 3565 if ( this.type === "checkbox" || this.type === "radio" ) {
Daniel@0 3566 this.buttonElement.removeClass( "ui-state-focus" );
Daniel@0 3567 } else {
Daniel@0 3568 this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
Daniel@0 3569 }
Daniel@0 3570 }
Daniel@0 3571 return;
Daniel@0 3572 }
Daniel@0 3573 this._resetButton();
Daniel@0 3574 },
Daniel@0 3575
Daniel@0 3576 refresh: function() {
Daniel@0 3577 //See #8237 & #8828
Daniel@0 3578 var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
Daniel@0 3579
Daniel@0 3580 if ( isDisabled !== this.options.disabled ) {
Daniel@0 3581 this._setOption( "disabled", isDisabled );
Daniel@0 3582 }
Daniel@0 3583 if ( this.type === "radio" ) {
Daniel@0 3584 radioGroup( this.element[0] ).each(function() {
Daniel@0 3585 if ( $( this ).is( ":checked" ) ) {
Daniel@0 3586 $( this ).button( "widget" )
Daniel@0 3587 .addClass( "ui-state-active" )
Daniel@0 3588 .attr( "aria-pressed", "true" );
Daniel@0 3589 } else {
Daniel@0 3590 $( this ).button( "widget" )
Daniel@0 3591 .removeClass( "ui-state-active" )
Daniel@0 3592 .attr( "aria-pressed", "false" );
Daniel@0 3593 }
Daniel@0 3594 });
Daniel@0 3595 } else if ( this.type === "checkbox" ) {
Daniel@0 3596 if ( this.element.is( ":checked" ) ) {
Daniel@0 3597 this.buttonElement
Daniel@0 3598 .addClass( "ui-state-active" )
Daniel@0 3599 .attr( "aria-pressed", "true" );
Daniel@0 3600 } else {
Daniel@0 3601 this.buttonElement
Daniel@0 3602 .removeClass( "ui-state-active" )
Daniel@0 3603 .attr( "aria-pressed", "false" );
Daniel@0 3604 }
Daniel@0 3605 }
Daniel@0 3606 },
Daniel@0 3607
Daniel@0 3608 _resetButton: function() {
Daniel@0 3609 if ( this.type === "input" ) {
Daniel@0 3610 if ( this.options.label ) {
Daniel@0 3611 this.element.val( this.options.label );
Daniel@0 3612 }
Daniel@0 3613 return;
Daniel@0 3614 }
Daniel@0 3615 var buttonElement = this.buttonElement.removeClass( typeClasses ),
Daniel@0 3616 buttonText = $( "<span></span>", this.document[0] )
Daniel@0 3617 .addClass( "ui-button-text" )
Daniel@0 3618 .html( this.options.label )
Daniel@0 3619 .appendTo( buttonElement.empty() )
Daniel@0 3620 .text(),
Daniel@0 3621 icons = this.options.icons,
Daniel@0 3622 multipleIcons = icons.primary && icons.secondary,
Daniel@0 3623 buttonClasses = [];
Daniel@0 3624
Daniel@0 3625 if ( icons.primary || icons.secondary ) {
Daniel@0 3626 if ( this.options.text ) {
Daniel@0 3627 buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
Daniel@0 3628 }
Daniel@0 3629
Daniel@0 3630 if ( icons.primary ) {
Daniel@0 3631 buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
Daniel@0 3632 }
Daniel@0 3633
Daniel@0 3634 if ( icons.secondary ) {
Daniel@0 3635 buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
Daniel@0 3636 }
Daniel@0 3637
Daniel@0 3638 if ( !this.options.text ) {
Daniel@0 3639 buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
Daniel@0 3640
Daniel@0 3641 if ( !this.hasTitle ) {
Daniel@0 3642 buttonElement.attr( "title", $.trim( buttonText ) );
Daniel@0 3643 }
Daniel@0 3644 }
Daniel@0 3645 } else {
Daniel@0 3646 buttonClasses.push( "ui-button-text-only" );
Daniel@0 3647 }
Daniel@0 3648 buttonElement.addClass( buttonClasses.join( " " ) );
Daniel@0 3649 }
Daniel@0 3650 });
Daniel@0 3651
Daniel@0 3652 $.widget( "ui.buttonset", {
Daniel@0 3653 version: "1.11.0",
Daniel@0 3654 options: {
Daniel@0 3655 items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
Daniel@0 3656 },
Daniel@0 3657
Daniel@0 3658 _create: function() {
Daniel@0 3659 this.element.addClass( "ui-buttonset" );
Daniel@0 3660 },
Daniel@0 3661
Daniel@0 3662 _init: function() {
Daniel@0 3663 this.refresh();
Daniel@0 3664 },
Daniel@0 3665
Daniel@0 3666 _setOption: function( key, value ) {
Daniel@0 3667 if ( key === "disabled" ) {
Daniel@0 3668 this.buttons.button( "option", key, value );
Daniel@0 3669 }
Daniel@0 3670
Daniel@0 3671 this._super( key, value );
Daniel@0 3672 },
Daniel@0 3673
Daniel@0 3674 refresh: function() {
Daniel@0 3675 var rtl = this.element.css( "direction" ) === "rtl",
Daniel@0 3676 allButtons = this.element.find( this.options.items ),
Daniel@0 3677 existingButtons = allButtons.filter( ":ui-button" );
Daniel@0 3678
Daniel@0 3679 // Initialize new buttons
Daniel@0 3680 allButtons.not( ":ui-button" ).button();
Daniel@0 3681
Daniel@0 3682 // Refresh existing buttons
Daniel@0 3683 existingButtons.button( "refresh" );
Daniel@0 3684
Daniel@0 3685 this.buttons = allButtons
Daniel@0 3686 .map(function() {
Daniel@0 3687 return $( this ).button( "widget" )[ 0 ];
Daniel@0 3688 })
Daniel@0 3689 .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
Daniel@0 3690 .filter( ":first" )
Daniel@0 3691 .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
Daniel@0 3692 .end()
Daniel@0 3693 .filter( ":last" )
Daniel@0 3694 .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
Daniel@0 3695 .end()
Daniel@0 3696 .end();
Daniel@0 3697 },
Daniel@0 3698
Daniel@0 3699 _destroy: function() {
Daniel@0 3700 this.element.removeClass( "ui-buttonset" );
Daniel@0 3701 this.buttons
Daniel@0 3702 .map(function() {
Daniel@0 3703 return $( this ).button( "widget" )[ 0 ];
Daniel@0 3704 })
Daniel@0 3705 .removeClass( "ui-corner-left ui-corner-right" )
Daniel@0 3706 .end()
Daniel@0 3707 .button( "destroy" );
Daniel@0 3708 }
Daniel@0 3709 });
Daniel@0 3710
Daniel@0 3711 var button = $.ui.button;
Daniel@0 3712
Daniel@0 3713
Daniel@0 3714 /*!
Daniel@0 3715 * jQuery UI Datepicker 1.11.0
Daniel@0 3716 * http://jqueryui.com
Daniel@0 3717 *
Daniel@0 3718 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 3719 * Released under the MIT license.
Daniel@0 3720 * http://jquery.org/license
Daniel@0 3721 *
Daniel@0 3722 * http://api.jqueryui.com/datepicker/
Daniel@0 3723 */
Daniel@0 3724
Daniel@0 3725
Daniel@0 3726 $.extend($.ui, { datepicker: { version: "1.11.0" } });
Daniel@0 3727
Daniel@0 3728 var datepicker_instActive;
Daniel@0 3729
Daniel@0 3730 function datepicker_getZindex( elem ) {
Daniel@0 3731 var position, value;
Daniel@0 3732 while ( elem.length && elem[ 0 ] !== document ) {
Daniel@0 3733 // Ignore z-index if position is set to a value where z-index is ignored by the browser
Daniel@0 3734 // This makes behavior of this function consistent across browsers
Daniel@0 3735 // WebKit always returns auto if the element is positioned
Daniel@0 3736 position = elem.css( "position" );
Daniel@0 3737 if ( position === "absolute" || position === "relative" || position === "fixed" ) {
Daniel@0 3738 // IE returns 0 when zIndex is not specified
Daniel@0 3739 // other browsers return a string
Daniel@0 3740 // we ignore the case of nested elements with an explicit value of 0
Daniel@0 3741 // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
Daniel@0 3742 value = parseInt( elem.css( "zIndex" ), 10 );
Daniel@0 3743 if ( !isNaN( value ) && value !== 0 ) {
Daniel@0 3744 return value;
Daniel@0 3745 }
Daniel@0 3746 }
Daniel@0 3747 elem = elem.parent();
Daniel@0 3748 }
Daniel@0 3749
Daniel@0 3750 return 0;
Daniel@0 3751 }
Daniel@0 3752 /* Date picker manager.
Daniel@0 3753 Use the singleton instance of this class, $.datepicker, to interact with the date picker.
Daniel@0 3754 Settings for (groups of) date pickers are maintained in an instance object,
Daniel@0 3755 allowing multiple different settings on the same page. */
Daniel@0 3756
Daniel@0 3757 function Datepicker() {
Daniel@0 3758 this._curInst = null; // The current instance in use
Daniel@0 3759 this._keyEvent = false; // If the last event was a key event
Daniel@0 3760 this._disabledInputs = []; // List of date picker inputs that have been disabled
Daniel@0 3761 this._datepickerShowing = false; // True if the popup picker is showing , false if not
Daniel@0 3762 this._inDialog = false; // True if showing within a "dialog", false if not
Daniel@0 3763 this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
Daniel@0 3764 this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
Daniel@0 3765 this._appendClass = "ui-datepicker-append"; // The name of the append marker class
Daniel@0 3766 this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
Daniel@0 3767 this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
Daniel@0 3768 this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
Daniel@0 3769 this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
Daniel@0 3770 this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
Daniel@0 3771 this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
Daniel@0 3772 this.regional = []; // Available regional settings, indexed by language code
Daniel@0 3773 this.regional[""] = { // Default regional settings
Daniel@0 3774 closeText: "Done", // Display text for close link
Daniel@0 3775 prevText: "Prev", // Display text for previous month link
Daniel@0 3776 nextText: "Next", // Display text for next month link
Daniel@0 3777 currentText: "Today", // Display text for current month link
Daniel@0 3778 monthNames: ["January","February","March","April","May","June",
Daniel@0 3779 "July","August","September","October","November","December"], // Names of months for drop-down and formatting
Daniel@0 3780 monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
Daniel@0 3781 dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
Daniel@0 3782 dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
Daniel@0 3783 dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
Daniel@0 3784 weekHeader: "Wk", // Column header for week of the year
Daniel@0 3785 dateFormat: "mm/dd/yy", // See format options on parseDate
Daniel@0 3786 firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
Daniel@0 3787 isRTL: false, // True if right-to-left language, false if left-to-right
Daniel@0 3788 showMonthAfterYear: false, // True if the year select precedes month, false for month then year
Daniel@0 3789 yearSuffix: "" // Additional text to append to the year in the month headers
Daniel@0 3790 };
Daniel@0 3791 this._defaults = { // Global defaults for all the date picker instances
Daniel@0 3792 showOn: "focus", // "focus" for popup on focus,
Daniel@0 3793 // "button" for trigger button, or "both" for either
Daniel@0 3794 showAnim: "fadeIn", // Name of jQuery animation for popup
Daniel@0 3795 showOptions: {}, // Options for enhanced animations
Daniel@0 3796 defaultDate: null, // Used when field is blank: actual date,
Daniel@0 3797 // +/-number for offset from today, null for today
Daniel@0 3798 appendText: "", // Display text following the input box, e.g. showing the format
Daniel@0 3799 buttonText: "...", // Text for trigger button
Daniel@0 3800 buttonImage: "", // URL for trigger button image
Daniel@0 3801 buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
Daniel@0 3802 hideIfNoPrevNext: false, // True to hide next/previous month links
Daniel@0 3803 // if not applicable, false to just disable them
Daniel@0 3804 navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
Daniel@0 3805 gotoCurrent: false, // True if today link goes back to current selection instead
Daniel@0 3806 changeMonth: false, // True if month can be selected directly, false if only prev/next
Daniel@0 3807 changeYear: false, // True if year can be selected directly, false if only prev/next
Daniel@0 3808 yearRange: "c-10:c+10", // Range of years to display in drop-down,
Daniel@0 3809 // either relative to today's year (-nn:+nn), relative to currently displayed year
Daniel@0 3810 // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
Daniel@0 3811 showOtherMonths: false, // True to show dates in other months, false to leave blank
Daniel@0 3812 selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
Daniel@0 3813 showWeek: false, // True to show week of the year, false to not show it
Daniel@0 3814 calculateWeek: this.iso8601Week, // How to calculate the week of the year,
Daniel@0 3815 // takes a Date and returns the number of the week for it
Daniel@0 3816 shortYearCutoff: "+10", // Short year values < this are in the current century,
Daniel@0 3817 // > this are in the previous century,
Daniel@0 3818 // string value starting with "+" for current year + value
Daniel@0 3819 minDate: null, // The earliest selectable date, or null for no limit
Daniel@0 3820 maxDate: null, // The latest selectable date, or null for no limit
Daniel@0 3821 duration: "fast", // Duration of display/closure
Daniel@0 3822 beforeShowDay: null, // Function that takes a date and returns an array with
Daniel@0 3823 // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
Daniel@0 3824 // [2] = cell title (optional), e.g. $.datepicker.noWeekends
Daniel@0 3825 beforeShow: null, // Function that takes an input field and
Daniel@0 3826 // returns a set of custom settings for the date picker
Daniel@0 3827 onSelect: null, // Define a callback function when a date is selected
Daniel@0 3828 onChangeMonthYear: null, // Define a callback function when the month or year is changed
Daniel@0 3829 onClose: null, // Define a callback function when the datepicker is closed
Daniel@0 3830 numberOfMonths: 1, // Number of months to show at a time
Daniel@0 3831 showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
Daniel@0 3832 stepMonths: 1, // Number of months to step back/forward
Daniel@0 3833 stepBigMonths: 12, // Number of months to step back/forward for the big links
Daniel@0 3834 altField: "", // Selector for an alternate field to store selected dates into
Daniel@0 3835 altFormat: "", // The date format to use for the alternate field
Daniel@0 3836 constrainInput: true, // The input is constrained by the current date format
Daniel@0 3837 showButtonPanel: false, // True to show button panel, false to not show it
Daniel@0 3838 autoSize: false, // True to size the input for the date format, false to leave as is
Daniel@0 3839 disabled: false // The initial disabled state
Daniel@0 3840 };
Daniel@0 3841 $.extend(this._defaults, this.regional[""]);
Daniel@0 3842 this.regional.en = $.extend( true, {}, this.regional[ "" ]);
Daniel@0 3843 this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
Daniel@0 3844 this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
Daniel@0 3845 }
Daniel@0 3846
Daniel@0 3847 $.extend(Datepicker.prototype, {
Daniel@0 3848 /* Class name added to elements to indicate already configured with a date picker. */
Daniel@0 3849 markerClassName: "hasDatepicker",
Daniel@0 3850
Daniel@0 3851 //Keep track of the maximum number of rows displayed (see #7043)
Daniel@0 3852 maxRows: 4,
Daniel@0 3853
Daniel@0 3854 // TODO rename to "widget" when switching to widget factory
Daniel@0 3855 _widgetDatepicker: function() {
Daniel@0 3856 return this.dpDiv;
Daniel@0 3857 },
Daniel@0 3858
Daniel@0 3859 /* Override the default settings for all instances of the date picker.
Daniel@0 3860 * @param settings object - the new settings to use as defaults (anonymous object)
Daniel@0 3861 * @return the manager object
Daniel@0 3862 */
Daniel@0 3863 setDefaults: function(settings) {
Daniel@0 3864 datepicker_extendRemove(this._defaults, settings || {});
Daniel@0 3865 return this;
Daniel@0 3866 },
Daniel@0 3867
Daniel@0 3868 /* Attach the date picker to a jQuery selection.
Daniel@0 3869 * @param target element - the target input field or division or span
Daniel@0 3870 * @param settings object - the new settings to use for this date picker instance (anonymous)
Daniel@0 3871 */
Daniel@0 3872 _attachDatepicker: function(target, settings) {
Daniel@0 3873 var nodeName, inline, inst;
Daniel@0 3874 nodeName = target.nodeName.toLowerCase();
Daniel@0 3875 inline = (nodeName === "div" || nodeName === "span");
Daniel@0 3876 if (!target.id) {
Daniel@0 3877 this.uuid += 1;
Daniel@0 3878 target.id = "dp" + this.uuid;
Daniel@0 3879 }
Daniel@0 3880 inst = this._newInst($(target), inline);
Daniel@0 3881 inst.settings = $.extend({}, settings || {});
Daniel@0 3882 if (nodeName === "input") {
Daniel@0 3883 this._connectDatepicker(target, inst);
Daniel@0 3884 } else if (inline) {
Daniel@0 3885 this._inlineDatepicker(target, inst);
Daniel@0 3886 }
Daniel@0 3887 },
Daniel@0 3888
Daniel@0 3889 /* Create a new instance object. */
Daniel@0 3890 _newInst: function(target, inline) {
Daniel@0 3891 var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
Daniel@0 3892 return {id: id, input: target, // associated target
Daniel@0 3893 selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
Daniel@0 3894 drawMonth: 0, drawYear: 0, // month being drawn
Daniel@0 3895 inline: inline, // is datepicker inline or not
Daniel@0 3896 dpDiv: (!inline ? this.dpDiv : // presentation div
Daniel@0 3897 datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
Daniel@0 3898 },
Daniel@0 3899
Daniel@0 3900 /* Attach the date picker to an input field. */
Daniel@0 3901 _connectDatepicker: function(target, inst) {
Daniel@0 3902 var input = $(target);
Daniel@0 3903 inst.append = $([]);
Daniel@0 3904 inst.trigger = $([]);
Daniel@0 3905 if (input.hasClass(this.markerClassName)) {
Daniel@0 3906 return;
Daniel@0 3907 }
Daniel@0 3908 this._attachments(input, inst);
Daniel@0 3909 input.addClass(this.markerClassName).keydown(this._doKeyDown).
Daniel@0 3910 keypress(this._doKeyPress).keyup(this._doKeyUp);
Daniel@0 3911 this._autoSize(inst);
Daniel@0 3912 $.data(target, "datepicker", inst);
Daniel@0 3913 //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
Daniel@0 3914 if( inst.settings.disabled ) {
Daniel@0 3915 this._disableDatepicker( target );
Daniel@0 3916 }
Daniel@0 3917 },
Daniel@0 3918
Daniel@0 3919 /* Make attachments based on settings. */
Daniel@0 3920 _attachments: function(input, inst) {
Daniel@0 3921 var showOn, buttonText, buttonImage,
Daniel@0 3922 appendText = this._get(inst, "appendText"),
Daniel@0 3923 isRTL = this._get(inst, "isRTL");
Daniel@0 3924
Daniel@0 3925 if (inst.append) {
Daniel@0 3926 inst.append.remove();
Daniel@0 3927 }
Daniel@0 3928 if (appendText) {
Daniel@0 3929 inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
Daniel@0 3930 input[isRTL ? "before" : "after"](inst.append);
Daniel@0 3931 }
Daniel@0 3932
Daniel@0 3933 input.unbind("focus", this._showDatepicker);
Daniel@0 3934
Daniel@0 3935 if (inst.trigger) {
Daniel@0 3936 inst.trigger.remove();
Daniel@0 3937 }
Daniel@0 3938
Daniel@0 3939 showOn = this._get(inst, "showOn");
Daniel@0 3940 if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
Daniel@0 3941 input.focus(this._showDatepicker);
Daniel@0 3942 }
Daniel@0 3943 if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
Daniel@0 3944 buttonText = this._get(inst, "buttonText");
Daniel@0 3945 buttonImage = this._get(inst, "buttonImage");
Daniel@0 3946 inst.trigger = $(this._get(inst, "buttonImageOnly") ?
Daniel@0 3947 $("<img/>").addClass(this._triggerClass).
Daniel@0 3948 attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
Daniel@0 3949 $("<button type='button'></button>").addClass(this._triggerClass).
Daniel@0 3950 html(!buttonImage ? buttonText : $("<img/>").attr(
Daniel@0 3951 { src:buttonImage, alt:buttonText, title:buttonText })));
Daniel@0 3952 input[isRTL ? "before" : "after"](inst.trigger);
Daniel@0 3953 inst.trigger.click(function() {
Daniel@0 3954 if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
Daniel@0 3955 $.datepicker._hideDatepicker();
Daniel@0 3956 } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
Daniel@0 3957 $.datepicker._hideDatepicker();
Daniel@0 3958 $.datepicker._showDatepicker(input[0]);
Daniel@0 3959 } else {
Daniel@0 3960 $.datepicker._showDatepicker(input[0]);
Daniel@0 3961 }
Daniel@0 3962 return false;
Daniel@0 3963 });
Daniel@0 3964 }
Daniel@0 3965 },
Daniel@0 3966
Daniel@0 3967 /* Apply the maximum length for the date format. */
Daniel@0 3968 _autoSize: function(inst) {
Daniel@0 3969 if (this._get(inst, "autoSize") && !inst.inline) {
Daniel@0 3970 var findMax, max, maxI, i,
Daniel@0 3971 date = new Date(2009, 12 - 1, 20), // Ensure double digits
Daniel@0 3972 dateFormat = this._get(inst, "dateFormat");
Daniel@0 3973
Daniel@0 3974 if (dateFormat.match(/[DM]/)) {
Daniel@0 3975 findMax = function(names) {
Daniel@0 3976 max = 0;
Daniel@0 3977 maxI = 0;
Daniel@0 3978 for (i = 0; i < names.length; i++) {
Daniel@0 3979 if (names[i].length > max) {
Daniel@0 3980 max = names[i].length;
Daniel@0 3981 maxI = i;
Daniel@0 3982 }
Daniel@0 3983 }
Daniel@0 3984 return maxI;
Daniel@0 3985 };
Daniel@0 3986 date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
Daniel@0 3987 "monthNames" : "monthNamesShort"))));
Daniel@0 3988 date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
Daniel@0 3989 "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
Daniel@0 3990 }
Daniel@0 3991 inst.input.attr("size", this._formatDate(inst, date).length);
Daniel@0 3992 }
Daniel@0 3993 },
Daniel@0 3994
Daniel@0 3995 /* Attach an inline date picker to a div. */
Daniel@0 3996 _inlineDatepicker: function(target, inst) {
Daniel@0 3997 var divSpan = $(target);
Daniel@0 3998 if (divSpan.hasClass(this.markerClassName)) {
Daniel@0 3999 return;
Daniel@0 4000 }
Daniel@0 4001 divSpan.addClass(this.markerClassName).append(inst.dpDiv);
Daniel@0 4002 $.data(target, "datepicker", inst);
Daniel@0 4003 this._setDate(inst, this._getDefaultDate(inst), true);
Daniel@0 4004 this._updateDatepicker(inst);
Daniel@0 4005 this._updateAlternate(inst);
Daniel@0 4006 //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
Daniel@0 4007 if( inst.settings.disabled ) {
Daniel@0 4008 this._disableDatepicker( target );
Daniel@0 4009 }
Daniel@0 4010 // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
Daniel@0 4011 // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
Daniel@0 4012 inst.dpDiv.css( "display", "block" );
Daniel@0 4013 },
Daniel@0 4014
Daniel@0 4015 /* Pop-up the date picker in a "dialog" box.
Daniel@0 4016 * @param input element - ignored
Daniel@0 4017 * @param date string or Date - the initial date to display
Daniel@0 4018 * @param onSelect function - the function to call when a date is selected
Daniel@0 4019 * @param settings object - update the dialog date picker instance's settings (anonymous object)
Daniel@0 4020 * @param pos int[2] - coordinates for the dialog's position within the screen or
Daniel@0 4021 * event - with x/y coordinates or
Daniel@0 4022 * leave empty for default (screen centre)
Daniel@0 4023 * @return the manager object
Daniel@0 4024 */
Daniel@0 4025 _dialogDatepicker: function(input, date, onSelect, settings, pos) {
Daniel@0 4026 var id, browserWidth, browserHeight, scrollX, scrollY,
Daniel@0 4027 inst = this._dialogInst; // internal instance
Daniel@0 4028
Daniel@0 4029 if (!inst) {
Daniel@0 4030 this.uuid += 1;
Daniel@0 4031 id = "dp" + this.uuid;
Daniel@0 4032 this._dialogInput = $("<input type='text' id='" + id +
Daniel@0 4033 "' style='position: absolute; top: -100px; width: 0px;'/>");
Daniel@0 4034 this._dialogInput.keydown(this._doKeyDown);
Daniel@0 4035 $("body").append(this._dialogInput);
Daniel@0 4036 inst = this._dialogInst = this._newInst(this._dialogInput, false);
Daniel@0 4037 inst.settings = {};
Daniel@0 4038 $.data(this._dialogInput[0], "datepicker", inst);
Daniel@0 4039 }
Daniel@0 4040 datepicker_extendRemove(inst.settings, settings || {});
Daniel@0 4041 date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
Daniel@0 4042 this._dialogInput.val(date);
Daniel@0 4043
Daniel@0 4044 this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
Daniel@0 4045 if (!this._pos) {
Daniel@0 4046 browserWidth = document.documentElement.clientWidth;
Daniel@0 4047 browserHeight = document.documentElement.clientHeight;
Daniel@0 4048 scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
Daniel@0 4049 scrollY = document.documentElement.scrollTop || document.body.scrollTop;
Daniel@0 4050 this._pos = // should use actual width/height below
Daniel@0 4051 [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
Daniel@0 4052 }
Daniel@0 4053
Daniel@0 4054 // move input on screen for focus, but hidden behind dialog
Daniel@0 4055 this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
Daniel@0 4056 inst.settings.onSelect = onSelect;
Daniel@0 4057 this._inDialog = true;
Daniel@0 4058 this.dpDiv.addClass(this._dialogClass);
Daniel@0 4059 this._showDatepicker(this._dialogInput[0]);
Daniel@0 4060 if ($.blockUI) {
Daniel@0 4061 $.blockUI(this.dpDiv);
Daniel@0 4062 }
Daniel@0 4063 $.data(this._dialogInput[0], "datepicker", inst);
Daniel@0 4064 return this;
Daniel@0 4065 },
Daniel@0 4066
Daniel@0 4067 /* Detach a datepicker from its control.
Daniel@0 4068 * @param target element - the target input field or division or span
Daniel@0 4069 */
Daniel@0 4070 _destroyDatepicker: function(target) {
Daniel@0 4071 var nodeName,
Daniel@0 4072 $target = $(target),
Daniel@0 4073 inst = $.data(target, "datepicker");
Daniel@0 4074
Daniel@0 4075 if (!$target.hasClass(this.markerClassName)) {
Daniel@0 4076 return;
Daniel@0 4077 }
Daniel@0 4078
Daniel@0 4079 nodeName = target.nodeName.toLowerCase();
Daniel@0 4080 $.removeData(target, "datepicker");
Daniel@0 4081 if (nodeName === "input") {
Daniel@0 4082 inst.append.remove();
Daniel@0 4083 inst.trigger.remove();
Daniel@0 4084 $target.removeClass(this.markerClassName).
Daniel@0 4085 unbind("focus", this._showDatepicker).
Daniel@0 4086 unbind("keydown", this._doKeyDown).
Daniel@0 4087 unbind("keypress", this._doKeyPress).
Daniel@0 4088 unbind("keyup", this._doKeyUp);
Daniel@0 4089 } else if (nodeName === "div" || nodeName === "span") {
Daniel@0 4090 $target.removeClass(this.markerClassName).empty();
Daniel@0 4091 }
Daniel@0 4092 },
Daniel@0 4093
Daniel@0 4094 /* Enable the date picker to a jQuery selection.
Daniel@0 4095 * @param target element - the target input field or division or span
Daniel@0 4096 */
Daniel@0 4097 _enableDatepicker: function(target) {
Daniel@0 4098 var nodeName, inline,
Daniel@0 4099 $target = $(target),
Daniel@0 4100 inst = $.data(target, "datepicker");
Daniel@0 4101
Daniel@0 4102 if (!$target.hasClass(this.markerClassName)) {
Daniel@0 4103 return;
Daniel@0 4104 }
Daniel@0 4105
Daniel@0 4106 nodeName = target.nodeName.toLowerCase();
Daniel@0 4107 if (nodeName === "input") {
Daniel@0 4108 target.disabled = false;
Daniel@0 4109 inst.trigger.filter("button").
Daniel@0 4110 each(function() { this.disabled = false; }).end().
Daniel@0 4111 filter("img").css({opacity: "1.0", cursor: ""});
Daniel@0 4112 } else if (nodeName === "div" || nodeName === "span") {
Daniel@0 4113 inline = $target.children("." + this._inlineClass);
Daniel@0 4114 inline.children().removeClass("ui-state-disabled");
Daniel@0 4115 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
Daniel@0 4116 prop("disabled", false);
Daniel@0 4117 }
Daniel@0 4118 this._disabledInputs = $.map(this._disabledInputs,
Daniel@0 4119 function(value) { return (value === target ? null : value); }); // delete entry
Daniel@0 4120 },
Daniel@0 4121
Daniel@0 4122 /* Disable the date picker to a jQuery selection.
Daniel@0 4123 * @param target element - the target input field or division or span
Daniel@0 4124 */
Daniel@0 4125 _disableDatepicker: function(target) {
Daniel@0 4126 var nodeName, inline,
Daniel@0 4127 $target = $(target),
Daniel@0 4128 inst = $.data(target, "datepicker");
Daniel@0 4129
Daniel@0 4130 if (!$target.hasClass(this.markerClassName)) {
Daniel@0 4131 return;
Daniel@0 4132 }
Daniel@0 4133
Daniel@0 4134 nodeName = target.nodeName.toLowerCase();
Daniel@0 4135 if (nodeName === "input") {
Daniel@0 4136 target.disabled = true;
Daniel@0 4137 inst.trigger.filter("button").
Daniel@0 4138 each(function() { this.disabled = true; }).end().
Daniel@0 4139 filter("img").css({opacity: "0.5", cursor: "default"});
Daniel@0 4140 } else if (nodeName === "div" || nodeName === "span") {
Daniel@0 4141 inline = $target.children("." + this._inlineClass);
Daniel@0 4142 inline.children().addClass("ui-state-disabled");
Daniel@0 4143 inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
Daniel@0 4144 prop("disabled", true);
Daniel@0 4145 }
Daniel@0 4146 this._disabledInputs = $.map(this._disabledInputs,
Daniel@0 4147 function(value) { return (value === target ? null : value); }); // delete entry
Daniel@0 4148 this._disabledInputs[this._disabledInputs.length] = target;
Daniel@0 4149 },
Daniel@0 4150
Daniel@0 4151 /* Is the first field in a jQuery collection disabled as a datepicker?
Daniel@0 4152 * @param target element - the target input field or division or span
Daniel@0 4153 * @return boolean - true if disabled, false if enabled
Daniel@0 4154 */
Daniel@0 4155 _isDisabledDatepicker: function(target) {
Daniel@0 4156 if (!target) {
Daniel@0 4157 return false;
Daniel@0 4158 }
Daniel@0 4159 for (var i = 0; i < this._disabledInputs.length; i++) {
Daniel@0 4160 if (this._disabledInputs[i] === target) {
Daniel@0 4161 return true;
Daniel@0 4162 }
Daniel@0 4163 }
Daniel@0 4164 return false;
Daniel@0 4165 },
Daniel@0 4166
Daniel@0 4167 /* Retrieve the instance data for the target control.
Daniel@0 4168 * @param target element - the target input field or division or span
Daniel@0 4169 * @return object - the associated instance data
Daniel@0 4170 * @throws error if a jQuery problem getting data
Daniel@0 4171 */
Daniel@0 4172 _getInst: function(target) {
Daniel@0 4173 try {
Daniel@0 4174 return $.data(target, "datepicker");
Daniel@0 4175 }
Daniel@0 4176 catch (err) {
Daniel@0 4177 throw "Missing instance data for this datepicker";
Daniel@0 4178 }
Daniel@0 4179 },
Daniel@0 4180
Daniel@0 4181 /* Update or retrieve the settings for a date picker attached to an input field or division.
Daniel@0 4182 * @param target element - the target input field or division or span
Daniel@0 4183 * @param name object - the new settings to update or
Daniel@0 4184 * string - the name of the setting to change or retrieve,
Daniel@0 4185 * when retrieving also "all" for all instance settings or
Daniel@0 4186 * "defaults" for all global defaults
Daniel@0 4187 * @param value any - the new value for the setting
Daniel@0 4188 * (omit if above is an object or to retrieve a value)
Daniel@0 4189 */
Daniel@0 4190 _optionDatepicker: function(target, name, value) {
Daniel@0 4191 var settings, date, minDate, maxDate,
Daniel@0 4192 inst = this._getInst(target);
Daniel@0 4193
Daniel@0 4194 if (arguments.length === 2 && typeof name === "string") {
Daniel@0 4195 return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
Daniel@0 4196 (inst ? (name === "all" ? $.extend({}, inst.settings) :
Daniel@0 4197 this._get(inst, name)) : null));
Daniel@0 4198 }
Daniel@0 4199
Daniel@0 4200 settings = name || {};
Daniel@0 4201 if (typeof name === "string") {
Daniel@0 4202 settings = {};
Daniel@0 4203 settings[name] = value;
Daniel@0 4204 }
Daniel@0 4205
Daniel@0 4206 if (inst) {
Daniel@0 4207 if (this._curInst === inst) {
Daniel@0 4208 this._hideDatepicker();
Daniel@0 4209 }
Daniel@0 4210
Daniel@0 4211 date = this._getDateDatepicker(target, true);
Daniel@0 4212 minDate = this._getMinMaxDate(inst, "min");
Daniel@0 4213 maxDate = this._getMinMaxDate(inst, "max");
Daniel@0 4214 datepicker_extendRemove(inst.settings, settings);
Daniel@0 4215 // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
Daniel@0 4216 if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
Daniel@0 4217 inst.settings.minDate = this._formatDate(inst, minDate);
Daniel@0 4218 }
Daniel@0 4219 if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
Daniel@0 4220 inst.settings.maxDate = this._formatDate(inst, maxDate);
Daniel@0 4221 }
Daniel@0 4222 if ( "disabled" in settings ) {
Daniel@0 4223 if ( settings.disabled ) {
Daniel@0 4224 this._disableDatepicker(target);
Daniel@0 4225 } else {
Daniel@0 4226 this._enableDatepicker(target);
Daniel@0 4227 }
Daniel@0 4228 }
Daniel@0 4229 this._attachments($(target), inst);
Daniel@0 4230 this._autoSize(inst);
Daniel@0 4231 this._setDate(inst, date);
Daniel@0 4232 this._updateAlternate(inst);
Daniel@0 4233 this._updateDatepicker(inst);
Daniel@0 4234 }
Daniel@0 4235 },
Daniel@0 4236
Daniel@0 4237 // change method deprecated
Daniel@0 4238 _changeDatepicker: function(target, name, value) {
Daniel@0 4239 this._optionDatepicker(target, name, value);
Daniel@0 4240 },
Daniel@0 4241
Daniel@0 4242 /* Redraw the date picker attached to an input field or division.
Daniel@0 4243 * @param target element - the target input field or division or span
Daniel@0 4244 */
Daniel@0 4245 _refreshDatepicker: function(target) {
Daniel@0 4246 var inst = this._getInst(target);
Daniel@0 4247 if (inst) {
Daniel@0 4248 this._updateDatepicker(inst);
Daniel@0 4249 }
Daniel@0 4250 },
Daniel@0 4251
Daniel@0 4252 /* Set the dates for a jQuery selection.
Daniel@0 4253 * @param target element - the target input field or division or span
Daniel@0 4254 * @param date Date - the new date
Daniel@0 4255 */
Daniel@0 4256 _setDateDatepicker: function(target, date) {
Daniel@0 4257 var inst = this._getInst(target);
Daniel@0 4258 if (inst) {
Daniel@0 4259 this._setDate(inst, date);
Daniel@0 4260 this._updateDatepicker(inst);
Daniel@0 4261 this._updateAlternate(inst);
Daniel@0 4262 }
Daniel@0 4263 },
Daniel@0 4264
Daniel@0 4265 /* Get the date(s) for the first entry in a jQuery selection.
Daniel@0 4266 * @param target element - the target input field or division or span
Daniel@0 4267 * @param noDefault boolean - true if no default date is to be used
Daniel@0 4268 * @return Date - the current date
Daniel@0 4269 */
Daniel@0 4270 _getDateDatepicker: function(target, noDefault) {
Daniel@0 4271 var inst = this._getInst(target);
Daniel@0 4272 if (inst && !inst.inline) {
Daniel@0 4273 this._setDateFromField(inst, noDefault);
Daniel@0 4274 }
Daniel@0 4275 return (inst ? this._getDate(inst) : null);
Daniel@0 4276 },
Daniel@0 4277
Daniel@0 4278 /* Handle keystrokes. */
Daniel@0 4279 _doKeyDown: function(event) {
Daniel@0 4280 var onSelect, dateStr, sel,
Daniel@0 4281 inst = $.datepicker._getInst(event.target),
Daniel@0 4282 handled = true,
Daniel@0 4283 isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
Daniel@0 4284
Daniel@0 4285 inst._keyEvent = true;
Daniel@0 4286 if ($.datepicker._datepickerShowing) {
Daniel@0 4287 switch (event.keyCode) {
Daniel@0 4288 case 9: $.datepicker._hideDatepicker();
Daniel@0 4289 handled = false;
Daniel@0 4290 break; // hide on tab out
Daniel@0 4291 case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
Daniel@0 4292 $.datepicker._currentClass + ")", inst.dpDiv);
Daniel@0 4293 if (sel[0]) {
Daniel@0 4294 $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
Daniel@0 4295 }
Daniel@0 4296
Daniel@0 4297 onSelect = $.datepicker._get(inst, "onSelect");
Daniel@0 4298 if (onSelect) {
Daniel@0 4299 dateStr = $.datepicker._formatDate(inst);
Daniel@0 4300
Daniel@0 4301 // trigger custom callback
Daniel@0 4302 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
Daniel@0 4303 } else {
Daniel@0 4304 $.datepicker._hideDatepicker();
Daniel@0 4305 }
Daniel@0 4306
Daniel@0 4307 return false; // don't submit the form
Daniel@0 4308 case 27: $.datepicker._hideDatepicker();
Daniel@0 4309 break; // hide on escape
Daniel@0 4310 case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
Daniel@0 4311 -$.datepicker._get(inst, "stepBigMonths") :
Daniel@0 4312 -$.datepicker._get(inst, "stepMonths")), "M");
Daniel@0 4313 break; // previous month/year on page up/+ ctrl
Daniel@0 4314 case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
Daniel@0 4315 +$.datepicker._get(inst, "stepBigMonths") :
Daniel@0 4316 +$.datepicker._get(inst, "stepMonths")), "M");
Daniel@0 4317 break; // next month/year on page down/+ ctrl
Daniel@0 4318 case 35: if (event.ctrlKey || event.metaKey) {
Daniel@0 4319 $.datepicker._clearDate(event.target);
Daniel@0 4320 }
Daniel@0 4321 handled = event.ctrlKey || event.metaKey;
Daniel@0 4322 break; // clear on ctrl or command +end
Daniel@0 4323 case 36: if (event.ctrlKey || event.metaKey) {
Daniel@0 4324 $.datepicker._gotoToday(event.target);
Daniel@0 4325 }
Daniel@0 4326 handled = event.ctrlKey || event.metaKey;
Daniel@0 4327 break; // current on ctrl or command +home
Daniel@0 4328 case 37: if (event.ctrlKey || event.metaKey) {
Daniel@0 4329 $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
Daniel@0 4330 }
Daniel@0 4331 handled = event.ctrlKey || event.metaKey;
Daniel@0 4332 // -1 day on ctrl or command +left
Daniel@0 4333 if (event.originalEvent.altKey) {
Daniel@0 4334 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
Daniel@0 4335 -$.datepicker._get(inst, "stepBigMonths") :
Daniel@0 4336 -$.datepicker._get(inst, "stepMonths")), "M");
Daniel@0 4337 }
Daniel@0 4338 // next month/year on alt +left on Mac
Daniel@0 4339 break;
Daniel@0 4340 case 38: if (event.ctrlKey || event.metaKey) {
Daniel@0 4341 $.datepicker._adjustDate(event.target, -7, "D");
Daniel@0 4342 }
Daniel@0 4343 handled = event.ctrlKey || event.metaKey;
Daniel@0 4344 break; // -1 week on ctrl or command +up
Daniel@0 4345 case 39: if (event.ctrlKey || event.metaKey) {
Daniel@0 4346 $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
Daniel@0 4347 }
Daniel@0 4348 handled = event.ctrlKey || event.metaKey;
Daniel@0 4349 // +1 day on ctrl or command +right
Daniel@0 4350 if (event.originalEvent.altKey) {
Daniel@0 4351 $.datepicker._adjustDate(event.target, (event.ctrlKey ?
Daniel@0 4352 +$.datepicker._get(inst, "stepBigMonths") :
Daniel@0 4353 +$.datepicker._get(inst, "stepMonths")), "M");
Daniel@0 4354 }
Daniel@0 4355 // next month/year on alt +right
Daniel@0 4356 break;
Daniel@0 4357 case 40: if (event.ctrlKey || event.metaKey) {
Daniel@0 4358 $.datepicker._adjustDate(event.target, +7, "D");
Daniel@0 4359 }
Daniel@0 4360 handled = event.ctrlKey || event.metaKey;
Daniel@0 4361 break; // +1 week on ctrl or command +down
Daniel@0 4362 default: handled = false;
Daniel@0 4363 }
Daniel@0 4364 } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
Daniel@0 4365 $.datepicker._showDatepicker(this);
Daniel@0 4366 } else {
Daniel@0 4367 handled = false;
Daniel@0 4368 }
Daniel@0 4369
Daniel@0 4370 if (handled) {
Daniel@0 4371 event.preventDefault();
Daniel@0 4372 event.stopPropagation();
Daniel@0 4373 }
Daniel@0 4374 },
Daniel@0 4375
Daniel@0 4376 /* Filter entered characters - based on date format. */
Daniel@0 4377 _doKeyPress: function(event) {
Daniel@0 4378 var chars, chr,
Daniel@0 4379 inst = $.datepicker._getInst(event.target);
Daniel@0 4380
Daniel@0 4381 if ($.datepicker._get(inst, "constrainInput")) {
Daniel@0 4382 chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
Daniel@0 4383 chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
Daniel@0 4384 return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
Daniel@0 4385 }
Daniel@0 4386 },
Daniel@0 4387
Daniel@0 4388 /* Synchronise manual entry and field/alternate field. */
Daniel@0 4389 _doKeyUp: function(event) {
Daniel@0 4390 var date,
Daniel@0 4391 inst = $.datepicker._getInst(event.target);
Daniel@0 4392
Daniel@0 4393 if (inst.input.val() !== inst.lastVal) {
Daniel@0 4394 try {
Daniel@0 4395 date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
Daniel@0 4396 (inst.input ? inst.input.val() : null),
Daniel@0 4397 $.datepicker._getFormatConfig(inst));
Daniel@0 4398
Daniel@0 4399 if (date) { // only if valid
Daniel@0 4400 $.datepicker._setDateFromField(inst);
Daniel@0 4401 $.datepicker._updateAlternate(inst);
Daniel@0 4402 $.datepicker._updateDatepicker(inst);
Daniel@0 4403 }
Daniel@0 4404 }
Daniel@0 4405 catch (err) {
Daniel@0 4406 }
Daniel@0 4407 }
Daniel@0 4408 return true;
Daniel@0 4409 },
Daniel@0 4410
Daniel@0 4411 /* Pop-up the date picker for a given input field.
Daniel@0 4412 * If false returned from beforeShow event handler do not show.
Daniel@0 4413 * @param input element - the input field attached to the date picker or
Daniel@0 4414 * event - if triggered by focus
Daniel@0 4415 */
Daniel@0 4416 _showDatepicker: function(input) {
Daniel@0 4417 input = input.target || input;
Daniel@0 4418 if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
Daniel@0 4419 input = $("input", input.parentNode)[0];
Daniel@0 4420 }
Daniel@0 4421
Daniel@0 4422 if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
Daniel@0 4423 return;
Daniel@0 4424 }
Daniel@0 4425
Daniel@0 4426 var inst, beforeShow, beforeShowSettings, isFixed,
Daniel@0 4427 offset, showAnim, duration;
Daniel@0 4428
Daniel@0 4429 inst = $.datepicker._getInst(input);
Daniel@0 4430 if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
Daniel@0 4431 $.datepicker._curInst.dpDiv.stop(true, true);
Daniel@0 4432 if ( inst && $.datepicker._datepickerShowing ) {
Daniel@0 4433 $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
Daniel@0 4434 }
Daniel@0 4435 }
Daniel@0 4436
Daniel@0 4437 beforeShow = $.datepicker._get(inst, "beforeShow");
Daniel@0 4438 beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
Daniel@0 4439 if(beforeShowSettings === false){
Daniel@0 4440 return;
Daniel@0 4441 }
Daniel@0 4442 datepicker_extendRemove(inst.settings, beforeShowSettings);
Daniel@0 4443
Daniel@0 4444 inst.lastVal = null;
Daniel@0 4445 $.datepicker._lastInput = input;
Daniel@0 4446 $.datepicker._setDateFromField(inst);
Daniel@0 4447
Daniel@0 4448 if ($.datepicker._inDialog) { // hide cursor
Daniel@0 4449 input.value = "";
Daniel@0 4450 }
Daniel@0 4451 if (!$.datepicker._pos) { // position below input
Daniel@0 4452 $.datepicker._pos = $.datepicker._findPos(input);
Daniel@0 4453 $.datepicker._pos[1] += input.offsetHeight; // add the height
Daniel@0 4454 }
Daniel@0 4455
Daniel@0 4456 isFixed = false;
Daniel@0 4457 $(input).parents().each(function() {
Daniel@0 4458 isFixed |= $(this).css("position") === "fixed";
Daniel@0 4459 return !isFixed;
Daniel@0 4460 });
Daniel@0 4461
Daniel@0 4462 offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
Daniel@0 4463 $.datepicker._pos = null;
Daniel@0 4464 //to avoid flashes on Firefox
Daniel@0 4465 inst.dpDiv.empty();
Daniel@0 4466 // determine sizing offscreen
Daniel@0 4467 inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
Daniel@0 4468 $.datepicker._updateDatepicker(inst);
Daniel@0 4469 // fix width for dynamic number of date pickers
Daniel@0 4470 // and adjust position before showing
Daniel@0 4471 offset = $.datepicker._checkOffset(inst, offset, isFixed);
Daniel@0 4472 inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
Daniel@0 4473 "static" : (isFixed ? "fixed" : "absolute")), display: "none",
Daniel@0 4474 left: offset.left + "px", top: offset.top + "px"});
Daniel@0 4475
Daniel@0 4476 if (!inst.inline) {
Daniel@0 4477 showAnim = $.datepicker._get(inst, "showAnim");
Daniel@0 4478 duration = $.datepicker._get(inst, "duration");
Daniel@0 4479 inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
Daniel@0 4480 $.datepicker._datepickerShowing = true;
Daniel@0 4481
Daniel@0 4482 if ( $.effects && $.effects.effect[ showAnim ] ) {
Daniel@0 4483 inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
Daniel@0 4484 } else {
Daniel@0 4485 inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
Daniel@0 4486 }
Daniel@0 4487
Daniel@0 4488 if ( $.datepicker._shouldFocusInput( inst ) ) {
Daniel@0 4489 inst.input.focus();
Daniel@0 4490 }
Daniel@0 4491
Daniel@0 4492 $.datepicker._curInst = inst;
Daniel@0 4493 }
Daniel@0 4494 },
Daniel@0 4495
Daniel@0 4496 /* Generate the date picker content. */
Daniel@0 4497 _updateDatepicker: function(inst) {
Daniel@0 4498 this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
Daniel@0 4499 datepicker_instActive = inst; // for delegate hover events
Daniel@0 4500 inst.dpDiv.empty().append(this._generateHTML(inst));
Daniel@0 4501 this._attachHandlers(inst);
Daniel@0 4502 inst.dpDiv.find("." + this._dayOverClass + " a");
Daniel@0 4503
Daniel@0 4504 var origyearshtml,
Daniel@0 4505 numMonths = this._getNumberOfMonths(inst),
Daniel@0 4506 cols = numMonths[1],
Daniel@0 4507 width = 17;
Daniel@0 4508
Daniel@0 4509 inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
Daniel@0 4510 if (cols > 1) {
Daniel@0 4511 inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
Daniel@0 4512 }
Daniel@0 4513 inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
Daniel@0 4514 "Class"]("ui-datepicker-multi");
Daniel@0 4515 inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
Daniel@0 4516 "Class"]("ui-datepicker-rtl");
Daniel@0 4517
Daniel@0 4518 if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
Daniel@0 4519 inst.input.focus();
Daniel@0 4520 }
Daniel@0 4521
Daniel@0 4522 // deffered render of the years select (to avoid flashes on Firefox)
Daniel@0 4523 if( inst.yearshtml ){
Daniel@0 4524 origyearshtml = inst.yearshtml;
Daniel@0 4525 setTimeout(function(){
Daniel@0 4526 //assure that inst.yearshtml didn't change.
Daniel@0 4527 if( origyearshtml === inst.yearshtml && inst.yearshtml ){
Daniel@0 4528 inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
Daniel@0 4529 }
Daniel@0 4530 origyearshtml = inst.yearshtml = null;
Daniel@0 4531 }, 0);
Daniel@0 4532 }
Daniel@0 4533 },
Daniel@0 4534
Daniel@0 4535 // #6694 - don't focus the input if it's already focused
Daniel@0 4536 // this breaks the change event in IE
Daniel@0 4537 // Support: IE and jQuery <1.9
Daniel@0 4538 _shouldFocusInput: function( inst ) {
Daniel@0 4539 return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
Daniel@0 4540 },
Daniel@0 4541
Daniel@0 4542 /* Check positioning to remain on screen. */
Daniel@0 4543 _checkOffset: function(inst, offset, isFixed) {
Daniel@0 4544 var dpWidth = inst.dpDiv.outerWidth(),
Daniel@0 4545 dpHeight = inst.dpDiv.outerHeight(),
Daniel@0 4546 inputWidth = inst.input ? inst.input.outerWidth() : 0,
Daniel@0 4547 inputHeight = inst.input ? inst.input.outerHeight() : 0,
Daniel@0 4548 viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
Daniel@0 4549 viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
Daniel@0 4550
Daniel@0 4551 offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
Daniel@0 4552 offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
Daniel@0 4553 offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
Daniel@0 4554
Daniel@0 4555 // now check if datepicker is showing outside window viewport - move to a better place if so.
Daniel@0 4556 offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
Daniel@0 4557 Math.abs(offset.left + dpWidth - viewWidth) : 0);
Daniel@0 4558 offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
Daniel@0 4559 Math.abs(dpHeight + inputHeight) : 0);
Daniel@0 4560
Daniel@0 4561 return offset;
Daniel@0 4562 },
Daniel@0 4563
Daniel@0 4564 /* Find an object's position on the screen. */
Daniel@0 4565 _findPos: function(obj) {
Daniel@0 4566 var position,
Daniel@0 4567 inst = this._getInst(obj),
Daniel@0 4568 isRTL = this._get(inst, "isRTL");
Daniel@0 4569
Daniel@0 4570 while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
Daniel@0 4571 obj = obj[isRTL ? "previousSibling" : "nextSibling"];
Daniel@0 4572 }
Daniel@0 4573
Daniel@0 4574 position = $(obj).offset();
Daniel@0 4575 return [position.left, position.top];
Daniel@0 4576 },
Daniel@0 4577
Daniel@0 4578 /* Hide the date picker from view.
Daniel@0 4579 * @param input element - the input field attached to the date picker
Daniel@0 4580 */
Daniel@0 4581 _hideDatepicker: function(input) {
Daniel@0 4582 var showAnim, duration, postProcess, onClose,
Daniel@0 4583 inst = this._curInst;
Daniel@0 4584
Daniel@0 4585 if (!inst || (input && inst !== $.data(input, "datepicker"))) {
Daniel@0 4586 return;
Daniel@0 4587 }
Daniel@0 4588
Daniel@0 4589 if (this._datepickerShowing) {
Daniel@0 4590 showAnim = this._get(inst, "showAnim");
Daniel@0 4591 duration = this._get(inst, "duration");
Daniel@0 4592 postProcess = function() {
Daniel@0 4593 $.datepicker._tidyDialog(inst);
Daniel@0 4594 };
Daniel@0 4595
Daniel@0 4596 // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
Daniel@0 4597 if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
Daniel@0 4598 inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
Daniel@0 4599 } else {
Daniel@0 4600 inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
Daniel@0 4601 (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
Daniel@0 4602 }
Daniel@0 4603
Daniel@0 4604 if (!showAnim) {
Daniel@0 4605 postProcess();
Daniel@0 4606 }
Daniel@0 4607 this._datepickerShowing = false;
Daniel@0 4608
Daniel@0 4609 onClose = this._get(inst, "onClose");
Daniel@0 4610 if (onClose) {
Daniel@0 4611 onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
Daniel@0 4612 }
Daniel@0 4613
Daniel@0 4614 this._lastInput = null;
Daniel@0 4615 if (this._inDialog) {
Daniel@0 4616 this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
Daniel@0 4617 if ($.blockUI) {
Daniel@0 4618 $.unblockUI();
Daniel@0 4619 $("body").append(this.dpDiv);
Daniel@0 4620 }
Daniel@0 4621 }
Daniel@0 4622 this._inDialog = false;
Daniel@0 4623 }
Daniel@0 4624 },
Daniel@0 4625
Daniel@0 4626 /* Tidy up after a dialog display. */
Daniel@0 4627 _tidyDialog: function(inst) {
Daniel@0 4628 inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
Daniel@0 4629 },
Daniel@0 4630
Daniel@0 4631 /* Close date picker if clicked elsewhere. */
Daniel@0 4632 _checkExternalClick: function(event) {
Daniel@0 4633 if (!$.datepicker._curInst) {
Daniel@0 4634 return;
Daniel@0 4635 }
Daniel@0 4636
Daniel@0 4637 var $target = $(event.target),
Daniel@0 4638 inst = $.datepicker._getInst($target[0]);
Daniel@0 4639
Daniel@0 4640 if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
Daniel@0 4641 $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
Daniel@0 4642 !$target.hasClass($.datepicker.markerClassName) &&
Daniel@0 4643 !$target.closest("." + $.datepicker._triggerClass).length &&
Daniel@0 4644 $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
Daniel@0 4645 ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
Daniel@0 4646 $.datepicker._hideDatepicker();
Daniel@0 4647 }
Daniel@0 4648 },
Daniel@0 4649
Daniel@0 4650 /* Adjust one of the date sub-fields. */
Daniel@0 4651 _adjustDate: function(id, offset, period) {
Daniel@0 4652 var target = $(id),
Daniel@0 4653 inst = this._getInst(target[0]);
Daniel@0 4654
Daniel@0 4655 if (this._isDisabledDatepicker(target[0])) {
Daniel@0 4656 return;
Daniel@0 4657 }
Daniel@0 4658 this._adjustInstDate(inst, offset +
Daniel@0 4659 (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
Daniel@0 4660 period);
Daniel@0 4661 this._updateDatepicker(inst);
Daniel@0 4662 },
Daniel@0 4663
Daniel@0 4664 /* Action for current link. */
Daniel@0 4665 _gotoToday: function(id) {
Daniel@0 4666 var date,
Daniel@0 4667 target = $(id),
Daniel@0 4668 inst = this._getInst(target[0]);
Daniel@0 4669
Daniel@0 4670 if (this._get(inst, "gotoCurrent") && inst.currentDay) {
Daniel@0 4671 inst.selectedDay = inst.currentDay;
Daniel@0 4672 inst.drawMonth = inst.selectedMonth = inst.currentMonth;
Daniel@0 4673 inst.drawYear = inst.selectedYear = inst.currentYear;
Daniel@0 4674 } else {
Daniel@0 4675 date = new Date();
Daniel@0 4676 inst.selectedDay = date.getDate();
Daniel@0 4677 inst.drawMonth = inst.selectedMonth = date.getMonth();
Daniel@0 4678 inst.drawYear = inst.selectedYear = date.getFullYear();
Daniel@0 4679 }
Daniel@0 4680 this._notifyChange(inst);
Daniel@0 4681 this._adjustDate(target);
Daniel@0 4682 },
Daniel@0 4683
Daniel@0 4684 /* Action for selecting a new month/year. */
Daniel@0 4685 _selectMonthYear: function(id, select, period) {
Daniel@0 4686 var target = $(id),
Daniel@0 4687 inst = this._getInst(target[0]);
Daniel@0 4688
Daniel@0 4689 inst["selected" + (period === "M" ? "Month" : "Year")] =
Daniel@0 4690 inst["draw" + (period === "M" ? "Month" : "Year")] =
Daniel@0 4691 parseInt(select.options[select.selectedIndex].value,10);
Daniel@0 4692
Daniel@0 4693 this._notifyChange(inst);
Daniel@0 4694 this._adjustDate(target);
Daniel@0 4695 },
Daniel@0 4696
Daniel@0 4697 /* Action for selecting a day. */
Daniel@0 4698 _selectDay: function(id, month, year, td) {
Daniel@0 4699 var inst,
Daniel@0 4700 target = $(id);
Daniel@0 4701
Daniel@0 4702 if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
Daniel@0 4703 return;
Daniel@0 4704 }
Daniel@0 4705
Daniel@0 4706 inst = this._getInst(target[0]);
Daniel@0 4707 inst.selectedDay = inst.currentDay = $("a", td).html();
Daniel@0 4708 inst.selectedMonth = inst.currentMonth = month;
Daniel@0 4709 inst.selectedYear = inst.currentYear = year;
Daniel@0 4710 this._selectDate(id, this._formatDate(inst,
Daniel@0 4711 inst.currentDay, inst.currentMonth, inst.currentYear));
Daniel@0 4712 },
Daniel@0 4713
Daniel@0 4714 /* Erase the input field and hide the date picker. */
Daniel@0 4715 _clearDate: function(id) {
Daniel@0 4716 var target = $(id);
Daniel@0 4717 this._selectDate(target, "");
Daniel@0 4718 },
Daniel@0 4719
Daniel@0 4720 /* Update the input field with the selected date. */
Daniel@0 4721 _selectDate: function(id, dateStr) {
Daniel@0 4722 var onSelect,
Daniel@0 4723 target = $(id),
Daniel@0 4724 inst = this._getInst(target[0]);
Daniel@0 4725
Daniel@0 4726 dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
Daniel@0 4727 if (inst.input) {
Daniel@0 4728 inst.input.val(dateStr);
Daniel@0 4729 }
Daniel@0 4730 this._updateAlternate(inst);
Daniel@0 4731
Daniel@0 4732 onSelect = this._get(inst, "onSelect");
Daniel@0 4733 if (onSelect) {
Daniel@0 4734 onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]); // trigger custom callback
Daniel@0 4735 } else if (inst.input) {
Daniel@0 4736 inst.input.trigger("change"); // fire the change event
Daniel@0 4737 }
Daniel@0 4738
Daniel@0 4739 if (inst.inline){
Daniel@0 4740 this._updateDatepicker(inst);
Daniel@0 4741 } else {
Daniel@0 4742 this._hideDatepicker();
Daniel@0 4743 this._lastInput = inst.input[0];
Daniel@0 4744 if (typeof(inst.input[0]) !== "object") {
Daniel@0 4745 inst.input.focus(); // restore focus
Daniel@0 4746 }
Daniel@0 4747 this._lastInput = null;
Daniel@0 4748 }
Daniel@0 4749 },
Daniel@0 4750
Daniel@0 4751 /* Update any alternate field to synchronise with the main field. */
Daniel@0 4752 _updateAlternate: function(inst) {
Daniel@0 4753 var altFormat, date, dateStr,
Daniel@0 4754 altField = this._get(inst, "altField");
Daniel@0 4755
Daniel@0 4756 if (altField) { // update alternate field too
Daniel@0 4757 altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
Daniel@0 4758 date = this._getDate(inst);
Daniel@0 4759 dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
Daniel@0 4760 $(altField).each(function() { $(this).val(dateStr); });
Daniel@0 4761 }
Daniel@0 4762 },
Daniel@0 4763
Daniel@0 4764 /* Set as beforeShowDay function to prevent selection of weekends.
Daniel@0 4765 * @param date Date - the date to customise
Daniel@0 4766 * @return [boolean, string] - is this date selectable?, what is its CSS class?
Daniel@0 4767 */
Daniel@0 4768 noWeekends: function(date) {
Daniel@0 4769 var day = date.getDay();
Daniel@0 4770 return [(day > 0 && day < 6), ""];
Daniel@0 4771 },
Daniel@0 4772
Daniel@0 4773 /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
Daniel@0 4774 * @param date Date - the date to get the week for
Daniel@0 4775 * @return number - the number of the week within the year that contains this date
Daniel@0 4776 */
Daniel@0 4777 iso8601Week: function(date) {
Daniel@0 4778 var time,
Daniel@0 4779 checkDate = new Date(date.getTime());
Daniel@0 4780
Daniel@0 4781 // Find Thursday of this week starting on Monday
Daniel@0 4782 checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
Daniel@0 4783
Daniel@0 4784 time = checkDate.getTime();
Daniel@0 4785 checkDate.setMonth(0); // Compare with Jan 1
Daniel@0 4786 checkDate.setDate(1);
Daniel@0 4787 return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
Daniel@0 4788 },
Daniel@0 4789
Daniel@0 4790 /* Parse a string value into a date object.
Daniel@0 4791 * See formatDate below for the possible formats.
Daniel@0 4792 *
Daniel@0 4793 * @param format string - the expected format of the date
Daniel@0 4794 * @param value string - the date in the above format
Daniel@0 4795 * @param settings Object - attributes include:
Daniel@0 4796 * shortYearCutoff number - the cutoff year for determining the century (optional)
Daniel@0 4797 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
Daniel@0 4798 * dayNames string[7] - names of the days from Sunday (optional)
Daniel@0 4799 * monthNamesShort string[12] - abbreviated names of the months (optional)
Daniel@0 4800 * monthNames string[12] - names of the months (optional)
Daniel@0 4801 * @return Date - the extracted date value or null if value is blank
Daniel@0 4802 */
Daniel@0 4803 parseDate: function (format, value, settings) {
Daniel@0 4804 if (format == null || value == null) {
Daniel@0 4805 throw "Invalid arguments";
Daniel@0 4806 }
Daniel@0 4807
Daniel@0 4808 value = (typeof value === "object" ? value.toString() : value + "");
Daniel@0 4809 if (value === "") {
Daniel@0 4810 return null;
Daniel@0 4811 }
Daniel@0 4812
Daniel@0 4813 var iFormat, dim, extra,
Daniel@0 4814 iValue = 0,
Daniel@0 4815 shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
Daniel@0 4816 shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
Daniel@0 4817 new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
Daniel@0 4818 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
Daniel@0 4819 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
Daniel@0 4820 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
Daniel@0 4821 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
Daniel@0 4822 year = -1,
Daniel@0 4823 month = -1,
Daniel@0 4824 day = -1,
Daniel@0 4825 doy = -1,
Daniel@0 4826 literal = false,
Daniel@0 4827 date,
Daniel@0 4828 // Check whether a format character is doubled
Daniel@0 4829 lookAhead = function(match) {
Daniel@0 4830 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
Daniel@0 4831 if (matches) {
Daniel@0 4832 iFormat++;
Daniel@0 4833 }
Daniel@0 4834 return matches;
Daniel@0 4835 },
Daniel@0 4836 // Extract a number from the string value
Daniel@0 4837 getNumber = function(match) {
Daniel@0 4838 var isDoubled = lookAhead(match),
Daniel@0 4839 size = (match === "@" ? 14 : (match === "!" ? 20 :
Daniel@0 4840 (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
Daniel@0 4841 digits = new RegExp("^\\d{1," + size + "}"),
Daniel@0 4842 num = value.substring(iValue).match(digits);
Daniel@0 4843 if (!num) {
Daniel@0 4844 throw "Missing number at position " + iValue;
Daniel@0 4845 }
Daniel@0 4846 iValue += num[0].length;
Daniel@0 4847 return parseInt(num[0], 10);
Daniel@0 4848 },
Daniel@0 4849 // Extract a name from the string value and convert to an index
Daniel@0 4850 getName = function(match, shortNames, longNames) {
Daniel@0 4851 var index = -1,
Daniel@0 4852 names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
Daniel@0 4853 return [ [k, v] ];
Daniel@0 4854 }).sort(function (a, b) {
Daniel@0 4855 return -(a[1].length - b[1].length);
Daniel@0 4856 });
Daniel@0 4857
Daniel@0 4858 $.each(names, function (i, pair) {
Daniel@0 4859 var name = pair[1];
Daniel@0 4860 if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
Daniel@0 4861 index = pair[0];
Daniel@0 4862 iValue += name.length;
Daniel@0 4863 return false;
Daniel@0 4864 }
Daniel@0 4865 });
Daniel@0 4866 if (index !== -1) {
Daniel@0 4867 return index + 1;
Daniel@0 4868 } else {
Daniel@0 4869 throw "Unknown name at position " + iValue;
Daniel@0 4870 }
Daniel@0 4871 },
Daniel@0 4872 // Confirm that a literal character matches the string value
Daniel@0 4873 checkLiteral = function() {
Daniel@0 4874 if (value.charAt(iValue) !== format.charAt(iFormat)) {
Daniel@0 4875 throw "Unexpected literal at position " + iValue;
Daniel@0 4876 }
Daniel@0 4877 iValue++;
Daniel@0 4878 };
Daniel@0 4879
Daniel@0 4880 for (iFormat = 0; iFormat < format.length; iFormat++) {
Daniel@0 4881 if (literal) {
Daniel@0 4882 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
Daniel@0 4883 literal = false;
Daniel@0 4884 } else {
Daniel@0 4885 checkLiteral();
Daniel@0 4886 }
Daniel@0 4887 } else {
Daniel@0 4888 switch (format.charAt(iFormat)) {
Daniel@0 4889 case "d":
Daniel@0 4890 day = getNumber("d");
Daniel@0 4891 break;
Daniel@0 4892 case "D":
Daniel@0 4893 getName("D", dayNamesShort, dayNames);
Daniel@0 4894 break;
Daniel@0 4895 case "o":
Daniel@0 4896 doy = getNumber("o");
Daniel@0 4897 break;
Daniel@0 4898 case "m":
Daniel@0 4899 month = getNumber("m");
Daniel@0 4900 break;
Daniel@0 4901 case "M":
Daniel@0 4902 month = getName("M", monthNamesShort, monthNames);
Daniel@0 4903 break;
Daniel@0 4904 case "y":
Daniel@0 4905 year = getNumber("y");
Daniel@0 4906 break;
Daniel@0 4907 case "@":
Daniel@0 4908 date = new Date(getNumber("@"));
Daniel@0 4909 year = date.getFullYear();
Daniel@0 4910 month = date.getMonth() + 1;
Daniel@0 4911 day = date.getDate();
Daniel@0 4912 break;
Daniel@0 4913 case "!":
Daniel@0 4914 date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
Daniel@0 4915 year = date.getFullYear();
Daniel@0 4916 month = date.getMonth() + 1;
Daniel@0 4917 day = date.getDate();
Daniel@0 4918 break;
Daniel@0 4919 case "'":
Daniel@0 4920 if (lookAhead("'")){
Daniel@0 4921 checkLiteral();
Daniel@0 4922 } else {
Daniel@0 4923 literal = true;
Daniel@0 4924 }
Daniel@0 4925 break;
Daniel@0 4926 default:
Daniel@0 4927 checkLiteral();
Daniel@0 4928 }
Daniel@0 4929 }
Daniel@0 4930 }
Daniel@0 4931
Daniel@0 4932 if (iValue < value.length){
Daniel@0 4933 extra = value.substr(iValue);
Daniel@0 4934 if (!/^\s+/.test(extra)) {
Daniel@0 4935 throw "Extra/unparsed characters found in date: " + extra;
Daniel@0 4936 }
Daniel@0 4937 }
Daniel@0 4938
Daniel@0 4939 if (year === -1) {
Daniel@0 4940 year = new Date().getFullYear();
Daniel@0 4941 } else if (year < 100) {
Daniel@0 4942 year += new Date().getFullYear() - new Date().getFullYear() % 100 +
Daniel@0 4943 (year <= shortYearCutoff ? 0 : -100);
Daniel@0 4944 }
Daniel@0 4945
Daniel@0 4946 if (doy > -1) {
Daniel@0 4947 month = 1;
Daniel@0 4948 day = doy;
Daniel@0 4949 do {
Daniel@0 4950 dim = this._getDaysInMonth(year, month - 1);
Daniel@0 4951 if (day <= dim) {
Daniel@0 4952 break;
Daniel@0 4953 }
Daniel@0 4954 month++;
Daniel@0 4955 day -= dim;
Daniel@0 4956 } while (true);
Daniel@0 4957 }
Daniel@0 4958
Daniel@0 4959 date = this._daylightSavingAdjust(new Date(year, month - 1, day));
Daniel@0 4960 if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
Daniel@0 4961 throw "Invalid date"; // E.g. 31/02/00
Daniel@0 4962 }
Daniel@0 4963 return date;
Daniel@0 4964 },
Daniel@0 4965
Daniel@0 4966 /* Standard date formats. */
Daniel@0 4967 ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
Daniel@0 4968 COOKIE: "D, dd M yy",
Daniel@0 4969 ISO_8601: "yy-mm-dd",
Daniel@0 4970 RFC_822: "D, d M y",
Daniel@0 4971 RFC_850: "DD, dd-M-y",
Daniel@0 4972 RFC_1036: "D, d M y",
Daniel@0 4973 RFC_1123: "D, d M yy",
Daniel@0 4974 RFC_2822: "D, d M yy",
Daniel@0 4975 RSS: "D, d M y", // RFC 822
Daniel@0 4976 TICKS: "!",
Daniel@0 4977 TIMESTAMP: "@",
Daniel@0 4978 W3C: "yy-mm-dd", // ISO 8601
Daniel@0 4979
Daniel@0 4980 _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
Daniel@0 4981 Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
Daniel@0 4982
Daniel@0 4983 /* Format a date object into a string value.
Daniel@0 4984 * The format can be combinations of the following:
Daniel@0 4985 * d - day of month (no leading zero)
Daniel@0 4986 * dd - day of month (two digit)
Daniel@0 4987 * o - day of year (no leading zeros)
Daniel@0 4988 * oo - day of year (three digit)
Daniel@0 4989 * D - day name short
Daniel@0 4990 * DD - day name long
Daniel@0 4991 * m - month of year (no leading zero)
Daniel@0 4992 * mm - month of year (two digit)
Daniel@0 4993 * M - month name short
Daniel@0 4994 * MM - month name long
Daniel@0 4995 * y - year (two digit)
Daniel@0 4996 * yy - year (four digit)
Daniel@0 4997 * @ - Unix timestamp (ms since 01/01/1970)
Daniel@0 4998 * ! - Windows ticks (100ns since 01/01/0001)
Daniel@0 4999 * "..." - literal text
Daniel@0 5000 * '' - single quote
Daniel@0 5001 *
Daniel@0 5002 * @param format string - the desired format of the date
Daniel@0 5003 * @param date Date - the date value to format
Daniel@0 5004 * @param settings Object - attributes include:
Daniel@0 5005 * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
Daniel@0 5006 * dayNames string[7] - names of the days from Sunday (optional)
Daniel@0 5007 * monthNamesShort string[12] - abbreviated names of the months (optional)
Daniel@0 5008 * monthNames string[12] - names of the months (optional)
Daniel@0 5009 * @return string - the date in the above format
Daniel@0 5010 */
Daniel@0 5011 formatDate: function (format, date, settings) {
Daniel@0 5012 if (!date) {
Daniel@0 5013 return "";
Daniel@0 5014 }
Daniel@0 5015
Daniel@0 5016 var iFormat,
Daniel@0 5017 dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
Daniel@0 5018 dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
Daniel@0 5019 monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
Daniel@0 5020 monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
Daniel@0 5021 // Check whether a format character is doubled
Daniel@0 5022 lookAhead = function(match) {
Daniel@0 5023 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
Daniel@0 5024 if (matches) {
Daniel@0 5025 iFormat++;
Daniel@0 5026 }
Daniel@0 5027 return matches;
Daniel@0 5028 },
Daniel@0 5029 // Format a number, with leading zero if necessary
Daniel@0 5030 formatNumber = function(match, value, len) {
Daniel@0 5031 var num = "" + value;
Daniel@0 5032 if (lookAhead(match)) {
Daniel@0 5033 while (num.length < len) {
Daniel@0 5034 num = "0" + num;
Daniel@0 5035 }
Daniel@0 5036 }
Daniel@0 5037 return num;
Daniel@0 5038 },
Daniel@0 5039 // Format a name, short or long as requested
Daniel@0 5040 formatName = function(match, value, shortNames, longNames) {
Daniel@0 5041 return (lookAhead(match) ? longNames[value] : shortNames[value]);
Daniel@0 5042 },
Daniel@0 5043 output = "",
Daniel@0 5044 literal = false;
Daniel@0 5045
Daniel@0 5046 if (date) {
Daniel@0 5047 for (iFormat = 0; iFormat < format.length; iFormat++) {
Daniel@0 5048 if (literal) {
Daniel@0 5049 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
Daniel@0 5050 literal = false;
Daniel@0 5051 } else {
Daniel@0 5052 output += format.charAt(iFormat);
Daniel@0 5053 }
Daniel@0 5054 } else {
Daniel@0 5055 switch (format.charAt(iFormat)) {
Daniel@0 5056 case "d":
Daniel@0 5057 output += formatNumber("d", date.getDate(), 2);
Daniel@0 5058 break;
Daniel@0 5059 case "D":
Daniel@0 5060 output += formatName("D", date.getDay(), dayNamesShort, dayNames);
Daniel@0 5061 break;
Daniel@0 5062 case "o":
Daniel@0 5063 output += formatNumber("o",
Daniel@0 5064 Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
Daniel@0 5065 break;
Daniel@0 5066 case "m":
Daniel@0 5067 output += formatNumber("m", date.getMonth() + 1, 2);
Daniel@0 5068 break;
Daniel@0 5069 case "M":
Daniel@0 5070 output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
Daniel@0 5071 break;
Daniel@0 5072 case "y":
Daniel@0 5073 output += (lookAhead("y") ? date.getFullYear() :
Daniel@0 5074 (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
Daniel@0 5075 break;
Daniel@0 5076 case "@":
Daniel@0 5077 output += date.getTime();
Daniel@0 5078 break;
Daniel@0 5079 case "!":
Daniel@0 5080 output += date.getTime() * 10000 + this._ticksTo1970;
Daniel@0 5081 break;
Daniel@0 5082 case "'":
Daniel@0 5083 if (lookAhead("'")) {
Daniel@0 5084 output += "'";
Daniel@0 5085 } else {
Daniel@0 5086 literal = true;
Daniel@0 5087 }
Daniel@0 5088 break;
Daniel@0 5089 default:
Daniel@0 5090 output += format.charAt(iFormat);
Daniel@0 5091 }
Daniel@0 5092 }
Daniel@0 5093 }
Daniel@0 5094 }
Daniel@0 5095 return output;
Daniel@0 5096 },
Daniel@0 5097
Daniel@0 5098 /* Extract all possible characters from the date format. */
Daniel@0 5099 _possibleChars: function (format) {
Daniel@0 5100 var iFormat,
Daniel@0 5101 chars = "",
Daniel@0 5102 literal = false,
Daniel@0 5103 // Check whether a format character is doubled
Daniel@0 5104 lookAhead = function(match) {
Daniel@0 5105 var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
Daniel@0 5106 if (matches) {
Daniel@0 5107 iFormat++;
Daniel@0 5108 }
Daniel@0 5109 return matches;
Daniel@0 5110 };
Daniel@0 5111
Daniel@0 5112 for (iFormat = 0; iFormat < format.length; iFormat++) {
Daniel@0 5113 if (literal) {
Daniel@0 5114 if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
Daniel@0 5115 literal = false;
Daniel@0 5116 } else {
Daniel@0 5117 chars += format.charAt(iFormat);
Daniel@0 5118 }
Daniel@0 5119 } else {
Daniel@0 5120 switch (format.charAt(iFormat)) {
Daniel@0 5121 case "d": case "m": case "y": case "@":
Daniel@0 5122 chars += "0123456789";
Daniel@0 5123 break;
Daniel@0 5124 case "D": case "M":
Daniel@0 5125 return null; // Accept anything
Daniel@0 5126 case "'":
Daniel@0 5127 if (lookAhead("'")) {
Daniel@0 5128 chars += "'";
Daniel@0 5129 } else {
Daniel@0 5130 literal = true;
Daniel@0 5131 }
Daniel@0 5132 break;
Daniel@0 5133 default:
Daniel@0 5134 chars += format.charAt(iFormat);
Daniel@0 5135 }
Daniel@0 5136 }
Daniel@0 5137 }
Daniel@0 5138 return chars;
Daniel@0 5139 },
Daniel@0 5140
Daniel@0 5141 /* Get a setting value, defaulting if necessary. */
Daniel@0 5142 _get: function(inst, name) {
Daniel@0 5143 return inst.settings[name] !== undefined ?
Daniel@0 5144 inst.settings[name] : this._defaults[name];
Daniel@0 5145 },
Daniel@0 5146
Daniel@0 5147 /* Parse existing date and initialise date picker. */
Daniel@0 5148 _setDateFromField: function(inst, noDefault) {
Daniel@0 5149 if (inst.input.val() === inst.lastVal) {
Daniel@0 5150 return;
Daniel@0 5151 }
Daniel@0 5152
Daniel@0 5153 var dateFormat = this._get(inst, "dateFormat"),
Daniel@0 5154 dates = inst.lastVal = inst.input ? inst.input.val() : null,
Daniel@0 5155 defaultDate = this._getDefaultDate(inst),
Daniel@0 5156 date = defaultDate,
Daniel@0 5157 settings = this._getFormatConfig(inst);
Daniel@0 5158
Daniel@0 5159 try {
Daniel@0 5160 date = this.parseDate(dateFormat, dates, settings) || defaultDate;
Daniel@0 5161 } catch (event) {
Daniel@0 5162 dates = (noDefault ? "" : dates);
Daniel@0 5163 }
Daniel@0 5164 inst.selectedDay = date.getDate();
Daniel@0 5165 inst.drawMonth = inst.selectedMonth = date.getMonth();
Daniel@0 5166 inst.drawYear = inst.selectedYear = date.getFullYear();
Daniel@0 5167 inst.currentDay = (dates ? date.getDate() : 0);
Daniel@0 5168 inst.currentMonth = (dates ? date.getMonth() : 0);
Daniel@0 5169 inst.currentYear = (dates ? date.getFullYear() : 0);
Daniel@0 5170 this._adjustInstDate(inst);
Daniel@0 5171 },
Daniel@0 5172
Daniel@0 5173 /* Retrieve the default date shown on opening. */
Daniel@0 5174 _getDefaultDate: function(inst) {
Daniel@0 5175 return this._restrictMinMax(inst,
Daniel@0 5176 this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
Daniel@0 5177 },
Daniel@0 5178
Daniel@0 5179 /* A date may be specified as an exact value or a relative one. */
Daniel@0 5180 _determineDate: function(inst, date, defaultDate) {
Daniel@0 5181 var offsetNumeric = function(offset) {
Daniel@0 5182 var date = new Date();
Daniel@0 5183 date.setDate(date.getDate() + offset);
Daniel@0 5184 return date;
Daniel@0 5185 },
Daniel@0 5186 offsetString = function(offset) {
Daniel@0 5187 try {
Daniel@0 5188 return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
Daniel@0 5189 offset, $.datepicker._getFormatConfig(inst));
Daniel@0 5190 }
Daniel@0 5191 catch (e) {
Daniel@0 5192 // Ignore
Daniel@0 5193 }
Daniel@0 5194
Daniel@0 5195 var date = (offset.toLowerCase().match(/^c/) ?
Daniel@0 5196 $.datepicker._getDate(inst) : null) || new Date(),
Daniel@0 5197 year = date.getFullYear(),
Daniel@0 5198 month = date.getMonth(),
Daniel@0 5199 day = date.getDate(),
Daniel@0 5200 pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
Daniel@0 5201 matches = pattern.exec(offset);
Daniel@0 5202
Daniel@0 5203 while (matches) {
Daniel@0 5204 switch (matches[2] || "d") {
Daniel@0 5205 case "d" : case "D" :
Daniel@0 5206 day += parseInt(matches[1],10); break;
Daniel@0 5207 case "w" : case "W" :
Daniel@0 5208 day += parseInt(matches[1],10) * 7; break;
Daniel@0 5209 case "m" : case "M" :
Daniel@0 5210 month += parseInt(matches[1],10);
Daniel@0 5211 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
Daniel@0 5212 break;
Daniel@0 5213 case "y": case "Y" :
Daniel@0 5214 year += parseInt(matches[1],10);
Daniel@0 5215 day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
Daniel@0 5216 break;
Daniel@0 5217 }
Daniel@0 5218 matches = pattern.exec(offset);
Daniel@0 5219 }
Daniel@0 5220 return new Date(year, month, day);
Daniel@0 5221 },
Daniel@0 5222 newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
Daniel@0 5223 (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
Daniel@0 5224
Daniel@0 5225 newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
Daniel@0 5226 if (newDate) {
Daniel@0 5227 newDate.setHours(0);
Daniel@0 5228 newDate.setMinutes(0);
Daniel@0 5229 newDate.setSeconds(0);
Daniel@0 5230 newDate.setMilliseconds(0);
Daniel@0 5231 }
Daniel@0 5232 return this._daylightSavingAdjust(newDate);
Daniel@0 5233 },
Daniel@0 5234
Daniel@0 5235 /* Handle switch to/from daylight saving.
Daniel@0 5236 * Hours may be non-zero on daylight saving cut-over:
Daniel@0 5237 * > 12 when midnight changeover, but then cannot generate
Daniel@0 5238 * midnight datetime, so jump to 1AM, otherwise reset.
Daniel@0 5239 * @param date (Date) the date to check
Daniel@0 5240 * @return (Date) the corrected date
Daniel@0 5241 */
Daniel@0 5242 _daylightSavingAdjust: function(date) {
Daniel@0 5243 if (!date) {
Daniel@0 5244 return null;
Daniel@0 5245 }
Daniel@0 5246 date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
Daniel@0 5247 return date;
Daniel@0 5248 },
Daniel@0 5249
Daniel@0 5250 /* Set the date(s) directly. */
Daniel@0 5251 _setDate: function(inst, date, noChange) {
Daniel@0 5252 var clear = !date,
Daniel@0 5253 origMonth = inst.selectedMonth,
Daniel@0 5254 origYear = inst.selectedYear,
Daniel@0 5255 newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
Daniel@0 5256
Daniel@0 5257 inst.selectedDay = inst.currentDay = newDate.getDate();
Daniel@0 5258 inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
Daniel@0 5259 inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
Daniel@0 5260 if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
Daniel@0 5261 this._notifyChange(inst);
Daniel@0 5262 }
Daniel@0 5263 this._adjustInstDate(inst);
Daniel@0 5264 if (inst.input) {
Daniel@0 5265 inst.input.val(clear ? "" : this._formatDate(inst));
Daniel@0 5266 }
Daniel@0 5267 },
Daniel@0 5268
Daniel@0 5269 /* Retrieve the date(s) directly. */
Daniel@0 5270 _getDate: function(inst) {
Daniel@0 5271 var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
Daniel@0 5272 this._daylightSavingAdjust(new Date(
Daniel@0 5273 inst.currentYear, inst.currentMonth, inst.currentDay)));
Daniel@0 5274 return startDate;
Daniel@0 5275 },
Daniel@0 5276
Daniel@0 5277 /* Attach the onxxx handlers. These are declared statically so
Daniel@0 5278 * they work with static code transformers like Caja.
Daniel@0 5279 */
Daniel@0 5280 _attachHandlers: function(inst) {
Daniel@0 5281 var stepMonths = this._get(inst, "stepMonths"),
Daniel@0 5282 id = "#" + inst.id.replace( /\\\\/g, "\\" );
Daniel@0 5283 inst.dpDiv.find("[data-handler]").map(function () {
Daniel@0 5284 var handler = {
Daniel@0 5285 prev: function () {
Daniel@0 5286 $.datepicker._adjustDate(id, -stepMonths, "M");
Daniel@0 5287 },
Daniel@0 5288 next: function () {
Daniel@0 5289 $.datepicker._adjustDate(id, +stepMonths, "M");
Daniel@0 5290 },
Daniel@0 5291 hide: function () {
Daniel@0 5292 $.datepicker._hideDatepicker();
Daniel@0 5293 },
Daniel@0 5294 today: function () {
Daniel@0 5295 $.datepicker._gotoToday(id);
Daniel@0 5296 },
Daniel@0 5297 selectDay: function () {
Daniel@0 5298 $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
Daniel@0 5299 return false;
Daniel@0 5300 },
Daniel@0 5301 selectMonth: function () {
Daniel@0 5302 $.datepicker._selectMonthYear(id, this, "M");
Daniel@0 5303 return false;
Daniel@0 5304 },
Daniel@0 5305 selectYear: function () {
Daniel@0 5306 $.datepicker._selectMonthYear(id, this, "Y");
Daniel@0 5307 return false;
Daniel@0 5308 }
Daniel@0 5309 };
Daniel@0 5310 $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
Daniel@0 5311 });
Daniel@0 5312 },
Daniel@0 5313
Daniel@0 5314 /* Generate the HTML for the current state of the date picker. */
Daniel@0 5315 _generateHTML: function(inst) {
Daniel@0 5316 var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
Daniel@0 5317 controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
Daniel@0 5318 monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
Daniel@0 5319 selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
Daniel@0 5320 cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
Daniel@0 5321 printDate, dRow, tbody, daySettings, otherMonth, unselectable,
Daniel@0 5322 tempDate = new Date(),
Daniel@0 5323 today = this._daylightSavingAdjust(
Daniel@0 5324 new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
Daniel@0 5325 isRTL = this._get(inst, "isRTL"),
Daniel@0 5326 showButtonPanel = this._get(inst, "showButtonPanel"),
Daniel@0 5327 hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
Daniel@0 5328 navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
Daniel@0 5329 numMonths = this._getNumberOfMonths(inst),
Daniel@0 5330 showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
Daniel@0 5331 stepMonths = this._get(inst, "stepMonths"),
Daniel@0 5332 isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
Daniel@0 5333 currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
Daniel@0 5334 new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
Daniel@0 5335 minDate = this._getMinMaxDate(inst, "min"),
Daniel@0 5336 maxDate = this._getMinMaxDate(inst, "max"),
Daniel@0 5337 drawMonth = inst.drawMonth - showCurrentAtPos,
Daniel@0 5338 drawYear = inst.drawYear;
Daniel@0 5339
Daniel@0 5340 if (drawMonth < 0) {
Daniel@0 5341 drawMonth += 12;
Daniel@0 5342 drawYear--;
Daniel@0 5343 }
Daniel@0 5344 if (maxDate) {
Daniel@0 5345 maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
Daniel@0 5346 maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
Daniel@0 5347 maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
Daniel@0 5348 while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
Daniel@0 5349 drawMonth--;
Daniel@0 5350 if (drawMonth < 0) {
Daniel@0 5351 drawMonth = 11;
Daniel@0 5352 drawYear--;
Daniel@0 5353 }
Daniel@0 5354 }
Daniel@0 5355 }
Daniel@0 5356 inst.drawMonth = drawMonth;
Daniel@0 5357 inst.drawYear = drawYear;
Daniel@0 5358
Daniel@0 5359 prevText = this._get(inst, "prevText");
Daniel@0 5360 prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
Daniel@0 5361 this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
Daniel@0 5362 this._getFormatConfig(inst)));
Daniel@0 5363
Daniel@0 5364 prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
Daniel@0 5365 "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
Daniel@0 5366 " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
Daniel@0 5367 (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>"));
Daniel@0 5368
Daniel@0 5369 nextText = this._get(inst, "nextText");
Daniel@0 5370 nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
Daniel@0 5371 this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
Daniel@0 5372 this._getFormatConfig(inst)));
Daniel@0 5373
Daniel@0 5374 next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
Daniel@0 5375 "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
Daniel@0 5376 " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
Daniel@0 5377 (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>"));
Daniel@0 5378
Daniel@0 5379 currentText = this._get(inst, "currentText");
Daniel@0 5380 gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
Daniel@0 5381 currentText = (!navigationAsDateFormat ? currentText :
Daniel@0 5382 this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
Daniel@0 5383
Daniel@0 5384 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'>" +
Daniel@0 5385 this._get(inst, "closeText") + "</button>" : "");
Daniel@0 5386
Daniel@0 5387 buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
Daniel@0 5388 (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'" +
Daniel@0 5389 ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
Daniel@0 5390
Daniel@0 5391 firstDay = parseInt(this._get(inst, "firstDay"),10);
Daniel@0 5392 firstDay = (isNaN(firstDay) ? 0 : firstDay);
Daniel@0 5393
Daniel@0 5394 showWeek = this._get(inst, "showWeek");
Daniel@0 5395 dayNames = this._get(inst, "dayNames");
Daniel@0 5396 dayNamesMin = this._get(inst, "dayNamesMin");
Daniel@0 5397 monthNames = this._get(inst, "monthNames");
Daniel@0 5398 monthNamesShort = this._get(inst, "monthNamesShort");
Daniel@0 5399 beforeShowDay = this._get(inst, "beforeShowDay");
Daniel@0 5400 showOtherMonths = this._get(inst, "showOtherMonths");
Daniel@0 5401 selectOtherMonths = this._get(inst, "selectOtherMonths");
Daniel@0 5402 defaultDate = this._getDefaultDate(inst);
Daniel@0 5403 html = "";
Daniel@0 5404 dow;
Daniel@0 5405 for (row = 0; row < numMonths[0]; row++) {
Daniel@0 5406 group = "";
Daniel@0 5407 this.maxRows = 4;
Daniel@0 5408 for (col = 0; col < numMonths[1]; col++) {
Daniel@0 5409 selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
Daniel@0 5410 cornerClass = " ui-corner-all";
Daniel@0 5411 calender = "";
Daniel@0 5412 if (isMultiMonth) {
Daniel@0 5413 calender += "<div class='ui-datepicker-group";
Daniel@0 5414 if (numMonths[1] > 1) {
Daniel@0 5415 switch (col) {
Daniel@0 5416 case 0: calender += " ui-datepicker-group-first";
Daniel@0 5417 cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
Daniel@0 5418 case numMonths[1]-1: calender += " ui-datepicker-group-last";
Daniel@0 5419 cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
Daniel@0 5420 default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
Daniel@0 5421 }
Daniel@0 5422 }
Daniel@0 5423 calender += "'>";
Daniel@0 5424 }
Daniel@0 5425 calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
Daniel@0 5426 (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
Daniel@0 5427 (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
Daniel@0 5428 this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
Daniel@0 5429 row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
Daniel@0 5430 "</div><table class='ui-datepicker-calendar'><thead>" +
Daniel@0 5431 "<tr>";
Daniel@0 5432 thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
Daniel@0 5433 for (dow = 0; dow < 7; dow++) { // days of the week
Daniel@0 5434 day = (dow + firstDay) % 7;
Daniel@0 5435 thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
Daniel@0 5436 "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
Daniel@0 5437 }
Daniel@0 5438 calender += thead + "</tr></thead><tbody>";
Daniel@0 5439 daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
Daniel@0 5440 if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
Daniel@0 5441 inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
Daniel@0 5442 }
Daniel@0 5443 leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
Daniel@0 5444 curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
Daniel@0 5445 numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
Daniel@0 5446 this.maxRows = numRows;
Daniel@0 5447 printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
Daniel@0 5448 for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
Daniel@0 5449 calender += "<tr>";
Daniel@0 5450 tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
Daniel@0 5451 this._get(inst, "calculateWeek")(printDate) + "</td>");
Daniel@0 5452 for (dow = 0; dow < 7; dow++) { // create date picker days
Daniel@0 5453 daySettings = (beforeShowDay ?
Daniel@0 5454 beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
Daniel@0 5455 otherMonth = (printDate.getMonth() !== drawMonth);
Daniel@0 5456 unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
Daniel@0 5457 (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
Daniel@0 5458 tbody += "<td class='" +
Daniel@0 5459 ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
Daniel@0 5460 (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
Daniel@0 5461 ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
Daniel@0 5462 (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
Daniel@0 5463 // or defaultDate is current printedDate and defaultDate is selectedDate
Daniel@0 5464 " " + this._dayOverClass : "") + // highlight selected day
Daniel@0 5465 (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") + // highlight unselectable days
Daniel@0 5466 (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
Daniel@0 5467 (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
Daniel@0 5468 (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
Daniel@0 5469 ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
Daniel@0 5470 (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
Daniel@0 5471 (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
Daniel@0 5472 (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
Daniel@0 5473 (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
Daniel@0 5474 (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
Daniel@0 5475 (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
Daniel@0 5476 "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
Daniel@0 5477 printDate.setDate(printDate.getDate() + 1);
Daniel@0 5478 printDate = this._daylightSavingAdjust(printDate);
Daniel@0 5479 }
Daniel@0 5480 calender += tbody + "</tr>";
Daniel@0 5481 }
Daniel@0 5482 drawMonth++;
Daniel@0 5483 if (drawMonth > 11) {
Daniel@0 5484 drawMonth = 0;
Daniel@0 5485 drawYear++;
Daniel@0 5486 }
Daniel@0 5487 calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
Daniel@0 5488 ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
Daniel@0 5489 group += calender;
Daniel@0 5490 }
Daniel@0 5491 html += group;
Daniel@0 5492 }
Daniel@0 5493 html += buttonPanel;
Daniel@0 5494 inst._keyEvent = false;
Daniel@0 5495 return html;
Daniel@0 5496 },
Daniel@0 5497
Daniel@0 5498 /* Generate the month and year header. */
Daniel@0 5499 _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
Daniel@0 5500 secondary, monthNames, monthNamesShort) {
Daniel@0 5501
Daniel@0 5502 var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
Daniel@0 5503 changeMonth = this._get(inst, "changeMonth"),
Daniel@0 5504 changeYear = this._get(inst, "changeYear"),
Daniel@0 5505 showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
Daniel@0 5506 html = "<div class='ui-datepicker-title'>",
Daniel@0 5507 monthHtml = "";
Daniel@0 5508
Daniel@0 5509 // month selection
Daniel@0 5510 if (secondary || !changeMonth) {
Daniel@0 5511 monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
Daniel@0 5512 } else {
Daniel@0 5513 inMinYear = (minDate && minDate.getFullYear() === drawYear);
Daniel@0 5514 inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
Daniel@0 5515 monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
Daniel@0 5516 for ( month = 0; month < 12; month++) {
Daniel@0 5517 if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
Daniel@0 5518 monthHtml += "<option value='" + month + "'" +
Daniel@0 5519 (month === drawMonth ? " selected='selected'" : "") +
Daniel@0 5520 ">" + monthNamesShort[month] + "</option>";
Daniel@0 5521 }
Daniel@0 5522 }
Daniel@0 5523 monthHtml += "</select>";
Daniel@0 5524 }
Daniel@0 5525
Daniel@0 5526 if (!showMonthAfterYear) {
Daniel@0 5527 html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
Daniel@0 5528 }
Daniel@0 5529
Daniel@0 5530 // year selection
Daniel@0 5531 if ( !inst.yearshtml ) {
Daniel@0 5532 inst.yearshtml = "";
Daniel@0 5533 if (secondary || !changeYear) {
Daniel@0 5534 html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
Daniel@0 5535 } else {
Daniel@0 5536 // determine range of years to display
Daniel@0 5537 years = this._get(inst, "yearRange").split(":");
Daniel@0 5538 thisYear = new Date().getFullYear();
Daniel@0 5539 determineYear = function(value) {
Daniel@0 5540 var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
Daniel@0 5541 (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
Daniel@0 5542 parseInt(value, 10)));
Daniel@0 5543 return (isNaN(year) ? thisYear : year);
Daniel@0 5544 };
Daniel@0 5545 year = determineYear(years[0]);
Daniel@0 5546 endYear = Math.max(year, determineYear(years[1] || ""));
Daniel@0 5547 year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
Daniel@0 5548 endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
Daniel@0 5549 inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
Daniel@0 5550 for (; year <= endYear; year++) {
Daniel@0 5551 inst.yearshtml += "<option value='" + year + "'" +
Daniel@0 5552 (year === drawYear ? " selected='selected'" : "") +
Daniel@0 5553 ">" + year + "</option>";
Daniel@0 5554 }
Daniel@0 5555 inst.yearshtml += "</select>";
Daniel@0 5556
Daniel@0 5557 html += inst.yearshtml;
Daniel@0 5558 inst.yearshtml = null;
Daniel@0 5559 }
Daniel@0 5560 }
Daniel@0 5561
Daniel@0 5562 html += this._get(inst, "yearSuffix");
Daniel@0 5563 if (showMonthAfterYear) {
Daniel@0 5564 html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
Daniel@0 5565 }
Daniel@0 5566 html += "</div>"; // Close datepicker_header
Daniel@0 5567 return html;
Daniel@0 5568 },
Daniel@0 5569
Daniel@0 5570 /* Adjust one of the date sub-fields. */
Daniel@0 5571 _adjustInstDate: function(inst, offset, period) {
Daniel@0 5572 var year = inst.drawYear + (period === "Y" ? offset : 0),
Daniel@0 5573 month = inst.drawMonth + (period === "M" ? offset : 0),
Daniel@0 5574 day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
Daniel@0 5575 date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
Daniel@0 5576
Daniel@0 5577 inst.selectedDay = date.getDate();
Daniel@0 5578 inst.drawMonth = inst.selectedMonth = date.getMonth();
Daniel@0 5579 inst.drawYear = inst.selectedYear = date.getFullYear();
Daniel@0 5580 if (period === "M" || period === "Y") {
Daniel@0 5581 this._notifyChange(inst);
Daniel@0 5582 }
Daniel@0 5583 },
Daniel@0 5584
Daniel@0 5585 /* Ensure a date is within any min/max bounds. */
Daniel@0 5586 _restrictMinMax: function(inst, date) {
Daniel@0 5587 var minDate = this._getMinMaxDate(inst, "min"),
Daniel@0 5588 maxDate = this._getMinMaxDate(inst, "max"),
Daniel@0 5589 newDate = (minDate && date < minDate ? minDate : date);
Daniel@0 5590 return (maxDate && newDate > maxDate ? maxDate : newDate);
Daniel@0 5591 },
Daniel@0 5592
Daniel@0 5593 /* Notify change of month/year. */
Daniel@0 5594 _notifyChange: function(inst) {
Daniel@0 5595 var onChange = this._get(inst, "onChangeMonthYear");
Daniel@0 5596 if (onChange) {
Daniel@0 5597 onChange.apply((inst.input ? inst.input[0] : null),
Daniel@0 5598 [inst.selectedYear, inst.selectedMonth + 1, inst]);
Daniel@0 5599 }
Daniel@0 5600 },
Daniel@0 5601
Daniel@0 5602 /* Determine the number of months to show. */
Daniel@0 5603 _getNumberOfMonths: function(inst) {
Daniel@0 5604 var numMonths = this._get(inst, "numberOfMonths");
Daniel@0 5605 return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
Daniel@0 5606 },
Daniel@0 5607
Daniel@0 5608 /* Determine the current maximum date - ensure no time components are set. */
Daniel@0 5609 _getMinMaxDate: function(inst, minMax) {
Daniel@0 5610 return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
Daniel@0 5611 },
Daniel@0 5612
Daniel@0 5613 /* Find the number of days in a given month. */
Daniel@0 5614 _getDaysInMonth: function(year, month) {
Daniel@0 5615 return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
Daniel@0 5616 },
Daniel@0 5617
Daniel@0 5618 /* Find the day of the week of the first of a month. */
Daniel@0 5619 _getFirstDayOfMonth: function(year, month) {
Daniel@0 5620 return new Date(year, month, 1).getDay();
Daniel@0 5621 },
Daniel@0 5622
Daniel@0 5623 /* Determines if we should allow a "next/prev" month display change. */
Daniel@0 5624 _canAdjustMonth: function(inst, offset, curYear, curMonth) {
Daniel@0 5625 var numMonths = this._getNumberOfMonths(inst),
Daniel@0 5626 date = this._daylightSavingAdjust(new Date(curYear,
Daniel@0 5627 curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
Daniel@0 5628
Daniel@0 5629 if (offset < 0) {
Daniel@0 5630 date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
Daniel@0 5631 }
Daniel@0 5632 return this._isInRange(inst, date);
Daniel@0 5633 },
Daniel@0 5634
Daniel@0 5635 /* Is the given date in the accepted range? */
Daniel@0 5636 _isInRange: function(inst, date) {
Daniel@0 5637 var yearSplit, currentYear,
Daniel@0 5638 minDate = this._getMinMaxDate(inst, "min"),
Daniel@0 5639 maxDate = this._getMinMaxDate(inst, "max"),
Daniel@0 5640 minYear = null,
Daniel@0 5641 maxYear = null,
Daniel@0 5642 years = this._get(inst, "yearRange");
Daniel@0 5643 if (years){
Daniel@0 5644 yearSplit = years.split(":");
Daniel@0 5645 currentYear = new Date().getFullYear();
Daniel@0 5646 minYear = parseInt(yearSplit[0], 10);
Daniel@0 5647 maxYear = parseInt(yearSplit[1], 10);
Daniel@0 5648 if ( yearSplit[0].match(/[+\-].*/) ) {
Daniel@0 5649 minYear += currentYear;
Daniel@0 5650 }
Daniel@0 5651 if ( yearSplit[1].match(/[+\-].*/) ) {
Daniel@0 5652 maxYear += currentYear;
Daniel@0 5653 }
Daniel@0 5654 }
Daniel@0 5655
Daniel@0 5656 return ((!minDate || date.getTime() >= minDate.getTime()) &&
Daniel@0 5657 (!maxDate || date.getTime() <= maxDate.getTime()) &&
Daniel@0 5658 (!minYear || date.getFullYear() >= minYear) &&
Daniel@0 5659 (!maxYear || date.getFullYear() <= maxYear));
Daniel@0 5660 },
Daniel@0 5661
Daniel@0 5662 /* Provide the configuration settings for formatting/parsing. */
Daniel@0 5663 _getFormatConfig: function(inst) {
Daniel@0 5664 var shortYearCutoff = this._get(inst, "shortYearCutoff");
Daniel@0 5665 shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
Daniel@0 5666 new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
Daniel@0 5667 return {shortYearCutoff: shortYearCutoff,
Daniel@0 5668 dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
Daniel@0 5669 monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
Daniel@0 5670 },
Daniel@0 5671
Daniel@0 5672 /* Format the given date for display. */
Daniel@0 5673 _formatDate: function(inst, day, month, year) {
Daniel@0 5674 if (!day) {
Daniel@0 5675 inst.currentDay = inst.selectedDay;
Daniel@0 5676 inst.currentMonth = inst.selectedMonth;
Daniel@0 5677 inst.currentYear = inst.selectedYear;
Daniel@0 5678 }
Daniel@0 5679 var date = (day ? (typeof day === "object" ? day :
Daniel@0 5680 this._daylightSavingAdjust(new Date(year, month, day))) :
Daniel@0 5681 this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
Daniel@0 5682 return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
Daniel@0 5683 }
Daniel@0 5684 });
Daniel@0 5685
Daniel@0 5686 /*
Daniel@0 5687 * Bind hover events for datepicker elements.
Daniel@0 5688 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
Daniel@0 5689 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
Daniel@0 5690 */
Daniel@0 5691 function datepicker_bindHover(dpDiv) {
Daniel@0 5692 var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
Daniel@0 5693 return dpDiv.delegate(selector, "mouseout", function() {
Daniel@0 5694 $(this).removeClass("ui-state-hover");
Daniel@0 5695 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
Daniel@0 5696 $(this).removeClass("ui-datepicker-prev-hover");
Daniel@0 5697 }
Daniel@0 5698 if (this.className.indexOf("ui-datepicker-next") !== -1) {
Daniel@0 5699 $(this).removeClass("ui-datepicker-next-hover");
Daniel@0 5700 }
Daniel@0 5701 })
Daniel@0 5702 .delegate(selector, "mouseover", function(){
Daniel@0 5703 if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? dpDiv.parent()[0] : datepicker_instActive.input[0])) {
Daniel@0 5704 $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
Daniel@0 5705 $(this).addClass("ui-state-hover");
Daniel@0 5706 if (this.className.indexOf("ui-datepicker-prev") !== -1) {
Daniel@0 5707 $(this).addClass("ui-datepicker-prev-hover");
Daniel@0 5708 }
Daniel@0 5709 if (this.className.indexOf("ui-datepicker-next") !== -1) {
Daniel@0 5710 $(this).addClass("ui-datepicker-next-hover");
Daniel@0 5711 }
Daniel@0 5712 }
Daniel@0 5713 });
Daniel@0 5714 }
Daniel@0 5715
Daniel@0 5716 /* jQuery extend now ignores nulls! */
Daniel@0 5717 function datepicker_extendRemove(target, props) {
Daniel@0 5718 $.extend(target, props);
Daniel@0 5719 for (var name in props) {
Daniel@0 5720 if (props[name] == null) {
Daniel@0 5721 target[name] = props[name];
Daniel@0 5722 }
Daniel@0 5723 }
Daniel@0 5724 return target;
Daniel@0 5725 }
Daniel@0 5726
Daniel@0 5727 /* Invoke the datepicker functionality.
Daniel@0 5728 @param options string - a command, optionally followed by additional parameters or
Daniel@0 5729 Object - settings for attaching new datepicker functionality
Daniel@0 5730 @return jQuery object */
Daniel@0 5731 $.fn.datepicker = function(options){
Daniel@0 5732
Daniel@0 5733 /* Verify an empty collection wasn't passed - Fixes #6976 */
Daniel@0 5734 if ( !this.length ) {
Daniel@0 5735 return this;
Daniel@0 5736 }
Daniel@0 5737
Daniel@0 5738 /* Initialise the date picker. */
Daniel@0 5739 if (!$.datepicker.initialized) {
Daniel@0 5740 $(document).mousedown($.datepicker._checkExternalClick);
Daniel@0 5741 $.datepicker.initialized = true;
Daniel@0 5742 }
Daniel@0 5743
Daniel@0 5744 /* Append datepicker main container to body if not exist. */
Daniel@0 5745 if ($("#"+$.datepicker._mainDivId).length === 0) {
Daniel@0 5746 $("body").append($.datepicker.dpDiv);
Daniel@0 5747 }
Daniel@0 5748
Daniel@0 5749 var otherArgs = Array.prototype.slice.call(arguments, 1);
Daniel@0 5750 if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
Daniel@0 5751 return $.datepicker["_" + options + "Datepicker"].
Daniel@0 5752 apply($.datepicker, [this[0]].concat(otherArgs));
Daniel@0 5753 }
Daniel@0 5754 if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
Daniel@0 5755 return $.datepicker["_" + options + "Datepicker"].
Daniel@0 5756 apply($.datepicker, [this[0]].concat(otherArgs));
Daniel@0 5757 }
Daniel@0 5758 return this.each(function() {
Daniel@0 5759 typeof options === "string" ?
Daniel@0 5760 $.datepicker["_" + options + "Datepicker"].
Daniel@0 5761 apply($.datepicker, [this].concat(otherArgs)) :
Daniel@0 5762 $.datepicker._attachDatepicker(this, options);
Daniel@0 5763 });
Daniel@0 5764 };
Daniel@0 5765
Daniel@0 5766 $.datepicker = new Datepicker(); // singleton instance
Daniel@0 5767 $.datepicker.initialized = false;
Daniel@0 5768 $.datepicker.uuid = new Date().getTime();
Daniel@0 5769 $.datepicker.version = "1.11.0";
Daniel@0 5770
Daniel@0 5771 var datepicker = $.datepicker;
Daniel@0 5772
Daniel@0 5773
Daniel@0 5774 /*!
Daniel@0 5775 * jQuery UI Draggable 1.11.0
Daniel@0 5776 * http://jqueryui.com
Daniel@0 5777 *
Daniel@0 5778 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 5779 * Released under the MIT license.
Daniel@0 5780 * http://jquery.org/license
Daniel@0 5781 *
Daniel@0 5782 * http://api.jqueryui.com/draggable/
Daniel@0 5783 */
Daniel@0 5784
Daniel@0 5785
Daniel@0 5786 $.widget("ui.draggable", $.ui.mouse, {
Daniel@0 5787 version: "1.11.0",
Daniel@0 5788 widgetEventPrefix: "drag",
Daniel@0 5789 options: {
Daniel@0 5790 addClasses: true,
Daniel@0 5791 appendTo: "parent",
Daniel@0 5792 axis: false,
Daniel@0 5793 connectToSortable: false,
Daniel@0 5794 containment: false,
Daniel@0 5795 cursor: "auto",
Daniel@0 5796 cursorAt: false,
Daniel@0 5797 grid: false,
Daniel@0 5798 handle: false,
Daniel@0 5799 helper: "original",
Daniel@0 5800 iframeFix: false,
Daniel@0 5801 opacity: false,
Daniel@0 5802 refreshPositions: false,
Daniel@0 5803 revert: false,
Daniel@0 5804 revertDuration: 500,
Daniel@0 5805 scope: "default",
Daniel@0 5806 scroll: true,
Daniel@0 5807 scrollSensitivity: 20,
Daniel@0 5808 scrollSpeed: 20,
Daniel@0 5809 snap: false,
Daniel@0 5810 snapMode: "both",
Daniel@0 5811 snapTolerance: 20,
Daniel@0 5812 stack: false,
Daniel@0 5813 zIndex: false,
Daniel@0 5814
Daniel@0 5815 // callbacks
Daniel@0 5816 drag: null,
Daniel@0 5817 start: null,
Daniel@0 5818 stop: null
Daniel@0 5819 },
Daniel@0 5820 _create: function() {
Daniel@0 5821
Daniel@0 5822 if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) {
Daniel@0 5823 this.element[0].style.position = "relative";
Daniel@0 5824 }
Daniel@0 5825 if (this.options.addClasses){
Daniel@0 5826 this.element.addClass("ui-draggable");
Daniel@0 5827 }
Daniel@0 5828 if (this.options.disabled){
Daniel@0 5829 this.element.addClass("ui-draggable-disabled");
Daniel@0 5830 }
Daniel@0 5831 this._setHandleClassName();
Daniel@0 5832
Daniel@0 5833 this._mouseInit();
Daniel@0 5834 },
Daniel@0 5835
Daniel@0 5836 _setOption: function( key, value ) {
Daniel@0 5837 this._super( key, value );
Daniel@0 5838 if ( key === "handle" ) {
Daniel@0 5839 this._setHandleClassName();
Daniel@0 5840 }
Daniel@0 5841 },
Daniel@0 5842
Daniel@0 5843 _destroy: function() {
Daniel@0 5844 if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
Daniel@0 5845 this.destroyOnClear = true;
Daniel@0 5846 return;
Daniel@0 5847 }
Daniel@0 5848 this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
Daniel@0 5849 this._removeHandleClassName();
Daniel@0 5850 this._mouseDestroy();
Daniel@0 5851 },
Daniel@0 5852
Daniel@0 5853 _mouseCapture: function(event) {
Daniel@0 5854
Daniel@0 5855 var document = this.document[ 0 ],
Daniel@0 5856 o = this.options;
Daniel@0 5857
Daniel@0 5858 // support: IE9
Daniel@0 5859 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
Daniel@0 5860 try {
Daniel@0 5861 // Support: IE9+
Daniel@0 5862 // If the <body> is blurred, IE will switch windows, see #9520
Daniel@0 5863 if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
Daniel@0 5864 // Blur any element that currently has focus, see #4261
Daniel@0 5865 $( document.activeElement ).blur();
Daniel@0 5866 }
Daniel@0 5867 } catch ( error ) {}
Daniel@0 5868
Daniel@0 5869 // among others, prevent a drag on a resizable-handle
Daniel@0 5870 if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
Daniel@0 5871 return false;
Daniel@0 5872 }
Daniel@0 5873
Daniel@0 5874 //Quit if we're not on a valid handle
Daniel@0 5875 this.handle = this._getHandle(event);
Daniel@0 5876 if (!this.handle) {
Daniel@0 5877 return false;
Daniel@0 5878 }
Daniel@0 5879
Daniel@0 5880 $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() {
Daniel@0 5881 $("<div class='ui-draggable-iframeFix' style='background: #fff;'></div>")
Daniel@0 5882 .css({
Daniel@0 5883 width: this.offsetWidth + "px", height: this.offsetHeight + "px",
Daniel@0 5884 position: "absolute", opacity: "0.001", zIndex: 1000
Daniel@0 5885 })
Daniel@0 5886 .css($(this).offset())
Daniel@0 5887 .appendTo("body");
Daniel@0 5888 });
Daniel@0 5889
Daniel@0 5890 return true;
Daniel@0 5891
Daniel@0 5892 },
Daniel@0 5893
Daniel@0 5894 _mouseStart: function(event) {
Daniel@0 5895
Daniel@0 5896 var o = this.options;
Daniel@0 5897
Daniel@0 5898 //Create and append the visible helper
Daniel@0 5899 this.helper = this._createHelper(event);
Daniel@0 5900
Daniel@0 5901 this.helper.addClass("ui-draggable-dragging");
Daniel@0 5902
Daniel@0 5903 //Cache the helper size
Daniel@0 5904 this._cacheHelperProportions();
Daniel@0 5905
Daniel@0 5906 //If ddmanager is used for droppables, set the global draggable
Daniel@0 5907 if ($.ui.ddmanager) {
Daniel@0 5908 $.ui.ddmanager.current = this;
Daniel@0 5909 }
Daniel@0 5910
Daniel@0 5911 /*
Daniel@0 5912 * - Position generation -
Daniel@0 5913 * This block generates everything position related - it's the core of draggables.
Daniel@0 5914 */
Daniel@0 5915
Daniel@0 5916 //Cache the margins of the original element
Daniel@0 5917 this._cacheMargins();
Daniel@0 5918
Daniel@0 5919 //Store the helper's css position
Daniel@0 5920 this.cssPosition = this.helper.css( "position" );
Daniel@0 5921 this.scrollParent = this.helper.scrollParent();
Daniel@0 5922 this.offsetParent = this.helper.offsetParent();
Daniel@0 5923 this.offsetParentCssPosition = this.offsetParent.css( "position" );
Daniel@0 5924
Daniel@0 5925 //The element's absolute position on the page minus margins
Daniel@0 5926 this.offset = this.positionAbs = this.element.offset();
Daniel@0 5927 this.offset = {
Daniel@0 5928 top: this.offset.top - this.margins.top,
Daniel@0 5929 left: this.offset.left - this.margins.left
Daniel@0 5930 };
Daniel@0 5931
Daniel@0 5932 //Reset scroll cache
Daniel@0 5933 this.offset.scroll = false;
Daniel@0 5934
Daniel@0 5935 $.extend(this.offset, {
Daniel@0 5936 click: { //Where the click happened, relative to the element
Daniel@0 5937 left: event.pageX - this.offset.left,
Daniel@0 5938 top: event.pageY - this.offset.top
Daniel@0 5939 },
Daniel@0 5940 parent: this._getParentOffset(),
Daniel@0 5941 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
Daniel@0 5942 });
Daniel@0 5943
Daniel@0 5944 //Generate the original position
Daniel@0 5945 this.originalPosition = this.position = this._generatePosition( event, false );
Daniel@0 5946 this.originalPageX = event.pageX;
Daniel@0 5947 this.originalPageY = event.pageY;
Daniel@0 5948
Daniel@0 5949 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
Daniel@0 5950 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
Daniel@0 5951
Daniel@0 5952 //Set a containment if given in the options
Daniel@0 5953 this._setContainment();
Daniel@0 5954
Daniel@0 5955 //Trigger event + callbacks
Daniel@0 5956 if (this._trigger("start", event) === false) {
Daniel@0 5957 this._clear();
Daniel@0 5958 return false;
Daniel@0 5959 }
Daniel@0 5960
Daniel@0 5961 //Recache the helper size
Daniel@0 5962 this._cacheHelperProportions();
Daniel@0 5963
Daniel@0 5964 //Prepare the droppable offsets
Daniel@0 5965 if ($.ui.ddmanager && !o.dropBehaviour) {
Daniel@0 5966 $.ui.ddmanager.prepareOffsets(this, event);
Daniel@0 5967 }
Daniel@0 5968
Daniel@0 5969 this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
Daniel@0 5970
Daniel@0 5971 //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
Daniel@0 5972 if ( $.ui.ddmanager ) {
Daniel@0 5973 $.ui.ddmanager.dragStart(this, event);
Daniel@0 5974 }
Daniel@0 5975
Daniel@0 5976 return true;
Daniel@0 5977 },
Daniel@0 5978
Daniel@0 5979 _mouseDrag: function(event, noPropagation) {
Daniel@0 5980 // reset any necessary cached properties (see #5009)
Daniel@0 5981 if ( this.offsetParentCssPosition === "fixed" ) {
Daniel@0 5982 this.offset.parent = this._getParentOffset();
Daniel@0 5983 }
Daniel@0 5984
Daniel@0 5985 //Compute the helpers position
Daniel@0 5986 this.position = this._generatePosition( event, true );
Daniel@0 5987 this.positionAbs = this._convertPositionTo("absolute");
Daniel@0 5988
Daniel@0 5989 //Call plugins and callbacks and use the resulting position if something is returned
Daniel@0 5990 if (!noPropagation) {
Daniel@0 5991 var ui = this._uiHash();
Daniel@0 5992 if (this._trigger("drag", event, ui) === false) {
Daniel@0 5993 this._mouseUp({});
Daniel@0 5994 return false;
Daniel@0 5995 }
Daniel@0 5996 this.position = ui.position;
Daniel@0 5997 }
Daniel@0 5998
Daniel@0 5999 this.helper[ 0 ].style.left = this.position.left + "px";
Daniel@0 6000 this.helper[ 0 ].style.top = this.position.top + "px";
Daniel@0 6001
Daniel@0 6002 if ($.ui.ddmanager) {
Daniel@0 6003 $.ui.ddmanager.drag(this, event);
Daniel@0 6004 }
Daniel@0 6005
Daniel@0 6006 return false;
Daniel@0 6007 },
Daniel@0 6008
Daniel@0 6009 _mouseStop: function(event) {
Daniel@0 6010
Daniel@0 6011 //If we are using droppables, inform the manager about the drop
Daniel@0 6012 var that = this,
Daniel@0 6013 dropped = false;
Daniel@0 6014 if ($.ui.ddmanager && !this.options.dropBehaviour) {
Daniel@0 6015 dropped = $.ui.ddmanager.drop(this, event);
Daniel@0 6016 }
Daniel@0 6017
Daniel@0 6018 //if a drop comes from outside (a sortable)
Daniel@0 6019 if (this.dropped) {
Daniel@0 6020 dropped = this.dropped;
Daniel@0 6021 this.dropped = false;
Daniel@0 6022 }
Daniel@0 6023
Daniel@0 6024 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))) {
Daniel@0 6025 $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
Daniel@0 6026 if (that._trigger("stop", event) !== false) {
Daniel@0 6027 that._clear();
Daniel@0 6028 }
Daniel@0 6029 });
Daniel@0 6030 } else {
Daniel@0 6031 if (this._trigger("stop", event) !== false) {
Daniel@0 6032 this._clear();
Daniel@0 6033 }
Daniel@0 6034 }
Daniel@0 6035
Daniel@0 6036 return false;
Daniel@0 6037 },
Daniel@0 6038
Daniel@0 6039 _mouseUp: function(event) {
Daniel@0 6040 //Remove frame helpers
Daniel@0 6041 $("div.ui-draggable-iframeFix").each(function() {
Daniel@0 6042 this.parentNode.removeChild(this);
Daniel@0 6043 });
Daniel@0 6044
Daniel@0 6045 //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
Daniel@0 6046 if ( $.ui.ddmanager ) {
Daniel@0 6047 $.ui.ddmanager.dragStop(this, event);
Daniel@0 6048 }
Daniel@0 6049
Daniel@0 6050 // The interaction is over; whether or not the click resulted in a drag, focus the element
Daniel@0 6051 this.element.focus();
Daniel@0 6052
Daniel@0 6053 return $.ui.mouse.prototype._mouseUp.call(this, event);
Daniel@0 6054 },
Daniel@0 6055
Daniel@0 6056 cancel: function() {
Daniel@0 6057
Daniel@0 6058 if (this.helper.is(".ui-draggable-dragging")) {
Daniel@0 6059 this._mouseUp({});
Daniel@0 6060 } else {
Daniel@0 6061 this._clear();
Daniel@0 6062 }
Daniel@0 6063
Daniel@0 6064 return this;
Daniel@0 6065
Daniel@0 6066 },
Daniel@0 6067
Daniel@0 6068 _getHandle: function(event) {
Daniel@0 6069 return this.options.handle ?
Daniel@0 6070 !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
Daniel@0 6071 true;
Daniel@0 6072 },
Daniel@0 6073
Daniel@0 6074 _setHandleClassName: function() {
Daniel@0 6075 this._removeHandleClassName();
Daniel@0 6076 $( this.options.handle || this.element ).addClass( "ui-draggable-handle" );
Daniel@0 6077 },
Daniel@0 6078
Daniel@0 6079 _removeHandleClassName: function() {
Daniel@0 6080 this.element.find( ".ui-draggable-handle" )
Daniel@0 6081 .addBack()
Daniel@0 6082 .removeClass( "ui-draggable-handle" );
Daniel@0 6083 },
Daniel@0 6084
Daniel@0 6085 _createHelper: function(event) {
Daniel@0 6086
Daniel@0 6087 var o = this.options,
Daniel@0 6088 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[ 0 ], [ event ])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element);
Daniel@0 6089
Daniel@0 6090 if (!helper.parents("body").length) {
Daniel@0 6091 helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
Daniel@0 6092 }
Daniel@0 6093
Daniel@0 6094 if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
Daniel@0 6095 helper.css("position", "absolute");
Daniel@0 6096 }
Daniel@0 6097
Daniel@0 6098 return helper;
Daniel@0 6099
Daniel@0 6100 },
Daniel@0 6101
Daniel@0 6102 _adjustOffsetFromHelper: function(obj) {
Daniel@0 6103 if (typeof obj === "string") {
Daniel@0 6104 obj = obj.split(" ");
Daniel@0 6105 }
Daniel@0 6106 if ($.isArray(obj)) {
Daniel@0 6107 obj = { left: +obj[0], top: +obj[1] || 0 };
Daniel@0 6108 }
Daniel@0 6109 if ("left" in obj) {
Daniel@0 6110 this.offset.click.left = obj.left + this.margins.left;
Daniel@0 6111 }
Daniel@0 6112 if ("right" in obj) {
Daniel@0 6113 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
Daniel@0 6114 }
Daniel@0 6115 if ("top" in obj) {
Daniel@0 6116 this.offset.click.top = obj.top + this.margins.top;
Daniel@0 6117 }
Daniel@0 6118 if ("bottom" in obj) {
Daniel@0 6119 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
Daniel@0 6120 }
Daniel@0 6121 },
Daniel@0 6122
Daniel@0 6123 _isRootNode: function( element ) {
Daniel@0 6124 return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
Daniel@0 6125 },
Daniel@0 6126
Daniel@0 6127 _getParentOffset: function() {
Daniel@0 6128
Daniel@0 6129 //Get the offsetParent and cache its position
Daniel@0 6130 var po = this.offsetParent.offset(),
Daniel@0 6131 document = this.document[ 0 ];
Daniel@0 6132
Daniel@0 6133 // This is a special case where we need to modify a offset calculated on start, since the following happened:
Daniel@0 6134 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
Daniel@0 6135 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
Daniel@0 6136 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
Daniel@0 6137 if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
Daniel@0 6138 po.left += this.scrollParent.scrollLeft();
Daniel@0 6139 po.top += this.scrollParent.scrollTop();
Daniel@0 6140 }
Daniel@0 6141
Daniel@0 6142 if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
Daniel@0 6143 po = { top: 0, left: 0 };
Daniel@0 6144 }
Daniel@0 6145
Daniel@0 6146 return {
Daniel@0 6147 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
Daniel@0 6148 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
Daniel@0 6149 };
Daniel@0 6150
Daniel@0 6151 },
Daniel@0 6152
Daniel@0 6153 _getRelativeOffset: function() {
Daniel@0 6154 if ( this.cssPosition !== "relative" ) {
Daniel@0 6155 return { top: 0, left: 0 };
Daniel@0 6156 }
Daniel@0 6157
Daniel@0 6158 var p = this.element.position(),
Daniel@0 6159 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
Daniel@0 6160
Daniel@0 6161 return {
Daniel@0 6162 top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
Daniel@0 6163 left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
Daniel@0 6164 };
Daniel@0 6165
Daniel@0 6166 },
Daniel@0 6167
Daniel@0 6168 _cacheMargins: function() {
Daniel@0 6169 this.margins = {
Daniel@0 6170 left: (parseInt(this.element.css("marginLeft"),10) || 0),
Daniel@0 6171 top: (parseInt(this.element.css("marginTop"),10) || 0),
Daniel@0 6172 right: (parseInt(this.element.css("marginRight"),10) || 0),
Daniel@0 6173 bottom: (parseInt(this.element.css("marginBottom"),10) || 0)
Daniel@0 6174 };
Daniel@0 6175 },
Daniel@0 6176
Daniel@0 6177 _cacheHelperProportions: function() {
Daniel@0 6178 this.helperProportions = {
Daniel@0 6179 width: this.helper.outerWidth(),
Daniel@0 6180 height: this.helper.outerHeight()
Daniel@0 6181 };
Daniel@0 6182 },
Daniel@0 6183
Daniel@0 6184 _setContainment: function() {
Daniel@0 6185
Daniel@0 6186 var over, c, ce,
Daniel@0 6187 o = this.options,
Daniel@0 6188 document = this.document[ 0 ];
Daniel@0 6189
Daniel@0 6190 this.relative_container = null;
Daniel@0 6191
Daniel@0 6192 if ( !o.containment ) {
Daniel@0 6193 this.containment = null;
Daniel@0 6194 return;
Daniel@0 6195 }
Daniel@0 6196
Daniel@0 6197 if ( o.containment === "window" ) {
Daniel@0 6198 this.containment = [
Daniel@0 6199 $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
Daniel@0 6200 $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
Daniel@0 6201 $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
Daniel@0 6202 $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
Daniel@0 6203 ];
Daniel@0 6204 return;
Daniel@0 6205 }
Daniel@0 6206
Daniel@0 6207 if ( o.containment === "document") {
Daniel@0 6208 this.containment = [
Daniel@0 6209 0,
Daniel@0 6210 0,
Daniel@0 6211 $( document ).width() - this.helperProportions.width - this.margins.left,
Daniel@0 6212 ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
Daniel@0 6213 ];
Daniel@0 6214 return;
Daniel@0 6215 }
Daniel@0 6216
Daniel@0 6217 if ( o.containment.constructor === Array ) {
Daniel@0 6218 this.containment = o.containment;
Daniel@0 6219 return;
Daniel@0 6220 }
Daniel@0 6221
Daniel@0 6222 if ( o.containment === "parent" ) {
Daniel@0 6223 o.containment = this.helper[ 0 ].parentNode;
Daniel@0 6224 }
Daniel@0 6225
Daniel@0 6226 c = $( o.containment );
Daniel@0 6227 ce = c[ 0 ];
Daniel@0 6228
Daniel@0 6229 if ( !ce ) {
Daniel@0 6230 return;
Daniel@0 6231 }
Daniel@0 6232
Daniel@0 6233 over = c.css( "overflow" ) !== "hidden";
Daniel@0 6234
Daniel@0 6235 this.containment = [
Daniel@0 6236 ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
Daniel@0 6237 ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
Daniel@0 6238 ( 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,
Daniel@0 6239 ( 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
Daniel@0 6240 ];
Daniel@0 6241 this.relative_container = c;
Daniel@0 6242 },
Daniel@0 6243
Daniel@0 6244 _convertPositionTo: function(d, pos) {
Daniel@0 6245
Daniel@0 6246 if (!pos) {
Daniel@0 6247 pos = this.position;
Daniel@0 6248 }
Daniel@0 6249
Daniel@0 6250 var mod = d === "absolute" ? 1 : -1,
Daniel@0 6251 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
Daniel@0 6252
Daniel@0 6253 return {
Daniel@0 6254 top: (
Daniel@0 6255 pos.top + // The absolute mouse position
Daniel@0 6256 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 6257 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
Daniel@0 6258 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
Daniel@0 6259 ),
Daniel@0 6260 left: (
Daniel@0 6261 pos.left + // The absolute mouse position
Daniel@0 6262 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 6263 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
Daniel@0 6264 ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
Daniel@0 6265 )
Daniel@0 6266 };
Daniel@0 6267
Daniel@0 6268 },
Daniel@0 6269
Daniel@0 6270 _generatePosition: function( event, constrainPosition ) {
Daniel@0 6271
Daniel@0 6272 var containment, co, top, left,
Daniel@0 6273 o = this.options,
Daniel@0 6274 scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
Daniel@0 6275 pageX = event.pageX,
Daniel@0 6276 pageY = event.pageY;
Daniel@0 6277
Daniel@0 6278 // Cache the scroll
Daniel@0 6279 if ( !scrollIsRootNode || !this.offset.scroll ) {
Daniel@0 6280 this.offset.scroll = {
Daniel@0 6281 top: this.scrollParent.scrollTop(),
Daniel@0 6282 left: this.scrollParent.scrollLeft()
Daniel@0 6283 };
Daniel@0 6284 }
Daniel@0 6285
Daniel@0 6286 /*
Daniel@0 6287 * - Position constraining -
Daniel@0 6288 * Constrain the position to a mix of grid, containment.
Daniel@0 6289 */
Daniel@0 6290
Daniel@0 6291 // If we are not dragging yet, we won't check for options
Daniel@0 6292 if ( constrainPosition ) {
Daniel@0 6293 if ( this.containment ) {
Daniel@0 6294 if ( this.relative_container ){
Daniel@0 6295 co = this.relative_container.offset();
Daniel@0 6296 containment = [
Daniel@0 6297 this.containment[ 0 ] + co.left,
Daniel@0 6298 this.containment[ 1 ] + co.top,
Daniel@0 6299 this.containment[ 2 ] + co.left,
Daniel@0 6300 this.containment[ 3 ] + co.top
Daniel@0 6301 ];
Daniel@0 6302 } else {
Daniel@0 6303 containment = this.containment;
Daniel@0 6304 }
Daniel@0 6305
Daniel@0 6306 if (event.pageX - this.offset.click.left < containment[0]) {
Daniel@0 6307 pageX = containment[0] + this.offset.click.left;
Daniel@0 6308 }
Daniel@0 6309 if (event.pageY - this.offset.click.top < containment[1]) {
Daniel@0 6310 pageY = containment[1] + this.offset.click.top;
Daniel@0 6311 }
Daniel@0 6312 if (event.pageX - this.offset.click.left > containment[2]) {
Daniel@0 6313 pageX = containment[2] + this.offset.click.left;
Daniel@0 6314 }
Daniel@0 6315 if (event.pageY - this.offset.click.top > containment[3]) {
Daniel@0 6316 pageY = containment[3] + this.offset.click.top;
Daniel@0 6317 }
Daniel@0 6318 }
Daniel@0 6319
Daniel@0 6320 if (o.grid) {
Daniel@0 6321 //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
Daniel@0 6322 top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
Daniel@0 6323 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;
Daniel@0 6324
Daniel@0 6325 left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
Daniel@0 6326 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;
Daniel@0 6327 }
Daniel@0 6328
Daniel@0 6329 if ( o.axis === "y" ) {
Daniel@0 6330 pageX = this.originalPageX;
Daniel@0 6331 }
Daniel@0 6332
Daniel@0 6333 if ( o.axis === "x" ) {
Daniel@0 6334 pageY = this.originalPageY;
Daniel@0 6335 }
Daniel@0 6336 }
Daniel@0 6337
Daniel@0 6338 return {
Daniel@0 6339 top: (
Daniel@0 6340 pageY - // The absolute mouse position
Daniel@0 6341 this.offset.click.top - // Click offset (relative to the element)
Daniel@0 6342 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 6343 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
Daniel@0 6344 ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
Daniel@0 6345 ),
Daniel@0 6346 left: (
Daniel@0 6347 pageX - // The absolute mouse position
Daniel@0 6348 this.offset.click.left - // Click offset (relative to the element)
Daniel@0 6349 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 6350 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
Daniel@0 6351 ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
Daniel@0 6352 )
Daniel@0 6353 };
Daniel@0 6354
Daniel@0 6355 },
Daniel@0 6356
Daniel@0 6357 _clear: function() {
Daniel@0 6358 this.helper.removeClass("ui-draggable-dragging");
Daniel@0 6359 if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
Daniel@0 6360 this.helper.remove();
Daniel@0 6361 }
Daniel@0 6362 this.helper = null;
Daniel@0 6363 this.cancelHelperRemoval = false;
Daniel@0 6364 if ( this.destroyOnClear ) {
Daniel@0 6365 this.destroy();
Daniel@0 6366 }
Daniel@0 6367 },
Daniel@0 6368
Daniel@0 6369 // From now on bulk stuff - mainly helpers
Daniel@0 6370
Daniel@0 6371 _trigger: function(type, event, ui) {
Daniel@0 6372 ui = ui || this._uiHash();
Daniel@0 6373 $.ui.plugin.call( this, type, [ event, ui, this ], true );
Daniel@0 6374 //The absolute position has to be recalculated after plugins
Daniel@0 6375 if (type === "drag") {
Daniel@0 6376 this.positionAbs = this._convertPositionTo("absolute");
Daniel@0 6377 }
Daniel@0 6378 return $.Widget.prototype._trigger.call(this, type, event, ui);
Daniel@0 6379 },
Daniel@0 6380
Daniel@0 6381 plugins: {},
Daniel@0 6382
Daniel@0 6383 _uiHash: function() {
Daniel@0 6384 return {
Daniel@0 6385 helper: this.helper,
Daniel@0 6386 position: this.position,
Daniel@0 6387 originalPosition: this.originalPosition,
Daniel@0 6388 offset: this.positionAbs
Daniel@0 6389 };
Daniel@0 6390 }
Daniel@0 6391
Daniel@0 6392 });
Daniel@0 6393
Daniel@0 6394 $.ui.plugin.add("draggable", "connectToSortable", {
Daniel@0 6395 start: function( event, ui, inst ) {
Daniel@0 6396
Daniel@0 6397 var o = inst.options,
Daniel@0 6398 uiSortable = $.extend({}, ui, { item: inst.element });
Daniel@0 6399 inst.sortables = [];
Daniel@0 6400 $(o.connectToSortable).each(function() {
Daniel@0 6401 var sortable = $( this ).sortable( "instance" );
Daniel@0 6402 if (sortable && !sortable.options.disabled) {
Daniel@0 6403 inst.sortables.push({
Daniel@0 6404 instance: sortable,
Daniel@0 6405 shouldRevert: sortable.options.revert
Daniel@0 6406 });
Daniel@0 6407 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).
Daniel@0 6408 sortable._trigger("activate", event, uiSortable);
Daniel@0 6409 }
Daniel@0 6410 });
Daniel@0 6411
Daniel@0 6412 },
Daniel@0 6413 stop: function( event, ui, inst ) {
Daniel@0 6414
Daniel@0 6415 //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
Daniel@0 6416 var uiSortable = $.extend( {}, ui, {
Daniel@0 6417 item: inst.element
Daniel@0 6418 });
Daniel@0 6419
Daniel@0 6420 $.each(inst.sortables, function() {
Daniel@0 6421 if (this.instance.isOver) {
Daniel@0 6422
Daniel@0 6423 this.instance.isOver = 0;
Daniel@0 6424
Daniel@0 6425 inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
Daniel@0 6426 this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
Daniel@0 6427
Daniel@0 6428 //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid"
Daniel@0 6429 if (this.shouldRevert) {
Daniel@0 6430 this.instance.options.revert = this.shouldRevert;
Daniel@0 6431 }
Daniel@0 6432
Daniel@0 6433 //Trigger the stop of the sortable
Daniel@0 6434 this.instance._mouseStop(event);
Daniel@0 6435
Daniel@0 6436 this.instance.options.helper = this.instance.options._helper;
Daniel@0 6437
Daniel@0 6438 //If the helper has been the original item, restore properties in the sortable
Daniel@0 6439 if (inst.options.helper === "original") {
Daniel@0 6440 this.instance.currentItem.css({ top: "auto", left: "auto" });
Daniel@0 6441 }
Daniel@0 6442
Daniel@0 6443 } else {
Daniel@0 6444 this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
Daniel@0 6445 this.instance._trigger("deactivate", event, uiSortable);
Daniel@0 6446 }
Daniel@0 6447
Daniel@0 6448 });
Daniel@0 6449
Daniel@0 6450 },
Daniel@0 6451 drag: function( event, ui, inst ) {
Daniel@0 6452
Daniel@0 6453 var that = this;
Daniel@0 6454
Daniel@0 6455 $.each(inst.sortables, function() {
Daniel@0 6456
Daniel@0 6457 var innermostIntersecting = false,
Daniel@0 6458 thisSortable = this;
Daniel@0 6459
Daniel@0 6460 //Copy over some variables to allow calling the sortable's native _intersectsWith
Daniel@0 6461 this.instance.positionAbs = inst.positionAbs;
Daniel@0 6462 this.instance.helperProportions = inst.helperProportions;
Daniel@0 6463 this.instance.offset.click = inst.offset.click;
Daniel@0 6464
Daniel@0 6465 if (this.instance._intersectsWith(this.instance.containerCache)) {
Daniel@0 6466 innermostIntersecting = true;
Daniel@0 6467 $.each(inst.sortables, function() {
Daniel@0 6468 this.instance.positionAbs = inst.positionAbs;
Daniel@0 6469 this.instance.helperProportions = inst.helperProportions;
Daniel@0 6470 this.instance.offset.click = inst.offset.click;
Daniel@0 6471 if (this !== thisSortable &&
Daniel@0 6472 this.instance._intersectsWith(this.instance.containerCache) &&
Daniel@0 6473 $.contains(thisSortable.instance.element[0], this.instance.element[0])
Daniel@0 6474 ) {
Daniel@0 6475 innermostIntersecting = false;
Daniel@0 6476 }
Daniel@0 6477 return innermostIntersecting;
Daniel@0 6478 });
Daniel@0 6479 }
Daniel@0 6480
Daniel@0 6481 if (innermostIntersecting) {
Daniel@0 6482 //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
Daniel@0 6483 if (!this.instance.isOver) {
Daniel@0 6484
Daniel@0 6485 this.instance.isOver = 1;
Daniel@0 6486 //Now we fake the start of dragging for the sortable instance,
Daniel@0 6487 //by cloning the list group item, appending it to the sortable and using it as inst.currentItem
Daniel@0 6488 //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)
Daniel@0 6489 this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true);
Daniel@0 6490 this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it
Daniel@0 6491 this.instance.options.helper = function() { return ui.helper[0]; };
Daniel@0 6492
Daniel@0 6493 event.target = this.instance.currentItem[0];
Daniel@0 6494 this.instance._mouseCapture(event, true);
Daniel@0 6495 this.instance._mouseStart(event, true, true);
Daniel@0 6496
Daniel@0 6497 //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
Daniel@0 6498 this.instance.offset.click.top = inst.offset.click.top;
Daniel@0 6499 this.instance.offset.click.left = inst.offset.click.left;
Daniel@0 6500 this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left;
Daniel@0 6501 this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top;
Daniel@0 6502
Daniel@0 6503 inst._trigger("toSortable", event);
Daniel@0 6504 inst.dropped = this.instance.element; //draggable revert needs that
Daniel@0 6505 //hack so receive/update callbacks work (mostly)
Daniel@0 6506 inst.currentItem = inst.element;
Daniel@0 6507 this.instance.fromOutside = inst;
Daniel@0 6508
Daniel@0 6509 }
Daniel@0 6510
Daniel@0 6511 //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
Daniel@0 6512 if (this.instance.currentItem) {
Daniel@0 6513 this.instance._mouseDrag(event);
Daniel@0 6514 }
Daniel@0 6515
Daniel@0 6516 } else {
Daniel@0 6517
Daniel@0 6518 //If it doesn't intersect with the sortable, and it intersected before,
Daniel@0 6519 //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
Daniel@0 6520 if (this.instance.isOver) {
Daniel@0 6521
Daniel@0 6522 this.instance.isOver = 0;
Daniel@0 6523 this.instance.cancelHelperRemoval = true;
Daniel@0 6524
Daniel@0 6525 //Prevent reverting on this forced stop
Daniel@0 6526 this.instance.options.revert = false;
Daniel@0 6527
Daniel@0 6528 // The out event needs to be triggered independently
Daniel@0 6529 this.instance._trigger("out", event, this.instance._uiHash(this.instance));
Daniel@0 6530
Daniel@0 6531 this.instance._mouseStop(event, true);
Daniel@0 6532 this.instance.options.helper = this.instance.options._helper;
Daniel@0 6533
Daniel@0 6534 //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
Daniel@0 6535 this.instance.currentItem.remove();
Daniel@0 6536 if (this.instance.placeholder) {
Daniel@0 6537 this.instance.placeholder.remove();
Daniel@0 6538 }
Daniel@0 6539
Daniel@0 6540 inst._trigger("fromSortable", event);
Daniel@0 6541 inst.dropped = false; //draggable revert needs that
Daniel@0 6542 }
Daniel@0 6543
Daniel@0 6544 }
Daniel@0 6545
Daniel@0 6546 });
Daniel@0 6547
Daniel@0 6548 }
Daniel@0 6549 });
Daniel@0 6550
Daniel@0 6551 $.ui.plugin.add("draggable", "cursor", {
Daniel@0 6552 start: function( event, ui, instance ) {
Daniel@0 6553 var t = $( "body" ),
Daniel@0 6554 o = instance.options;
Daniel@0 6555
Daniel@0 6556 if (t.css("cursor")) {
Daniel@0 6557 o._cursor = t.css("cursor");
Daniel@0 6558 }
Daniel@0 6559 t.css("cursor", o.cursor);
Daniel@0 6560 },
Daniel@0 6561 stop: function( event, ui, instance ) {
Daniel@0 6562 var o = instance.options;
Daniel@0 6563 if (o._cursor) {
Daniel@0 6564 $("body").css("cursor", o._cursor);
Daniel@0 6565 }
Daniel@0 6566 }
Daniel@0 6567 });
Daniel@0 6568
Daniel@0 6569 $.ui.plugin.add("draggable", "opacity", {
Daniel@0 6570 start: function( event, ui, instance ) {
Daniel@0 6571 var t = $( ui.helper ),
Daniel@0 6572 o = instance.options;
Daniel@0 6573 if (t.css("opacity")) {
Daniel@0 6574 o._opacity = t.css("opacity");
Daniel@0 6575 }
Daniel@0 6576 t.css("opacity", o.opacity);
Daniel@0 6577 },
Daniel@0 6578 stop: function( event, ui, instance ) {
Daniel@0 6579 var o = instance.options;
Daniel@0 6580 if (o._opacity) {
Daniel@0 6581 $(ui.helper).css("opacity", o._opacity);
Daniel@0 6582 }
Daniel@0 6583 }
Daniel@0 6584 });
Daniel@0 6585
Daniel@0 6586 $.ui.plugin.add("draggable", "scroll", {
Daniel@0 6587 start: function( event, ui, i ) {
Daniel@0 6588 if ( i.scrollParent[ 0 ] !== i.document[ 0 ] && i.scrollParent[ 0 ].tagName !== "HTML" ) {
Daniel@0 6589 i.overflowOffset = i.scrollParent.offset();
Daniel@0 6590 }
Daniel@0 6591 },
Daniel@0 6592 drag: function( event, ui, i ) {
Daniel@0 6593
Daniel@0 6594 var o = i.options,
Daniel@0 6595 scrolled = false,
Daniel@0 6596 document = i.document[ 0 ];
Daniel@0 6597
Daniel@0 6598 if ( i.scrollParent[ 0 ] !== document && i.scrollParent[ 0 ].tagName !== "HTML" ) {
Daniel@0 6599 if (!o.axis || o.axis !== "x") {
Daniel@0 6600 if ((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
Daniel@0 6601 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed;
Daniel@0 6602 } else if (event.pageY - i.overflowOffset.top < o.scrollSensitivity) {
Daniel@0 6603 i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed;
Daniel@0 6604 }
Daniel@0 6605 }
Daniel@0 6606
Daniel@0 6607 if (!o.axis || o.axis !== "y") {
Daniel@0 6608 if ((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
Daniel@0 6609 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed;
Daniel@0 6610 } else if (event.pageX - i.overflowOffset.left < o.scrollSensitivity) {
Daniel@0 6611 i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed;
Daniel@0 6612 }
Daniel@0 6613 }
Daniel@0 6614
Daniel@0 6615 } else {
Daniel@0 6616
Daniel@0 6617 if (!o.axis || o.axis !== "x") {
Daniel@0 6618 if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
Daniel@0 6619 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
Daniel@0 6620 } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
Daniel@0 6621 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
Daniel@0 6622 }
Daniel@0 6623 }
Daniel@0 6624
Daniel@0 6625 if (!o.axis || o.axis !== "y") {
Daniel@0 6626 if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
Daniel@0 6627 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
Daniel@0 6628 } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
Daniel@0 6629 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
Daniel@0 6630 }
Daniel@0 6631 }
Daniel@0 6632
Daniel@0 6633 }
Daniel@0 6634
Daniel@0 6635 if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
Daniel@0 6636 $.ui.ddmanager.prepareOffsets(i, event);
Daniel@0 6637 }
Daniel@0 6638
Daniel@0 6639 }
Daniel@0 6640 });
Daniel@0 6641
Daniel@0 6642 $.ui.plugin.add("draggable", "snap", {
Daniel@0 6643 start: function( event, ui, i ) {
Daniel@0 6644
Daniel@0 6645 var o = i.options;
Daniel@0 6646
Daniel@0 6647 i.snapElements = [];
Daniel@0 6648
Daniel@0 6649 $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
Daniel@0 6650 var $t = $(this),
Daniel@0 6651 $o = $t.offset();
Daniel@0 6652 if (this !== i.element[0]) {
Daniel@0 6653 i.snapElements.push({
Daniel@0 6654 item: this,
Daniel@0 6655 width: $t.outerWidth(), height: $t.outerHeight(),
Daniel@0 6656 top: $o.top, left: $o.left
Daniel@0 6657 });
Daniel@0 6658 }
Daniel@0 6659 });
Daniel@0 6660
Daniel@0 6661 },
Daniel@0 6662 drag: function( event, ui, inst ) {
Daniel@0 6663
Daniel@0 6664 var ts, bs, ls, rs, l, r, t, b, i, first,
Daniel@0 6665 o = inst.options,
Daniel@0 6666 d = o.snapTolerance,
Daniel@0 6667 x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
Daniel@0 6668 y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
Daniel@0 6669
Daniel@0 6670 for (i = inst.snapElements.length - 1; i >= 0; i--){
Daniel@0 6671
Daniel@0 6672 l = inst.snapElements[i].left;
Daniel@0 6673 r = l + inst.snapElements[i].width;
Daniel@0 6674 t = inst.snapElements[i].top;
Daniel@0 6675 b = t + inst.snapElements[i].height;
Daniel@0 6676
Daniel@0 6677 if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
Daniel@0 6678 if (inst.snapElements[i].snapping) {
Daniel@0 6679 (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
Daniel@0 6680 }
Daniel@0 6681 inst.snapElements[i].snapping = false;
Daniel@0 6682 continue;
Daniel@0 6683 }
Daniel@0 6684
Daniel@0 6685 if (o.snapMode !== "inner") {
Daniel@0 6686 ts = Math.abs(t - y2) <= d;
Daniel@0 6687 bs = Math.abs(b - y1) <= d;
Daniel@0 6688 ls = Math.abs(l - x2) <= d;
Daniel@0 6689 rs = Math.abs(r - x1) <= d;
Daniel@0 6690 if (ts) {
Daniel@0 6691 ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
Daniel@0 6692 }
Daniel@0 6693 if (bs) {
Daniel@0 6694 ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top;
Daniel@0 6695 }
Daniel@0 6696 if (ls) {
Daniel@0 6697 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left;
Daniel@0 6698 }
Daniel@0 6699 if (rs) {
Daniel@0 6700 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left;
Daniel@0 6701 }
Daniel@0 6702 }
Daniel@0 6703
Daniel@0 6704 first = (ts || bs || ls || rs);
Daniel@0 6705
Daniel@0 6706 if (o.snapMode !== "outer") {
Daniel@0 6707 ts = Math.abs(t - y1) <= d;
Daniel@0 6708 bs = Math.abs(b - y2) <= d;
Daniel@0 6709 ls = Math.abs(l - x1) <= d;
Daniel@0 6710 rs = Math.abs(r - x2) <= d;
Daniel@0 6711 if (ts) {
Daniel@0 6712 ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top;
Daniel@0 6713 }
Daniel@0 6714 if (bs) {
Daniel@0 6715 ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top;
Daniel@0 6716 }
Daniel@0 6717 if (ls) {
Daniel@0 6718 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left;
Daniel@0 6719 }
Daniel@0 6720 if (rs) {
Daniel@0 6721 ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left;
Daniel@0 6722 }
Daniel@0 6723 }
Daniel@0 6724
Daniel@0 6725 if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
Daniel@0 6726 (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
Daniel@0 6727 }
Daniel@0 6728 inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
Daniel@0 6729
Daniel@0 6730 }
Daniel@0 6731
Daniel@0 6732 }
Daniel@0 6733 });
Daniel@0 6734
Daniel@0 6735 $.ui.plugin.add("draggable", "stack", {
Daniel@0 6736 start: function( event, ui, instance ) {
Daniel@0 6737 var min,
Daniel@0 6738 o = instance.options,
Daniel@0 6739 group = $.makeArray($(o.stack)).sort(function(a,b) {
Daniel@0 6740 return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0);
Daniel@0 6741 });
Daniel@0 6742
Daniel@0 6743 if (!group.length) { return; }
Daniel@0 6744
Daniel@0 6745 min = parseInt($(group[0]).css("zIndex"), 10) || 0;
Daniel@0 6746 $(group).each(function(i) {
Daniel@0 6747 $(this).css("zIndex", min + i);
Daniel@0 6748 });
Daniel@0 6749 this.css("zIndex", (min + group.length));
Daniel@0 6750 }
Daniel@0 6751 });
Daniel@0 6752
Daniel@0 6753 $.ui.plugin.add("draggable", "zIndex", {
Daniel@0 6754 start: function( event, ui, instance ) {
Daniel@0 6755 var t = $( ui.helper ),
Daniel@0 6756 o = instance.options;
Daniel@0 6757
Daniel@0 6758 if (t.css("zIndex")) {
Daniel@0 6759 o._zIndex = t.css("zIndex");
Daniel@0 6760 }
Daniel@0 6761 t.css("zIndex", o.zIndex);
Daniel@0 6762 },
Daniel@0 6763 stop: function( event, ui, instance ) {
Daniel@0 6764 var o = instance.options;
Daniel@0 6765
Daniel@0 6766 if (o._zIndex) {
Daniel@0 6767 $(ui.helper).css("zIndex", o._zIndex);
Daniel@0 6768 }
Daniel@0 6769 }
Daniel@0 6770 });
Daniel@0 6771
Daniel@0 6772 var draggable = $.ui.draggable;
Daniel@0 6773
Daniel@0 6774
Daniel@0 6775 /*!
Daniel@0 6776 * jQuery UI Resizable 1.11.0
Daniel@0 6777 * http://jqueryui.com
Daniel@0 6778 *
Daniel@0 6779 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 6780 * Released under the MIT license.
Daniel@0 6781 * http://jquery.org/license
Daniel@0 6782 *
Daniel@0 6783 * http://api.jqueryui.com/resizable/
Daniel@0 6784 */
Daniel@0 6785
Daniel@0 6786
Daniel@0 6787 $.widget("ui.resizable", $.ui.mouse, {
Daniel@0 6788 version: "1.11.0",
Daniel@0 6789 widgetEventPrefix: "resize",
Daniel@0 6790 options: {
Daniel@0 6791 alsoResize: false,
Daniel@0 6792 animate: false,
Daniel@0 6793 animateDuration: "slow",
Daniel@0 6794 animateEasing: "swing",
Daniel@0 6795 aspectRatio: false,
Daniel@0 6796 autoHide: false,
Daniel@0 6797 containment: false,
Daniel@0 6798 ghost: false,
Daniel@0 6799 grid: false,
Daniel@0 6800 handles: "e,s,se",
Daniel@0 6801 helper: false,
Daniel@0 6802 maxHeight: null,
Daniel@0 6803 maxWidth: null,
Daniel@0 6804 minHeight: 10,
Daniel@0 6805 minWidth: 10,
Daniel@0 6806 // See #7960
Daniel@0 6807 zIndex: 90,
Daniel@0 6808
Daniel@0 6809 // callbacks
Daniel@0 6810 resize: null,
Daniel@0 6811 start: null,
Daniel@0 6812 stop: null
Daniel@0 6813 },
Daniel@0 6814
Daniel@0 6815 _num: function( value ) {
Daniel@0 6816 return parseInt( value, 10 ) || 0;
Daniel@0 6817 },
Daniel@0 6818
Daniel@0 6819 _isNumber: function( value ) {
Daniel@0 6820 return !isNaN( parseInt( value , 10 ) );
Daniel@0 6821 },
Daniel@0 6822
Daniel@0 6823 _hasScroll: function( el, a ) {
Daniel@0 6824
Daniel@0 6825 if ( $( el ).css( "overflow" ) === "hidden") {
Daniel@0 6826 return false;
Daniel@0 6827 }
Daniel@0 6828
Daniel@0 6829 var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
Daniel@0 6830 has = false;
Daniel@0 6831
Daniel@0 6832 if ( el[ scroll ] > 0 ) {
Daniel@0 6833 return true;
Daniel@0 6834 }
Daniel@0 6835
Daniel@0 6836 // TODO: determine which cases actually cause this to happen
Daniel@0 6837 // if the element doesn't have the scroll set, see if it's possible to
Daniel@0 6838 // set the scroll
Daniel@0 6839 el[ scroll ] = 1;
Daniel@0 6840 has = ( el[ scroll ] > 0 );
Daniel@0 6841 el[ scroll ] = 0;
Daniel@0 6842 return has;
Daniel@0 6843 },
Daniel@0 6844
Daniel@0 6845 _create: function() {
Daniel@0 6846
Daniel@0 6847 var n, i, handle, axis, hname,
Daniel@0 6848 that = this,
Daniel@0 6849 o = this.options;
Daniel@0 6850 this.element.addClass("ui-resizable");
Daniel@0 6851
Daniel@0 6852 $.extend(this, {
Daniel@0 6853 _aspectRatio: !!(o.aspectRatio),
Daniel@0 6854 aspectRatio: o.aspectRatio,
Daniel@0 6855 originalElement: this.element,
Daniel@0 6856 _proportionallyResizeElements: [],
Daniel@0 6857 _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
Daniel@0 6858 });
Daniel@0 6859
Daniel@0 6860 // Wrap the element if it cannot hold child nodes
Daniel@0 6861 if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
Daniel@0 6862
Daniel@0 6863 this.element.wrap(
Daniel@0 6864 $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
Daniel@0 6865 position: this.element.css("position"),
Daniel@0 6866 width: this.element.outerWidth(),
Daniel@0 6867 height: this.element.outerHeight(),
Daniel@0 6868 top: this.element.css("top"),
Daniel@0 6869 left: this.element.css("left")
Daniel@0 6870 })
Daniel@0 6871 );
Daniel@0 6872
Daniel@0 6873 this.element = this.element.parent().data(
Daniel@0 6874 "ui-resizable", this.element.resizable( "instance" )
Daniel@0 6875 );
Daniel@0 6876
Daniel@0 6877 this.elementIsWrapper = true;
Daniel@0 6878
Daniel@0 6879 this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") });
Daniel@0 6880 this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0});
Daniel@0 6881 // support: Safari
Daniel@0 6882 // Prevent Safari textarea resize
Daniel@0 6883 this.originalResizeStyle = this.originalElement.css("resize");
Daniel@0 6884 this.originalElement.css("resize", "none");
Daniel@0 6885
Daniel@0 6886 this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" }));
Daniel@0 6887
Daniel@0 6888 // support: IE9
Daniel@0 6889 // avoid IE jump (hard set the margin)
Daniel@0 6890 this.originalElement.css({ margin: this.originalElement.css("margin") });
Daniel@0 6891
Daniel@0 6892 this._proportionallyResize();
Daniel@0 6893 }
Daniel@0 6894
Daniel@0 6895 this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" });
Daniel@0 6896 if(this.handles.constructor === String) {
Daniel@0 6897
Daniel@0 6898 if ( this.handles === "all") {
Daniel@0 6899 this.handles = "n,e,s,w,se,sw,ne,nw";
Daniel@0 6900 }
Daniel@0 6901
Daniel@0 6902 n = this.handles.split(",");
Daniel@0 6903 this.handles = {};
Daniel@0 6904
Daniel@0 6905 for(i = 0; i < n.length; i++) {
Daniel@0 6906
Daniel@0 6907 handle = $.trim(n[i]);
Daniel@0 6908 hname = "ui-resizable-"+handle;
Daniel@0 6909 axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
Daniel@0 6910
Daniel@0 6911 axis.css({ zIndex: o.zIndex });
Daniel@0 6912
Daniel@0 6913 // TODO : What's going on here?
Daniel@0 6914 if ("se" === handle) {
Daniel@0 6915 axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
Daniel@0 6916 }
Daniel@0 6917
Daniel@0 6918 this.handles[handle] = ".ui-resizable-"+handle;
Daniel@0 6919 this.element.append(axis);
Daniel@0 6920 }
Daniel@0 6921
Daniel@0 6922 }
Daniel@0 6923
Daniel@0 6924 this._renderAxis = function(target) {
Daniel@0 6925
Daniel@0 6926 var i, axis, padPos, padWrapper;
Daniel@0 6927
Daniel@0 6928 target = target || this.element;
Daniel@0 6929
Daniel@0 6930 for(i in this.handles) {
Daniel@0 6931
Daniel@0 6932 if(this.handles[i].constructor === String) {
Daniel@0 6933 this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
Daniel@0 6934 }
Daniel@0 6935
Daniel@0 6936 if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
Daniel@0 6937
Daniel@0 6938 axis = $(this.handles[i], this.element);
Daniel@0 6939
Daniel@0 6940 padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
Daniel@0 6941
Daniel@0 6942 padPos = [ "padding",
Daniel@0 6943 /ne|nw|n/.test(i) ? "Top" :
Daniel@0 6944 /se|sw|s/.test(i) ? "Bottom" :
Daniel@0 6945 /^e$/.test(i) ? "Right" : "Left" ].join("");
Daniel@0 6946
Daniel@0 6947 target.css(padPos, padWrapper);
Daniel@0 6948
Daniel@0 6949 this._proportionallyResize();
Daniel@0 6950
Daniel@0 6951 }
Daniel@0 6952
Daniel@0 6953 // TODO: What's that good for? There's not anything to be executed left
Daniel@0 6954 if(!$(this.handles[i]).length) {
Daniel@0 6955 continue;
Daniel@0 6956 }
Daniel@0 6957 }
Daniel@0 6958 };
Daniel@0 6959
Daniel@0 6960 // TODO: make renderAxis a prototype function
Daniel@0 6961 this._renderAxis(this.element);
Daniel@0 6962
Daniel@0 6963 this._handles = $(".ui-resizable-handle", this.element)
Daniel@0 6964 .disableSelection();
Daniel@0 6965
Daniel@0 6966 this._handles.mouseover(function() {
Daniel@0 6967 if (!that.resizing) {
Daniel@0 6968 if (this.className) {
Daniel@0 6969 axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
Daniel@0 6970 }
Daniel@0 6971 that.axis = axis && axis[1] ? axis[1] : "se";
Daniel@0 6972 }
Daniel@0 6973 });
Daniel@0 6974
Daniel@0 6975 if (o.autoHide) {
Daniel@0 6976 this._handles.hide();
Daniel@0 6977 $(this.element)
Daniel@0 6978 .addClass("ui-resizable-autohide")
Daniel@0 6979 .mouseenter(function() {
Daniel@0 6980 if (o.disabled) {
Daniel@0 6981 return;
Daniel@0 6982 }
Daniel@0 6983 $(this).removeClass("ui-resizable-autohide");
Daniel@0 6984 that._handles.show();
Daniel@0 6985 })
Daniel@0 6986 .mouseleave(function(){
Daniel@0 6987 if (o.disabled) {
Daniel@0 6988 return;
Daniel@0 6989 }
Daniel@0 6990 if (!that.resizing) {
Daniel@0 6991 $(this).addClass("ui-resizable-autohide");
Daniel@0 6992 that._handles.hide();
Daniel@0 6993 }
Daniel@0 6994 });
Daniel@0 6995 }
Daniel@0 6996
Daniel@0 6997 this._mouseInit();
Daniel@0 6998
Daniel@0 6999 },
Daniel@0 7000
Daniel@0 7001 _destroy: function() {
Daniel@0 7002
Daniel@0 7003 this._mouseDestroy();
Daniel@0 7004
Daniel@0 7005 var wrapper,
Daniel@0 7006 _destroy = function(exp) {
Daniel@0 7007 $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
Daniel@0 7008 .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove();
Daniel@0 7009 };
Daniel@0 7010
Daniel@0 7011 // TODO: Unwrap at same DOM position
Daniel@0 7012 if (this.elementIsWrapper) {
Daniel@0 7013 _destroy(this.element);
Daniel@0 7014 wrapper = this.element;
Daniel@0 7015 this.originalElement.css({
Daniel@0 7016 position: wrapper.css("position"),
Daniel@0 7017 width: wrapper.outerWidth(),
Daniel@0 7018 height: wrapper.outerHeight(),
Daniel@0 7019 top: wrapper.css("top"),
Daniel@0 7020 left: wrapper.css("left")
Daniel@0 7021 }).insertAfter( wrapper );
Daniel@0 7022 wrapper.remove();
Daniel@0 7023 }
Daniel@0 7024
Daniel@0 7025 this.originalElement.css("resize", this.originalResizeStyle);
Daniel@0 7026 _destroy(this.originalElement);
Daniel@0 7027
Daniel@0 7028 return this;
Daniel@0 7029 },
Daniel@0 7030
Daniel@0 7031 _mouseCapture: function(event) {
Daniel@0 7032 var i, handle,
Daniel@0 7033 capture = false;
Daniel@0 7034
Daniel@0 7035 for (i in this.handles) {
Daniel@0 7036 handle = $(this.handles[i])[0];
Daniel@0 7037 if (handle === event.target || $.contains(handle, event.target)) {
Daniel@0 7038 capture = true;
Daniel@0 7039 }
Daniel@0 7040 }
Daniel@0 7041
Daniel@0 7042 return !this.options.disabled && capture;
Daniel@0 7043 },
Daniel@0 7044
Daniel@0 7045 _mouseStart: function(event) {
Daniel@0 7046
Daniel@0 7047 var curleft, curtop, cursor,
Daniel@0 7048 o = this.options,
Daniel@0 7049 el = this.element;
Daniel@0 7050
Daniel@0 7051 this.resizing = true;
Daniel@0 7052
Daniel@0 7053 this._renderProxy();
Daniel@0 7054
Daniel@0 7055 curleft = this._num(this.helper.css("left"));
Daniel@0 7056 curtop = this._num(this.helper.css("top"));
Daniel@0 7057
Daniel@0 7058 if (o.containment) {
Daniel@0 7059 curleft += $(o.containment).scrollLeft() || 0;
Daniel@0 7060 curtop += $(o.containment).scrollTop() || 0;
Daniel@0 7061 }
Daniel@0 7062
Daniel@0 7063 this.offset = this.helper.offset();
Daniel@0 7064 this.position = { left: curleft, top: curtop };
Daniel@0 7065 this.size = this._helper ? { width: this.helper.width(), height: this.helper.height() } : { width: el.width(), height: el.height() };
Daniel@0 7066 this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() };
Daniel@0 7067 this.originalPosition = { left: curleft, top: curtop };
Daniel@0 7068 this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() };
Daniel@0 7069 this.originalMousePosition = { left: event.pageX, top: event.pageY };
Daniel@0 7070
Daniel@0 7071 this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1);
Daniel@0 7072
Daniel@0 7073 cursor = $(".ui-resizable-" + this.axis).css("cursor");
Daniel@0 7074 $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
Daniel@0 7075
Daniel@0 7076 el.addClass("ui-resizable-resizing");
Daniel@0 7077 this._propagate("start", event);
Daniel@0 7078 return true;
Daniel@0 7079 },
Daniel@0 7080
Daniel@0 7081 _mouseDrag: function(event) {
Daniel@0 7082
Daniel@0 7083 var data,
Daniel@0 7084 el = this.helper, props = {},
Daniel@0 7085 smp = this.originalMousePosition,
Daniel@0 7086 a = this.axis,
Daniel@0 7087 dx = (event.pageX-smp.left)||0,
Daniel@0 7088 dy = (event.pageY-smp.top)||0,
Daniel@0 7089 trigger = this._change[a];
Daniel@0 7090
Daniel@0 7091 this.prevPosition = {
Daniel@0 7092 top: this.position.top,
Daniel@0 7093 left: this.position.left
Daniel@0 7094 };
Daniel@0 7095 this.prevSize = {
Daniel@0 7096 width: this.size.width,
Daniel@0 7097 height: this.size.height
Daniel@0 7098 };
Daniel@0 7099
Daniel@0 7100 if (!trigger) {
Daniel@0 7101 return false;
Daniel@0 7102 }
Daniel@0 7103
Daniel@0 7104 data = trigger.apply(this, [event, dx, dy]);
Daniel@0 7105
Daniel@0 7106 this._updateVirtualBoundaries(event.shiftKey);
Daniel@0 7107 if (this._aspectRatio || event.shiftKey) {
Daniel@0 7108 data = this._updateRatio(data, event);
Daniel@0 7109 }
Daniel@0 7110
Daniel@0 7111 data = this._respectSize(data, event);
Daniel@0 7112
Daniel@0 7113 this._updateCache(data);
Daniel@0 7114
Daniel@0 7115 this._propagate("resize", event);
Daniel@0 7116
Daniel@0 7117 if ( this.position.top !== this.prevPosition.top ) {
Daniel@0 7118 props.top = this.position.top + "px";
Daniel@0 7119 }
Daniel@0 7120 if ( this.position.left !== this.prevPosition.left ) {
Daniel@0 7121 props.left = this.position.left + "px";
Daniel@0 7122 }
Daniel@0 7123 if ( this.size.width !== this.prevSize.width ) {
Daniel@0 7124 props.width = this.size.width + "px";
Daniel@0 7125 }
Daniel@0 7126 if ( this.size.height !== this.prevSize.height ) {
Daniel@0 7127 props.height = this.size.height + "px";
Daniel@0 7128 }
Daniel@0 7129 el.css( props );
Daniel@0 7130
Daniel@0 7131 if ( !this._helper && this._proportionallyResizeElements.length ) {
Daniel@0 7132 this._proportionallyResize();
Daniel@0 7133 }
Daniel@0 7134
Daniel@0 7135 if ( !$.isEmptyObject( props ) ) {
Daniel@0 7136 this._trigger( "resize", event, this.ui() );
Daniel@0 7137 }
Daniel@0 7138
Daniel@0 7139 return false;
Daniel@0 7140 },
Daniel@0 7141
Daniel@0 7142 _mouseStop: function(event) {
Daniel@0 7143
Daniel@0 7144 this.resizing = false;
Daniel@0 7145 var pr, ista, soffseth, soffsetw, s, left, top,
Daniel@0 7146 o = this.options, that = this;
Daniel@0 7147
Daniel@0 7148 if(this._helper) {
Daniel@0 7149
Daniel@0 7150 pr = this._proportionallyResizeElements;
Daniel@0 7151 ista = pr.length && (/textarea/i).test(pr[0].nodeName);
Daniel@0 7152 soffseth = ista && this._hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height;
Daniel@0 7153 soffsetw = ista ? 0 : that.sizeDiff.width;
Daniel@0 7154
Daniel@0 7155 s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) };
Daniel@0 7156 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null;
Daniel@0 7157 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
Daniel@0 7158
Daniel@0 7159 if (!o.animate) {
Daniel@0 7160 this.element.css($.extend(s, { top: top, left: left }));
Daniel@0 7161 }
Daniel@0 7162
Daniel@0 7163 that.helper.height(that.size.height);
Daniel@0 7164 that.helper.width(that.size.width);
Daniel@0 7165
Daniel@0 7166 if (this._helper && !o.animate) {
Daniel@0 7167 this._proportionallyResize();
Daniel@0 7168 }
Daniel@0 7169 }
Daniel@0 7170
Daniel@0 7171 $("body").css("cursor", "auto");
Daniel@0 7172
Daniel@0 7173 this.element.removeClass("ui-resizable-resizing");
Daniel@0 7174
Daniel@0 7175 this._propagate("stop", event);
Daniel@0 7176
Daniel@0 7177 if (this._helper) {
Daniel@0 7178 this.helper.remove();
Daniel@0 7179 }
Daniel@0 7180
Daniel@0 7181 return false;
Daniel@0 7182
Daniel@0 7183 },
Daniel@0 7184
Daniel@0 7185 _updateVirtualBoundaries: function(forceAspectRatio) {
Daniel@0 7186 var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
Daniel@0 7187 o = this.options;
Daniel@0 7188
Daniel@0 7189 b = {
Daniel@0 7190 minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
Daniel@0 7191 maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
Daniel@0 7192 minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
Daniel@0 7193 maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
Daniel@0 7194 };
Daniel@0 7195
Daniel@0 7196 if(this._aspectRatio || forceAspectRatio) {
Daniel@0 7197 pMinWidth = b.minHeight * this.aspectRatio;
Daniel@0 7198 pMinHeight = b.minWidth / this.aspectRatio;
Daniel@0 7199 pMaxWidth = b.maxHeight * this.aspectRatio;
Daniel@0 7200 pMaxHeight = b.maxWidth / this.aspectRatio;
Daniel@0 7201
Daniel@0 7202 if(pMinWidth > b.minWidth) {
Daniel@0 7203 b.minWidth = pMinWidth;
Daniel@0 7204 }
Daniel@0 7205 if(pMinHeight > b.minHeight) {
Daniel@0 7206 b.minHeight = pMinHeight;
Daniel@0 7207 }
Daniel@0 7208 if(pMaxWidth < b.maxWidth) {
Daniel@0 7209 b.maxWidth = pMaxWidth;
Daniel@0 7210 }
Daniel@0 7211 if(pMaxHeight < b.maxHeight) {
Daniel@0 7212 b.maxHeight = pMaxHeight;
Daniel@0 7213 }
Daniel@0 7214 }
Daniel@0 7215 this._vBoundaries = b;
Daniel@0 7216 },
Daniel@0 7217
Daniel@0 7218 _updateCache: function(data) {
Daniel@0 7219 this.offset = this.helper.offset();
Daniel@0 7220 if (this._isNumber(data.left)) {
Daniel@0 7221 this.position.left = data.left;
Daniel@0 7222 }
Daniel@0 7223 if (this._isNumber(data.top)) {
Daniel@0 7224 this.position.top = data.top;
Daniel@0 7225 }
Daniel@0 7226 if (this._isNumber(data.height)) {
Daniel@0 7227 this.size.height = data.height;
Daniel@0 7228 }
Daniel@0 7229 if (this._isNumber(data.width)) {
Daniel@0 7230 this.size.width = data.width;
Daniel@0 7231 }
Daniel@0 7232 },
Daniel@0 7233
Daniel@0 7234 _updateRatio: function( data ) {
Daniel@0 7235
Daniel@0 7236 var cpos = this.position,
Daniel@0 7237 csize = this.size,
Daniel@0 7238 a = this.axis;
Daniel@0 7239
Daniel@0 7240 if (this._isNumber(data.height)) {
Daniel@0 7241 data.width = (data.height * this.aspectRatio);
Daniel@0 7242 } else if (this._isNumber(data.width)) {
Daniel@0 7243 data.height = (data.width / this.aspectRatio);
Daniel@0 7244 }
Daniel@0 7245
Daniel@0 7246 if (a === "sw") {
Daniel@0 7247 data.left = cpos.left + (csize.width - data.width);
Daniel@0 7248 data.top = null;
Daniel@0 7249 }
Daniel@0 7250 if (a === "nw") {
Daniel@0 7251 data.top = cpos.top + (csize.height - data.height);
Daniel@0 7252 data.left = cpos.left + (csize.width - data.width);
Daniel@0 7253 }
Daniel@0 7254
Daniel@0 7255 return data;
Daniel@0 7256 },
Daniel@0 7257
Daniel@0 7258 _respectSize: function( data ) {
Daniel@0 7259
Daniel@0 7260 var o = this._vBoundaries,
Daniel@0 7261 a = this.axis,
Daniel@0 7262 ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
Daniel@0 7263 isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
Daniel@0 7264 dw = this.originalPosition.left + this.originalSize.width,
Daniel@0 7265 dh = this.position.top + this.size.height,
Daniel@0 7266 cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
Daniel@0 7267 if (isminw) {
Daniel@0 7268 data.width = o.minWidth;
Daniel@0 7269 }
Daniel@0 7270 if (isminh) {
Daniel@0 7271 data.height = o.minHeight;
Daniel@0 7272 }
Daniel@0 7273 if (ismaxw) {
Daniel@0 7274 data.width = o.maxWidth;
Daniel@0 7275 }
Daniel@0 7276 if (ismaxh) {
Daniel@0 7277 data.height = o.maxHeight;
Daniel@0 7278 }
Daniel@0 7279
Daniel@0 7280 if (isminw && cw) {
Daniel@0 7281 data.left = dw - o.minWidth;
Daniel@0 7282 }
Daniel@0 7283 if (ismaxw && cw) {
Daniel@0 7284 data.left = dw - o.maxWidth;
Daniel@0 7285 }
Daniel@0 7286 if (isminh && ch) {
Daniel@0 7287 data.top = dh - o.minHeight;
Daniel@0 7288 }
Daniel@0 7289 if (ismaxh && ch) {
Daniel@0 7290 data.top = dh - o.maxHeight;
Daniel@0 7291 }
Daniel@0 7292
Daniel@0 7293 // Fixing jump error on top/left - bug #2330
Daniel@0 7294 if (!data.width && !data.height && !data.left && data.top) {
Daniel@0 7295 data.top = null;
Daniel@0 7296 } else if (!data.width && !data.height && !data.top && data.left) {
Daniel@0 7297 data.left = null;
Daniel@0 7298 }
Daniel@0 7299
Daniel@0 7300 return data;
Daniel@0 7301 },
Daniel@0 7302
Daniel@0 7303 _proportionallyResize: function() {
Daniel@0 7304
Daniel@0 7305 if (!this._proportionallyResizeElements.length) {
Daniel@0 7306 return;
Daniel@0 7307 }
Daniel@0 7308
Daniel@0 7309 var i, j, borders, paddings, prel,
Daniel@0 7310 element = this.helper || this.element;
Daniel@0 7311
Daniel@0 7312 for ( i=0; i < this._proportionallyResizeElements.length; i++) {
Daniel@0 7313
Daniel@0 7314 prel = this._proportionallyResizeElements[i];
Daniel@0 7315
Daniel@0 7316 if (!this.borderDif) {
Daniel@0 7317 this.borderDif = [];
Daniel@0 7318 borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")];
Daniel@0 7319 paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")];
Daniel@0 7320
Daniel@0 7321 for ( j = 0; j < borders.length; j++ ) {
Daniel@0 7322 this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 );
Daniel@0 7323 }
Daniel@0 7324 }
Daniel@0 7325
Daniel@0 7326 prel.css({
Daniel@0 7327 height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0,
Daniel@0 7328 width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0
Daniel@0 7329 });
Daniel@0 7330
Daniel@0 7331 }
Daniel@0 7332
Daniel@0 7333 },
Daniel@0 7334
Daniel@0 7335 _renderProxy: function() {
Daniel@0 7336
Daniel@0 7337 var el = this.element, o = this.options;
Daniel@0 7338 this.elementOffset = el.offset();
Daniel@0 7339
Daniel@0 7340 if(this._helper) {
Daniel@0 7341
Daniel@0 7342 this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
Daniel@0 7343
Daniel@0 7344 this.helper.addClass(this._helper).css({
Daniel@0 7345 width: this.element.outerWidth() - 1,
Daniel@0 7346 height: this.element.outerHeight() - 1,
Daniel@0 7347 position: "absolute",
Daniel@0 7348 left: this.elementOffset.left +"px",
Daniel@0 7349 top: this.elementOffset.top +"px",
Daniel@0 7350 zIndex: ++o.zIndex //TODO: Don't modify option
Daniel@0 7351 });
Daniel@0 7352
Daniel@0 7353 this.helper
Daniel@0 7354 .appendTo("body")
Daniel@0 7355 .disableSelection();
Daniel@0 7356
Daniel@0 7357 } else {
Daniel@0 7358 this.helper = this.element;
Daniel@0 7359 }
Daniel@0 7360
Daniel@0 7361 },
Daniel@0 7362
Daniel@0 7363 _change: {
Daniel@0 7364 e: function(event, dx) {
Daniel@0 7365 return { width: this.originalSize.width + dx };
Daniel@0 7366 },
Daniel@0 7367 w: function(event, dx) {
Daniel@0 7368 var cs = this.originalSize, sp = this.originalPosition;
Daniel@0 7369 return { left: sp.left + dx, width: cs.width - dx };
Daniel@0 7370 },
Daniel@0 7371 n: function(event, dx, dy) {
Daniel@0 7372 var cs = this.originalSize, sp = this.originalPosition;
Daniel@0 7373 return { top: sp.top + dy, height: cs.height - dy };
Daniel@0 7374 },
Daniel@0 7375 s: function(event, dx, dy) {
Daniel@0 7376 return { height: this.originalSize.height + dy };
Daniel@0 7377 },
Daniel@0 7378 se: function(event, dx, dy) {
Daniel@0 7379 return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
Daniel@0 7380 },
Daniel@0 7381 sw: function(event, dx, dy) {
Daniel@0 7382 return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
Daniel@0 7383 },
Daniel@0 7384 ne: function(event, dx, dy) {
Daniel@0 7385 return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy]));
Daniel@0 7386 },
Daniel@0 7387 nw: function(event, dx, dy) {
Daniel@0 7388 return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy]));
Daniel@0 7389 }
Daniel@0 7390 },
Daniel@0 7391
Daniel@0 7392 _propagate: function(n, event) {
Daniel@0 7393 $.ui.plugin.call(this, n, [event, this.ui()]);
Daniel@0 7394 (n !== "resize" && this._trigger(n, event, this.ui()));
Daniel@0 7395 },
Daniel@0 7396
Daniel@0 7397 plugins: {},
Daniel@0 7398
Daniel@0 7399 ui: function() {
Daniel@0 7400 return {
Daniel@0 7401 originalElement: this.originalElement,
Daniel@0 7402 element: this.element,
Daniel@0 7403 helper: this.helper,
Daniel@0 7404 position: this.position,
Daniel@0 7405 size: this.size,
Daniel@0 7406 originalSize: this.originalSize,
Daniel@0 7407 originalPosition: this.originalPosition,
Daniel@0 7408 prevSize: this.prevSize,
Daniel@0 7409 prevPosition: this.prevPosition
Daniel@0 7410 };
Daniel@0 7411 }
Daniel@0 7412
Daniel@0 7413 });
Daniel@0 7414
Daniel@0 7415 /*
Daniel@0 7416 * Resizable Extensions
Daniel@0 7417 */
Daniel@0 7418
Daniel@0 7419 $.ui.plugin.add("resizable", "animate", {
Daniel@0 7420
Daniel@0 7421 stop: function( event ) {
Daniel@0 7422 var that = $(this).resizable( "instance" ),
Daniel@0 7423 o = that.options,
Daniel@0 7424 pr = that._proportionallyResizeElements,
Daniel@0 7425 ista = pr.length && (/textarea/i).test(pr[0].nodeName),
Daniel@0 7426 soffseth = ista && that._hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height,
Daniel@0 7427 soffsetw = ista ? 0 : that.sizeDiff.width,
Daniel@0 7428 style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
Daniel@0 7429 left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null,
Daniel@0 7430 top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null;
Daniel@0 7431
Daniel@0 7432 that.element.animate(
Daniel@0 7433 $.extend(style, top && left ? { top: top, left: left } : {}), {
Daniel@0 7434 duration: o.animateDuration,
Daniel@0 7435 easing: o.animateEasing,
Daniel@0 7436 step: function() {
Daniel@0 7437
Daniel@0 7438 var data = {
Daniel@0 7439 width: parseInt(that.element.css("width"), 10),
Daniel@0 7440 height: parseInt(that.element.css("height"), 10),
Daniel@0 7441 top: parseInt(that.element.css("top"), 10),
Daniel@0 7442 left: parseInt(that.element.css("left"), 10)
Daniel@0 7443 };
Daniel@0 7444
Daniel@0 7445 if (pr && pr.length) {
Daniel@0 7446 $(pr[0]).css({ width: data.width, height: data.height });
Daniel@0 7447 }
Daniel@0 7448
Daniel@0 7449 // propagating resize, and updating values for each animation step
Daniel@0 7450 that._updateCache(data);
Daniel@0 7451 that._propagate("resize", event);
Daniel@0 7452
Daniel@0 7453 }
Daniel@0 7454 }
Daniel@0 7455 );
Daniel@0 7456 }
Daniel@0 7457
Daniel@0 7458 });
Daniel@0 7459
Daniel@0 7460 $.ui.plugin.add( "resizable", "containment", {
Daniel@0 7461
Daniel@0 7462 start: function() {
Daniel@0 7463 var element, p, co, ch, cw, width, height,
Daniel@0 7464 that = $( this ).resizable( "instance" ),
Daniel@0 7465 o = that.options,
Daniel@0 7466 el = that.element,
Daniel@0 7467 oc = o.containment,
Daniel@0 7468 ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
Daniel@0 7469
Daniel@0 7470 if ( !ce ) {
Daniel@0 7471 return;
Daniel@0 7472 }
Daniel@0 7473
Daniel@0 7474 that.containerElement = $( ce );
Daniel@0 7475
Daniel@0 7476 if ( /document/.test( oc ) || oc === document ) {
Daniel@0 7477 that.containerOffset = {
Daniel@0 7478 left: 0,
Daniel@0 7479 top: 0
Daniel@0 7480 };
Daniel@0 7481 that.containerPosition = {
Daniel@0 7482 left: 0,
Daniel@0 7483 top: 0
Daniel@0 7484 };
Daniel@0 7485
Daniel@0 7486 that.parentData = {
Daniel@0 7487 element: $( document ),
Daniel@0 7488 left: 0,
Daniel@0 7489 top: 0,
Daniel@0 7490 width: $( document ).width(),
Daniel@0 7491 height: $( document ).height() || document.body.parentNode.scrollHeight
Daniel@0 7492 };
Daniel@0 7493 } else {
Daniel@0 7494 element = $( ce );
Daniel@0 7495 p = [];
Daniel@0 7496 $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
Daniel@0 7497 p[ i ] = that._num( element.css( "padding" + name ) );
Daniel@0 7498 });
Daniel@0 7499
Daniel@0 7500 that.containerOffset = element.offset();
Daniel@0 7501 that.containerPosition = element.position();
Daniel@0 7502 that.containerSize = {
Daniel@0 7503 height: ( element.innerHeight() - p[ 3 ] ),
Daniel@0 7504 width: ( element.innerWidth() - p[ 1 ] )
Daniel@0 7505 };
Daniel@0 7506
Daniel@0 7507 co = that.containerOffset;
Daniel@0 7508 ch = that.containerSize.height;
Daniel@0 7509 cw = that.containerSize.width;
Daniel@0 7510 width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
Daniel@0 7511 height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
Daniel@0 7512
Daniel@0 7513 that.parentData = {
Daniel@0 7514 element: ce,
Daniel@0 7515 left: co.left,
Daniel@0 7516 top: co.top,
Daniel@0 7517 width: width,
Daniel@0 7518 height: height
Daniel@0 7519 };
Daniel@0 7520 }
Daniel@0 7521 },
Daniel@0 7522
Daniel@0 7523 resize: function( event, ui ) {
Daniel@0 7524 var woset, hoset, isParent, isOffsetRelative,
Daniel@0 7525 that = $( this ).resizable( "instance" ),
Daniel@0 7526 o = that.options,
Daniel@0 7527 co = that.containerOffset,
Daniel@0 7528 cp = that.position,
Daniel@0 7529 pRatio = that._aspectRatio || event.shiftKey,
Daniel@0 7530 cop = {
Daniel@0 7531 top: 0,
Daniel@0 7532 left: 0
Daniel@0 7533 },
Daniel@0 7534 ce = that.containerElement,
Daniel@0 7535 continueResize = true;
Daniel@0 7536
Daniel@0 7537 if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
Daniel@0 7538 cop = co;
Daniel@0 7539 }
Daniel@0 7540
Daniel@0 7541 if ( cp.left < ( that._helper ? co.left : 0 ) ) {
Daniel@0 7542 that.size.width = that.size.width + ( that._helper ? ( that.position.left - co.left ) : ( that.position.left - cop.left ) );
Daniel@0 7543 if ( pRatio ) {
Daniel@0 7544 that.size.height = that.size.width / that.aspectRatio;
Daniel@0 7545 continueResize = false;
Daniel@0 7546 }
Daniel@0 7547 that.position.left = o.helper ? co.left : 0;
Daniel@0 7548 }
Daniel@0 7549
Daniel@0 7550 if ( cp.top < ( that._helper ? co.top : 0 ) ) {
Daniel@0 7551 that.size.height = that.size.height + ( that._helper ? ( that.position.top - co.top ) : that.position.top );
Daniel@0 7552 if ( pRatio ) {
Daniel@0 7553 that.size.width = that.size.height * that.aspectRatio;
Daniel@0 7554 continueResize = false;
Daniel@0 7555 }
Daniel@0 7556 that.position.top = that._helper ? co.top : 0;
Daniel@0 7557 }
Daniel@0 7558
Daniel@0 7559 that.offset.left = that.parentData.left + that.position.left;
Daniel@0 7560 that.offset.top = that.parentData.top + that.position.top;
Daniel@0 7561
Daniel@0 7562 woset = Math.abs( ( that._helper ? that.offset.left - cop.left : ( that.offset.left - co.left ) ) + that.sizeDiff.width );
Daniel@0 7563 hoset = Math.abs( ( that._helper ? that.offset.top - cop.top : ( that.offset.top - co.top ) ) + that.sizeDiff.height );
Daniel@0 7564
Daniel@0 7565 isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
Daniel@0 7566 isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
Daniel@0 7567
Daniel@0 7568 if ( isParent && isOffsetRelative ) {
Daniel@0 7569 woset -= Math.abs( that.parentData.left );
Daniel@0 7570 }
Daniel@0 7571
Daniel@0 7572 if ( woset + that.size.width >= that.parentData.width ) {
Daniel@0 7573 that.size.width = that.parentData.width - woset;
Daniel@0 7574 if ( pRatio ) {
Daniel@0 7575 that.size.height = that.size.width / that.aspectRatio;
Daniel@0 7576 continueResize = false;
Daniel@0 7577 }
Daniel@0 7578 }
Daniel@0 7579
Daniel@0 7580 if ( hoset + that.size.height >= that.parentData.height ) {
Daniel@0 7581 that.size.height = that.parentData.height - hoset;
Daniel@0 7582 if ( pRatio ) {
Daniel@0 7583 that.size.width = that.size.height * that.aspectRatio;
Daniel@0 7584 continueResize = false;
Daniel@0 7585 }
Daniel@0 7586 }
Daniel@0 7587
Daniel@0 7588 if ( !continueResize ){
Daniel@0 7589 that.position.left = ui.prevPosition.left;
Daniel@0 7590 that.position.top = ui.prevPosition.top;
Daniel@0 7591 that.size.width = ui.prevSize.width;
Daniel@0 7592 that.size.height = ui.prevSize.height;
Daniel@0 7593 }
Daniel@0 7594 },
Daniel@0 7595
Daniel@0 7596 stop: function(){
Daniel@0 7597 var that = $( this ).resizable( "instance" ),
Daniel@0 7598 o = that.options,
Daniel@0 7599 co = that.containerOffset,
Daniel@0 7600 cop = that.containerPosition,
Daniel@0 7601 ce = that.containerElement,
Daniel@0 7602 helper = $( that.helper ),
Daniel@0 7603 ho = helper.offset(),
Daniel@0 7604 w = helper.outerWidth() - that.sizeDiff.width,
Daniel@0 7605 h = helper.outerHeight() - that.sizeDiff.height;
Daniel@0 7606
Daniel@0 7607 if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
Daniel@0 7608 $( this ).css({
Daniel@0 7609 left: ho.left - cop.left - co.left,
Daniel@0 7610 width: w,
Daniel@0 7611 height: h
Daniel@0 7612 });
Daniel@0 7613 }
Daniel@0 7614
Daniel@0 7615 if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
Daniel@0 7616 $( this ).css({
Daniel@0 7617 left: ho.left - cop.left - co.left,
Daniel@0 7618 width: w,
Daniel@0 7619 height: h
Daniel@0 7620 });
Daniel@0 7621 }
Daniel@0 7622 }
Daniel@0 7623 });
Daniel@0 7624
Daniel@0 7625 $.ui.plugin.add("resizable", "alsoResize", {
Daniel@0 7626
Daniel@0 7627 start: function () {
Daniel@0 7628 var that = $(this).resizable( "instance" ),
Daniel@0 7629 o = that.options,
Daniel@0 7630 _store = function (exp) {
Daniel@0 7631 $(exp).each(function() {
Daniel@0 7632 var el = $(this);
Daniel@0 7633 el.data("ui-resizable-alsoresize", {
Daniel@0 7634 width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
Daniel@0 7635 left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
Daniel@0 7636 });
Daniel@0 7637 });
Daniel@0 7638 };
Daniel@0 7639
Daniel@0 7640 if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
Daniel@0 7641 if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); }
Daniel@0 7642 else { $.each(o.alsoResize, function (exp) { _store(exp); }); }
Daniel@0 7643 }else{
Daniel@0 7644 _store(o.alsoResize);
Daniel@0 7645 }
Daniel@0 7646 },
Daniel@0 7647
Daniel@0 7648 resize: function (event, ui) {
Daniel@0 7649 var that = $(this).resizable( "instance" ),
Daniel@0 7650 o = that.options,
Daniel@0 7651 os = that.originalSize,
Daniel@0 7652 op = that.originalPosition,
Daniel@0 7653 delta = {
Daniel@0 7654 height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0,
Daniel@0 7655 top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0
Daniel@0 7656 },
Daniel@0 7657
Daniel@0 7658 _alsoResize = function (exp, c) {
Daniel@0 7659 $(exp).each(function() {
Daniel@0 7660 var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
Daniel@0 7661 css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"];
Daniel@0 7662
Daniel@0 7663 $.each(css, function (i, prop) {
Daniel@0 7664 var sum = (start[prop]||0) + (delta[prop]||0);
Daniel@0 7665 if (sum && sum >= 0) {
Daniel@0 7666 style[prop] = sum || null;
Daniel@0 7667 }
Daniel@0 7668 });
Daniel@0 7669
Daniel@0 7670 el.css(style);
Daniel@0 7671 });
Daniel@0 7672 };
Daniel@0 7673
Daniel@0 7674 if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
Daniel@0 7675 $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); });
Daniel@0 7676 }else{
Daniel@0 7677 _alsoResize(o.alsoResize);
Daniel@0 7678 }
Daniel@0 7679 },
Daniel@0 7680
Daniel@0 7681 stop: function () {
Daniel@0 7682 $(this).removeData("resizable-alsoresize");
Daniel@0 7683 }
Daniel@0 7684 });
Daniel@0 7685
Daniel@0 7686 $.ui.plugin.add("resizable", "ghost", {
Daniel@0 7687
Daniel@0 7688 start: function() {
Daniel@0 7689
Daniel@0 7690 var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
Daniel@0 7691
Daniel@0 7692 that.ghost = that.originalElement.clone();
Daniel@0 7693 that.ghost
Daniel@0 7694 .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 })
Daniel@0 7695 .addClass("ui-resizable-ghost")
Daniel@0 7696 .addClass(typeof o.ghost === "string" ? o.ghost : "");
Daniel@0 7697
Daniel@0 7698 that.ghost.appendTo(that.helper);
Daniel@0 7699
Daniel@0 7700 },
Daniel@0 7701
Daniel@0 7702 resize: function(){
Daniel@0 7703 var that = $(this).resizable( "instance" );
Daniel@0 7704 if (that.ghost) {
Daniel@0 7705 that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width });
Daniel@0 7706 }
Daniel@0 7707 },
Daniel@0 7708
Daniel@0 7709 stop: function() {
Daniel@0 7710 var that = $(this).resizable( "instance" );
Daniel@0 7711 if (that.ghost && that.helper) {
Daniel@0 7712 that.helper.get(0).removeChild(that.ghost.get(0));
Daniel@0 7713 }
Daniel@0 7714 }
Daniel@0 7715
Daniel@0 7716 });
Daniel@0 7717
Daniel@0 7718 $.ui.plugin.add("resizable", "grid", {
Daniel@0 7719
Daniel@0 7720 resize: function() {
Daniel@0 7721 var that = $(this).resizable( "instance" ),
Daniel@0 7722 o = that.options,
Daniel@0 7723 cs = that.size,
Daniel@0 7724 os = that.originalSize,
Daniel@0 7725 op = that.originalPosition,
Daniel@0 7726 a = that.axis,
Daniel@0 7727 grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid,
Daniel@0 7728 gridX = (grid[0]||1),
Daniel@0 7729 gridY = (grid[1]||1),
Daniel@0 7730 ox = Math.round((cs.width - os.width) / gridX) * gridX,
Daniel@0 7731 oy = Math.round((cs.height - os.height) / gridY) * gridY,
Daniel@0 7732 newWidth = os.width + ox,
Daniel@0 7733 newHeight = os.height + oy,
Daniel@0 7734 isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
Daniel@0 7735 isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
Daniel@0 7736 isMinWidth = o.minWidth && (o.minWidth > newWidth),
Daniel@0 7737 isMinHeight = o.minHeight && (o.minHeight > newHeight);
Daniel@0 7738
Daniel@0 7739 o.grid = grid;
Daniel@0 7740
Daniel@0 7741 if (isMinWidth) {
Daniel@0 7742 newWidth = newWidth + gridX;
Daniel@0 7743 }
Daniel@0 7744 if (isMinHeight) {
Daniel@0 7745 newHeight = newHeight + gridY;
Daniel@0 7746 }
Daniel@0 7747 if (isMaxWidth) {
Daniel@0 7748 newWidth = newWidth - gridX;
Daniel@0 7749 }
Daniel@0 7750 if (isMaxHeight) {
Daniel@0 7751 newHeight = newHeight - gridY;
Daniel@0 7752 }
Daniel@0 7753
Daniel@0 7754 if (/^(se|s|e)$/.test(a)) {
Daniel@0 7755 that.size.width = newWidth;
Daniel@0 7756 that.size.height = newHeight;
Daniel@0 7757 } else if (/^(ne)$/.test(a)) {
Daniel@0 7758 that.size.width = newWidth;
Daniel@0 7759 that.size.height = newHeight;
Daniel@0 7760 that.position.top = op.top - oy;
Daniel@0 7761 } else if (/^(sw)$/.test(a)) {
Daniel@0 7762 that.size.width = newWidth;
Daniel@0 7763 that.size.height = newHeight;
Daniel@0 7764 that.position.left = op.left - ox;
Daniel@0 7765 } else {
Daniel@0 7766 if ( newHeight - gridY > 0 ) {
Daniel@0 7767 that.size.height = newHeight;
Daniel@0 7768 that.position.top = op.top - oy;
Daniel@0 7769 } else {
Daniel@0 7770 that.size.height = gridY;
Daniel@0 7771 that.position.top = op.top + os.height - gridY;
Daniel@0 7772 }
Daniel@0 7773 if ( newWidth - gridX > 0 ) {
Daniel@0 7774 that.size.width = newWidth;
Daniel@0 7775 that.position.left = op.left - ox;
Daniel@0 7776 } else {
Daniel@0 7777 that.size.width = gridX;
Daniel@0 7778 that.position.left = op.left + os.width - gridX;
Daniel@0 7779 }
Daniel@0 7780 }
Daniel@0 7781 }
Daniel@0 7782
Daniel@0 7783 });
Daniel@0 7784
Daniel@0 7785 var resizable = $.ui.resizable;
Daniel@0 7786
Daniel@0 7787
Daniel@0 7788 /*!
Daniel@0 7789 * jQuery UI Dialog 1.11.0
Daniel@0 7790 * http://jqueryui.com
Daniel@0 7791 *
Daniel@0 7792 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 7793 * Released under the MIT license.
Daniel@0 7794 * http://jquery.org/license
Daniel@0 7795 *
Daniel@0 7796 * http://api.jqueryui.com/dialog/
Daniel@0 7797 */
Daniel@0 7798
Daniel@0 7799
Daniel@0 7800 var dialog = $.widget( "ui.dialog", {
Daniel@0 7801 version: "1.11.0",
Daniel@0 7802 options: {
Daniel@0 7803 appendTo: "body",
Daniel@0 7804 autoOpen: true,
Daniel@0 7805 buttons: [],
Daniel@0 7806 closeOnEscape: true,
Daniel@0 7807 closeText: "Close",
Daniel@0 7808 dialogClass: "",
Daniel@0 7809 draggable: true,
Daniel@0 7810 hide: null,
Daniel@0 7811 height: "auto",
Daniel@0 7812 maxHeight: null,
Daniel@0 7813 maxWidth: null,
Daniel@0 7814 minHeight: 150,
Daniel@0 7815 minWidth: 150,
Daniel@0 7816 modal: false,
Daniel@0 7817 position: {
Daniel@0 7818 my: "center",
Daniel@0 7819 at: "center",
Daniel@0 7820 of: window,
Daniel@0 7821 collision: "fit",
Daniel@0 7822 // Ensure the titlebar is always visible
Daniel@0 7823 using: function( pos ) {
Daniel@0 7824 var topOffset = $( this ).css( pos ).offset().top;
Daniel@0 7825 if ( topOffset < 0 ) {
Daniel@0 7826 $( this ).css( "top", pos.top - topOffset );
Daniel@0 7827 }
Daniel@0 7828 }
Daniel@0 7829 },
Daniel@0 7830 resizable: true,
Daniel@0 7831 show: null,
Daniel@0 7832 title: null,
Daniel@0 7833 width: 300,
Daniel@0 7834
Daniel@0 7835 // callbacks
Daniel@0 7836 beforeClose: null,
Daniel@0 7837 close: null,
Daniel@0 7838 drag: null,
Daniel@0 7839 dragStart: null,
Daniel@0 7840 dragStop: null,
Daniel@0 7841 focus: null,
Daniel@0 7842 open: null,
Daniel@0 7843 resize: null,
Daniel@0 7844 resizeStart: null,
Daniel@0 7845 resizeStop: null
Daniel@0 7846 },
Daniel@0 7847
Daniel@0 7848 sizeRelatedOptions: {
Daniel@0 7849 buttons: true,
Daniel@0 7850 height: true,
Daniel@0 7851 maxHeight: true,
Daniel@0 7852 maxWidth: true,
Daniel@0 7853 minHeight: true,
Daniel@0 7854 minWidth: true,
Daniel@0 7855 width: true
Daniel@0 7856 },
Daniel@0 7857
Daniel@0 7858 resizableRelatedOptions: {
Daniel@0 7859 maxHeight: true,
Daniel@0 7860 maxWidth: true,
Daniel@0 7861 minHeight: true,
Daniel@0 7862 minWidth: true
Daniel@0 7863 },
Daniel@0 7864
Daniel@0 7865 _create: function() {
Daniel@0 7866 this.originalCss = {
Daniel@0 7867 display: this.element[ 0 ].style.display,
Daniel@0 7868 width: this.element[ 0 ].style.width,
Daniel@0 7869 minHeight: this.element[ 0 ].style.minHeight,
Daniel@0 7870 maxHeight: this.element[ 0 ].style.maxHeight,
Daniel@0 7871 height: this.element[ 0 ].style.height
Daniel@0 7872 };
Daniel@0 7873 this.originalPosition = {
Daniel@0 7874 parent: this.element.parent(),
Daniel@0 7875 index: this.element.parent().children().index( this.element )
Daniel@0 7876 };
Daniel@0 7877 this.originalTitle = this.element.attr( "title" );
Daniel@0 7878 this.options.title = this.options.title || this.originalTitle;
Daniel@0 7879
Daniel@0 7880 this._createWrapper();
Daniel@0 7881
Daniel@0 7882 this.element
Daniel@0 7883 .show()
Daniel@0 7884 .removeAttr( "title" )
Daniel@0 7885 .addClass( "ui-dialog-content ui-widget-content" )
Daniel@0 7886 .appendTo( this.uiDialog );
Daniel@0 7887
Daniel@0 7888 this._createTitlebar();
Daniel@0 7889 this._createButtonPane();
Daniel@0 7890
Daniel@0 7891 if ( this.options.draggable && $.fn.draggable ) {
Daniel@0 7892 this._makeDraggable();
Daniel@0 7893 }
Daniel@0 7894 if ( this.options.resizable && $.fn.resizable ) {
Daniel@0 7895 this._makeResizable();
Daniel@0 7896 }
Daniel@0 7897
Daniel@0 7898 this._isOpen = false;
Daniel@0 7899
Daniel@0 7900 this._trackFocus();
Daniel@0 7901 },
Daniel@0 7902
Daniel@0 7903 _init: function() {
Daniel@0 7904 if ( this.options.autoOpen ) {
Daniel@0 7905 this.open();
Daniel@0 7906 }
Daniel@0 7907 },
Daniel@0 7908
Daniel@0 7909 _appendTo: function() {
Daniel@0 7910 var element = this.options.appendTo;
Daniel@0 7911 if ( element && (element.jquery || element.nodeType) ) {
Daniel@0 7912 return $( element );
Daniel@0 7913 }
Daniel@0 7914 return this.document.find( element || "body" ).eq( 0 );
Daniel@0 7915 },
Daniel@0 7916
Daniel@0 7917 _destroy: function() {
Daniel@0 7918 var next,
Daniel@0 7919 originalPosition = this.originalPosition;
Daniel@0 7920
Daniel@0 7921 this._destroyOverlay();
Daniel@0 7922
Daniel@0 7923 this.element
Daniel@0 7924 .removeUniqueId()
Daniel@0 7925 .removeClass( "ui-dialog-content ui-widget-content" )
Daniel@0 7926 .css( this.originalCss )
Daniel@0 7927 // Without detaching first, the following becomes really slow
Daniel@0 7928 .detach();
Daniel@0 7929
Daniel@0 7930 this.uiDialog.stop( true, true ).remove();
Daniel@0 7931
Daniel@0 7932 if ( this.originalTitle ) {
Daniel@0 7933 this.element.attr( "title", this.originalTitle );
Daniel@0 7934 }
Daniel@0 7935
Daniel@0 7936 next = originalPosition.parent.children().eq( originalPosition.index );
Daniel@0 7937 // Don't try to place the dialog next to itself (#8613)
Daniel@0 7938 if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
Daniel@0 7939 next.before( this.element );
Daniel@0 7940 } else {
Daniel@0 7941 originalPosition.parent.append( this.element );
Daniel@0 7942 }
Daniel@0 7943 },
Daniel@0 7944
Daniel@0 7945 widget: function() {
Daniel@0 7946 return this.uiDialog;
Daniel@0 7947 },
Daniel@0 7948
Daniel@0 7949 disable: $.noop,
Daniel@0 7950 enable: $.noop,
Daniel@0 7951
Daniel@0 7952 close: function( event ) {
Daniel@0 7953 var activeElement,
Daniel@0 7954 that = this;
Daniel@0 7955
Daniel@0 7956 if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
Daniel@0 7957 return;
Daniel@0 7958 }
Daniel@0 7959
Daniel@0 7960 this._isOpen = false;
Daniel@0 7961 this._focusedElement = null;
Daniel@0 7962 this._destroyOverlay();
Daniel@0 7963 this._untrackInstance();
Daniel@0 7964
Daniel@0 7965 if ( !this.opener.filter( ":focusable" ).focus().length ) {
Daniel@0 7966
Daniel@0 7967 // support: IE9
Daniel@0 7968 // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
Daniel@0 7969 try {
Daniel@0 7970 activeElement = this.document[ 0 ].activeElement;
Daniel@0 7971
Daniel@0 7972 // Support: IE9, IE10
Daniel@0 7973 // If the <body> is blurred, IE will switch windows, see #4520
Daniel@0 7974 if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
Daniel@0 7975
Daniel@0 7976 // Hiding a focused element doesn't trigger blur in WebKit
Daniel@0 7977 // so in case we have nothing to focus on, explicitly blur the active element
Daniel@0 7978 // https://bugs.webkit.org/show_bug.cgi?id=47182
Daniel@0 7979 $( activeElement ).blur();
Daniel@0 7980 }
Daniel@0 7981 } catch ( error ) {}
Daniel@0 7982 }
Daniel@0 7983
Daniel@0 7984 this._hide( this.uiDialog, this.options.hide, function() {
Daniel@0 7985 that._trigger( "close", event );
Daniel@0 7986 });
Daniel@0 7987 },
Daniel@0 7988
Daniel@0 7989 isOpen: function() {
Daniel@0 7990 return this._isOpen;
Daniel@0 7991 },
Daniel@0 7992
Daniel@0 7993 moveToTop: function() {
Daniel@0 7994 this._moveToTop();
Daniel@0 7995 },
Daniel@0 7996
Daniel@0 7997 _moveToTop: function( event, silent ) {
Daniel@0 7998 var moved = false,
Daniel@0 7999 zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
Daniel@0 8000 return +$( this ).css( "z-index" );
Daniel@0 8001 }).get(),
Daniel@0 8002 zIndexMax = Math.max.apply( null, zIndicies );
Daniel@0 8003
Daniel@0 8004 if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
Daniel@0 8005 this.uiDialog.css( "z-index", zIndexMax + 1 );
Daniel@0 8006 moved = true;
Daniel@0 8007 }
Daniel@0 8008
Daniel@0 8009 if ( moved && !silent ) {
Daniel@0 8010 this._trigger( "focus", event );
Daniel@0 8011 }
Daniel@0 8012 return moved;
Daniel@0 8013 },
Daniel@0 8014
Daniel@0 8015 open: function() {
Daniel@0 8016 var that = this;
Daniel@0 8017 if ( this._isOpen ) {
Daniel@0 8018 if ( this._moveToTop() ) {
Daniel@0 8019 this._focusTabbable();
Daniel@0 8020 }
Daniel@0 8021 return;
Daniel@0 8022 }
Daniel@0 8023
Daniel@0 8024 this._isOpen = true;
Daniel@0 8025 this.opener = $( this.document[ 0 ].activeElement );
Daniel@0 8026
Daniel@0 8027 this._size();
Daniel@0 8028 this._position();
Daniel@0 8029 this._createOverlay();
Daniel@0 8030 this._moveToTop( null, true );
Daniel@0 8031 this._show( this.uiDialog, this.options.show, function() {
Daniel@0 8032 that._focusTabbable();
Daniel@0 8033 that._trigger( "focus" );
Daniel@0 8034 });
Daniel@0 8035
Daniel@0 8036 this._trigger( "open" );
Daniel@0 8037 },
Daniel@0 8038
Daniel@0 8039 _focusTabbable: function() {
Daniel@0 8040 // Set focus to the first match:
Daniel@0 8041 // 1. An element that was focused previously
Daniel@0 8042 // 2. First element inside the dialog matching [autofocus]
Daniel@0 8043 // 3. Tabbable element inside the content element
Daniel@0 8044 // 4. Tabbable element inside the buttonpane
Daniel@0 8045 // 5. The close button
Daniel@0 8046 // 6. The dialog itself
Daniel@0 8047 var hasFocus = this._focusedElement;
Daniel@0 8048 if ( !hasFocus ) {
Daniel@0 8049 hasFocus = this.element.find( "[autofocus]" );
Daniel@0 8050 }
Daniel@0 8051 if ( !hasFocus.length ) {
Daniel@0 8052 hasFocus = this.element.find( ":tabbable" );
Daniel@0 8053 }
Daniel@0 8054 if ( !hasFocus.length ) {
Daniel@0 8055 hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
Daniel@0 8056 }
Daniel@0 8057 if ( !hasFocus.length ) {
Daniel@0 8058 hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
Daniel@0 8059 }
Daniel@0 8060 if ( !hasFocus.length ) {
Daniel@0 8061 hasFocus = this.uiDialog;
Daniel@0 8062 }
Daniel@0 8063 hasFocus.eq( 0 ).focus();
Daniel@0 8064 },
Daniel@0 8065
Daniel@0 8066 _keepFocus: function( event ) {
Daniel@0 8067 function checkFocus() {
Daniel@0 8068 var activeElement = this.document[0].activeElement,
Daniel@0 8069 isActive = this.uiDialog[0] === activeElement ||
Daniel@0 8070 $.contains( this.uiDialog[0], activeElement );
Daniel@0 8071 if ( !isActive ) {
Daniel@0 8072 this._focusTabbable();
Daniel@0 8073 }
Daniel@0 8074 }
Daniel@0 8075 event.preventDefault();
Daniel@0 8076 checkFocus.call( this );
Daniel@0 8077 // support: IE
Daniel@0 8078 // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
Daniel@0 8079 // so we check again later
Daniel@0 8080 this._delay( checkFocus );
Daniel@0 8081 },
Daniel@0 8082
Daniel@0 8083 _createWrapper: function() {
Daniel@0 8084 this.uiDialog = $("<div>")
Daniel@0 8085 .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
Daniel@0 8086 this.options.dialogClass )
Daniel@0 8087 .hide()
Daniel@0 8088 .attr({
Daniel@0 8089 // Setting tabIndex makes the div focusable
Daniel@0 8090 tabIndex: -1,
Daniel@0 8091 role: "dialog"
Daniel@0 8092 })
Daniel@0 8093 .appendTo( this._appendTo() );
Daniel@0 8094
Daniel@0 8095 this._on( this.uiDialog, {
Daniel@0 8096 keydown: function( event ) {
Daniel@0 8097 if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
Daniel@0 8098 event.keyCode === $.ui.keyCode.ESCAPE ) {
Daniel@0 8099 event.preventDefault();
Daniel@0 8100 this.close( event );
Daniel@0 8101 return;
Daniel@0 8102 }
Daniel@0 8103
Daniel@0 8104 // prevent tabbing out of dialogs
Daniel@0 8105 if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
Daniel@0 8106 return;
Daniel@0 8107 }
Daniel@0 8108 var tabbables = this.uiDialog.find( ":tabbable" ),
Daniel@0 8109 first = tabbables.filter( ":first" ),
Daniel@0 8110 last = tabbables.filter( ":last" );
Daniel@0 8111
Daniel@0 8112 if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
Daniel@0 8113 this._delay(function() {
Daniel@0 8114 first.focus();
Daniel@0 8115 });
Daniel@0 8116 event.preventDefault();
Daniel@0 8117 } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
Daniel@0 8118 this._delay(function() {
Daniel@0 8119 last.focus();
Daniel@0 8120 });
Daniel@0 8121 event.preventDefault();
Daniel@0 8122 }
Daniel@0 8123 },
Daniel@0 8124 mousedown: function( event ) {
Daniel@0 8125 if ( this._moveToTop( event ) ) {
Daniel@0 8126 this._focusTabbable();
Daniel@0 8127 }
Daniel@0 8128 }
Daniel@0 8129 });
Daniel@0 8130
Daniel@0 8131 // We assume that any existing aria-describedby attribute means
Daniel@0 8132 // that the dialog content is marked up properly
Daniel@0 8133 // otherwise we brute force the content as the description
Daniel@0 8134 if ( !this.element.find( "[aria-describedby]" ).length ) {
Daniel@0 8135 this.uiDialog.attr({
Daniel@0 8136 "aria-describedby": this.element.uniqueId().attr( "id" )
Daniel@0 8137 });
Daniel@0 8138 }
Daniel@0 8139 },
Daniel@0 8140
Daniel@0 8141 _createTitlebar: function() {
Daniel@0 8142 var uiDialogTitle;
Daniel@0 8143
Daniel@0 8144 this.uiDialogTitlebar = $( "<div>" )
Daniel@0 8145 .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
Daniel@0 8146 .prependTo( this.uiDialog );
Daniel@0 8147 this._on( this.uiDialogTitlebar, {
Daniel@0 8148 mousedown: function( event ) {
Daniel@0 8149 // Don't prevent click on close button (#8838)
Daniel@0 8150 // Focusing a dialog that is partially scrolled out of view
Daniel@0 8151 // causes the browser to scroll it into view, preventing the click event
Daniel@0 8152 if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
Daniel@0 8153 // Dialog isn't getting focus when dragging (#8063)
Daniel@0 8154 this.uiDialog.focus();
Daniel@0 8155 }
Daniel@0 8156 }
Daniel@0 8157 });
Daniel@0 8158
Daniel@0 8159 // support: IE
Daniel@0 8160 // Use type="button" to prevent enter keypresses in textboxes from closing the
Daniel@0 8161 // dialog in IE (#9312)
Daniel@0 8162 this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
Daniel@0 8163 .button({
Daniel@0 8164 label: this.options.closeText,
Daniel@0 8165 icons: {
Daniel@0 8166 primary: "ui-icon-closethick"
Daniel@0 8167 },
Daniel@0 8168 text: false
Daniel@0 8169 })
Daniel@0 8170 .addClass( "ui-dialog-titlebar-close" )
Daniel@0 8171 .appendTo( this.uiDialogTitlebar );
Daniel@0 8172 this._on( this.uiDialogTitlebarClose, {
Daniel@0 8173 click: function( event ) {
Daniel@0 8174 event.preventDefault();
Daniel@0 8175 this.close( event );
Daniel@0 8176 }
Daniel@0 8177 });
Daniel@0 8178
Daniel@0 8179 uiDialogTitle = $( "<span>" )
Daniel@0 8180 .uniqueId()
Daniel@0 8181 .addClass( "ui-dialog-title" )
Daniel@0 8182 .prependTo( this.uiDialogTitlebar );
Daniel@0 8183 this._title( uiDialogTitle );
Daniel@0 8184
Daniel@0 8185 this.uiDialog.attr({
Daniel@0 8186 "aria-labelledby": uiDialogTitle.attr( "id" )
Daniel@0 8187 });
Daniel@0 8188 },
Daniel@0 8189
Daniel@0 8190 _title: function( title ) {
Daniel@0 8191 if ( !this.options.title ) {
Daniel@0 8192 title.html( "&#160;" );
Daniel@0 8193 }
Daniel@0 8194 title.text( this.options.title );
Daniel@0 8195 },
Daniel@0 8196
Daniel@0 8197 _createButtonPane: function() {
Daniel@0 8198 this.uiDialogButtonPane = $( "<div>" )
Daniel@0 8199 .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
Daniel@0 8200
Daniel@0 8201 this.uiButtonSet = $( "<div>" )
Daniel@0 8202 .addClass( "ui-dialog-buttonset" )
Daniel@0 8203 .appendTo( this.uiDialogButtonPane );
Daniel@0 8204
Daniel@0 8205 this._createButtons();
Daniel@0 8206 },
Daniel@0 8207
Daniel@0 8208 _createButtons: function() {
Daniel@0 8209 var that = this,
Daniel@0 8210 buttons = this.options.buttons;
Daniel@0 8211
Daniel@0 8212 // if we already have a button pane, remove it
Daniel@0 8213 this.uiDialogButtonPane.remove();
Daniel@0 8214 this.uiButtonSet.empty();
Daniel@0 8215
Daniel@0 8216 if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
Daniel@0 8217 this.uiDialog.removeClass( "ui-dialog-buttons" );
Daniel@0 8218 return;
Daniel@0 8219 }
Daniel@0 8220
Daniel@0 8221 $.each( buttons, function( name, props ) {
Daniel@0 8222 var click, buttonOptions;
Daniel@0 8223 props = $.isFunction( props ) ?
Daniel@0 8224 { click: props, text: name } :
Daniel@0 8225 props;
Daniel@0 8226 // Default to a non-submitting button
Daniel@0 8227 props = $.extend( { type: "button" }, props );
Daniel@0 8228 // Change the context for the click callback to be the main element
Daniel@0 8229 click = props.click;
Daniel@0 8230 props.click = function() {
Daniel@0 8231 click.apply( that.element[ 0 ], arguments );
Daniel@0 8232 };
Daniel@0 8233 buttonOptions = {
Daniel@0 8234 icons: props.icons,
Daniel@0 8235 text: props.showText
Daniel@0 8236 };
Daniel@0 8237 delete props.icons;
Daniel@0 8238 delete props.showText;
Daniel@0 8239 $( "<button></button>", props )
Daniel@0 8240 .button( buttonOptions )
Daniel@0 8241 .appendTo( that.uiButtonSet );
Daniel@0 8242 });
Daniel@0 8243 this.uiDialog.addClass( "ui-dialog-buttons" );
Daniel@0 8244 this.uiDialogButtonPane.appendTo( this.uiDialog );
Daniel@0 8245 },
Daniel@0 8246
Daniel@0 8247 _makeDraggable: function() {
Daniel@0 8248 var that = this,
Daniel@0 8249 options = this.options;
Daniel@0 8250
Daniel@0 8251 function filteredUi( ui ) {
Daniel@0 8252 return {
Daniel@0 8253 position: ui.position,
Daniel@0 8254 offset: ui.offset
Daniel@0 8255 };
Daniel@0 8256 }
Daniel@0 8257
Daniel@0 8258 this.uiDialog.draggable({
Daniel@0 8259 cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
Daniel@0 8260 handle: ".ui-dialog-titlebar",
Daniel@0 8261 containment: "document",
Daniel@0 8262 start: function( event, ui ) {
Daniel@0 8263 $( this ).addClass( "ui-dialog-dragging" );
Daniel@0 8264 that._blockFrames();
Daniel@0 8265 that._trigger( "dragStart", event, filteredUi( ui ) );
Daniel@0 8266 },
Daniel@0 8267 drag: function( event, ui ) {
Daniel@0 8268 that._trigger( "drag", event, filteredUi( ui ) );
Daniel@0 8269 },
Daniel@0 8270 stop: function( event, ui ) {
Daniel@0 8271 var left = ui.offset.left - that.document.scrollLeft(),
Daniel@0 8272 top = ui.offset.top - that.document.scrollTop();
Daniel@0 8273
Daniel@0 8274 options.position = {
Daniel@0 8275 my: "left top",
Daniel@0 8276 at: "left" + (left >= 0 ? "+" : "") + left + " " +
Daniel@0 8277 "top" + (top >= 0 ? "+" : "") + top,
Daniel@0 8278 of: that.window
Daniel@0 8279 };
Daniel@0 8280 $( this ).removeClass( "ui-dialog-dragging" );
Daniel@0 8281 that._unblockFrames();
Daniel@0 8282 that._trigger( "dragStop", event, filteredUi( ui ) );
Daniel@0 8283 }
Daniel@0 8284 });
Daniel@0 8285 },
Daniel@0 8286
Daniel@0 8287 _makeResizable: function() {
Daniel@0 8288 var that = this,
Daniel@0 8289 options = this.options,
Daniel@0 8290 handles = options.resizable,
Daniel@0 8291 // .ui-resizable has position: relative defined in the stylesheet
Daniel@0 8292 // but dialogs have to use absolute or fixed positioning
Daniel@0 8293 position = this.uiDialog.css("position"),
Daniel@0 8294 resizeHandles = typeof handles === "string" ?
Daniel@0 8295 handles :
Daniel@0 8296 "n,e,s,w,se,sw,ne,nw";
Daniel@0 8297
Daniel@0 8298 function filteredUi( ui ) {
Daniel@0 8299 return {
Daniel@0 8300 originalPosition: ui.originalPosition,
Daniel@0 8301 originalSize: ui.originalSize,
Daniel@0 8302 position: ui.position,
Daniel@0 8303 size: ui.size
Daniel@0 8304 };
Daniel@0 8305 }
Daniel@0 8306
Daniel@0 8307 this.uiDialog.resizable({
Daniel@0 8308 cancel: ".ui-dialog-content",
Daniel@0 8309 containment: "document",
Daniel@0 8310 alsoResize: this.element,
Daniel@0 8311 maxWidth: options.maxWidth,
Daniel@0 8312 maxHeight: options.maxHeight,
Daniel@0 8313 minWidth: options.minWidth,
Daniel@0 8314 minHeight: this._minHeight(),
Daniel@0 8315 handles: resizeHandles,
Daniel@0 8316 start: function( event, ui ) {
Daniel@0 8317 $( this ).addClass( "ui-dialog-resizing" );
Daniel@0 8318 that._blockFrames();
Daniel@0 8319 that._trigger( "resizeStart", event, filteredUi( ui ) );
Daniel@0 8320 },
Daniel@0 8321 resize: function( event, ui ) {
Daniel@0 8322 that._trigger( "resize", event, filteredUi( ui ) );
Daniel@0 8323 },
Daniel@0 8324 stop: function( event, ui ) {
Daniel@0 8325 var offset = that.uiDialog.offset(),
Daniel@0 8326 left = offset.left - that.document.scrollLeft(),
Daniel@0 8327 top = offset.top - that.document.scrollTop();
Daniel@0 8328
Daniel@0 8329 options.height = that.uiDialog.height();
Daniel@0 8330 options.width = that.uiDialog.width();
Daniel@0 8331 options.position = {
Daniel@0 8332 my: "left top",
Daniel@0 8333 at: "left" + (left >= 0 ? "+" : "") + left + " " +
Daniel@0 8334 "top" + (top >= 0 ? "+" : "") + top,
Daniel@0 8335 of: that.window
Daniel@0 8336 };
Daniel@0 8337 $( this ).removeClass( "ui-dialog-resizing" );
Daniel@0 8338 that._unblockFrames();
Daniel@0 8339 that._trigger( "resizeStop", event, filteredUi( ui ) );
Daniel@0 8340 }
Daniel@0 8341 })
Daniel@0 8342 .css( "position", position );
Daniel@0 8343 },
Daniel@0 8344
Daniel@0 8345 _trackFocus: function() {
Daniel@0 8346 this._on( this.widget(), {
Daniel@0 8347 "focusin": function( event ) {
Daniel@0 8348 this._untrackInstance();
Daniel@0 8349 this._trackingInstances().unshift( this );
Daniel@0 8350 this._focusedElement = $( event.target );
Daniel@0 8351 }
Daniel@0 8352 });
Daniel@0 8353 },
Daniel@0 8354
Daniel@0 8355 _untrackInstance: function() {
Daniel@0 8356 var instances = this._trackingInstances(),
Daniel@0 8357 exists = $.inArray( this, instances );
Daniel@0 8358 if ( exists !== -1 ) {
Daniel@0 8359 instances.splice( exists, 1 );
Daniel@0 8360 }
Daniel@0 8361 },
Daniel@0 8362
Daniel@0 8363 _trackingInstances: function() {
Daniel@0 8364 var instances = this.document.data( "ui-dialog-instances" );
Daniel@0 8365 if ( !instances ) {
Daniel@0 8366 instances = [];
Daniel@0 8367 this.document.data( "ui-dialog-instances", instances );
Daniel@0 8368 }
Daniel@0 8369 return instances;
Daniel@0 8370 },
Daniel@0 8371
Daniel@0 8372 _minHeight: function() {
Daniel@0 8373 var options = this.options;
Daniel@0 8374
Daniel@0 8375 return options.height === "auto" ?
Daniel@0 8376 options.minHeight :
Daniel@0 8377 Math.min( options.minHeight, options.height );
Daniel@0 8378 },
Daniel@0 8379
Daniel@0 8380 _position: function() {
Daniel@0 8381 // Need to show the dialog to get the actual offset in the position plugin
Daniel@0 8382 var isVisible = this.uiDialog.is( ":visible" );
Daniel@0 8383 if ( !isVisible ) {
Daniel@0 8384 this.uiDialog.show();
Daniel@0 8385 }
Daniel@0 8386 this.uiDialog.position( this.options.position );
Daniel@0 8387 if ( !isVisible ) {
Daniel@0 8388 this.uiDialog.hide();
Daniel@0 8389 }
Daniel@0 8390 },
Daniel@0 8391
Daniel@0 8392 _setOptions: function( options ) {
Daniel@0 8393 var that = this,
Daniel@0 8394 resize = false,
Daniel@0 8395 resizableOptions = {};
Daniel@0 8396
Daniel@0 8397 $.each( options, function( key, value ) {
Daniel@0 8398 that._setOption( key, value );
Daniel@0 8399
Daniel@0 8400 if ( key in that.sizeRelatedOptions ) {
Daniel@0 8401 resize = true;
Daniel@0 8402 }
Daniel@0 8403 if ( key in that.resizableRelatedOptions ) {
Daniel@0 8404 resizableOptions[ key ] = value;
Daniel@0 8405 }
Daniel@0 8406 });
Daniel@0 8407
Daniel@0 8408 if ( resize ) {
Daniel@0 8409 this._size();
Daniel@0 8410 this._position();
Daniel@0 8411 }
Daniel@0 8412 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
Daniel@0 8413 this.uiDialog.resizable( "option", resizableOptions );
Daniel@0 8414 }
Daniel@0 8415 },
Daniel@0 8416
Daniel@0 8417 _setOption: function( key, value ) {
Daniel@0 8418 var isDraggable, isResizable,
Daniel@0 8419 uiDialog = this.uiDialog;
Daniel@0 8420
Daniel@0 8421 if ( key === "dialogClass" ) {
Daniel@0 8422 uiDialog
Daniel@0 8423 .removeClass( this.options.dialogClass )
Daniel@0 8424 .addClass( value );
Daniel@0 8425 }
Daniel@0 8426
Daniel@0 8427 if ( key === "disabled" ) {
Daniel@0 8428 return;
Daniel@0 8429 }
Daniel@0 8430
Daniel@0 8431 this._super( key, value );
Daniel@0 8432
Daniel@0 8433 if ( key === "appendTo" ) {
Daniel@0 8434 this.uiDialog.appendTo( this._appendTo() );
Daniel@0 8435 }
Daniel@0 8436
Daniel@0 8437 if ( key === "buttons" ) {
Daniel@0 8438 this._createButtons();
Daniel@0 8439 }
Daniel@0 8440
Daniel@0 8441 if ( key === "closeText" ) {
Daniel@0 8442 this.uiDialogTitlebarClose.button({
Daniel@0 8443 // Ensure that we always pass a string
Daniel@0 8444 label: "" + value
Daniel@0 8445 });
Daniel@0 8446 }
Daniel@0 8447
Daniel@0 8448 if ( key === "draggable" ) {
Daniel@0 8449 isDraggable = uiDialog.is( ":data(ui-draggable)" );
Daniel@0 8450 if ( isDraggable && !value ) {
Daniel@0 8451 uiDialog.draggable( "destroy" );
Daniel@0 8452 }
Daniel@0 8453
Daniel@0 8454 if ( !isDraggable && value ) {
Daniel@0 8455 this._makeDraggable();
Daniel@0 8456 }
Daniel@0 8457 }
Daniel@0 8458
Daniel@0 8459 if ( key === "position" ) {
Daniel@0 8460 this._position();
Daniel@0 8461 }
Daniel@0 8462
Daniel@0 8463 if ( key === "resizable" ) {
Daniel@0 8464 // currently resizable, becoming non-resizable
Daniel@0 8465 isResizable = uiDialog.is( ":data(ui-resizable)" );
Daniel@0 8466 if ( isResizable && !value ) {
Daniel@0 8467 uiDialog.resizable( "destroy" );
Daniel@0 8468 }
Daniel@0 8469
Daniel@0 8470 // currently resizable, changing handles
Daniel@0 8471 if ( isResizable && typeof value === "string" ) {
Daniel@0 8472 uiDialog.resizable( "option", "handles", value );
Daniel@0 8473 }
Daniel@0 8474
Daniel@0 8475 // currently non-resizable, becoming resizable
Daniel@0 8476 if ( !isResizable && value !== false ) {
Daniel@0 8477 this._makeResizable();
Daniel@0 8478 }
Daniel@0 8479 }
Daniel@0 8480
Daniel@0 8481 if ( key === "title" ) {
Daniel@0 8482 this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
Daniel@0 8483 }
Daniel@0 8484 },
Daniel@0 8485
Daniel@0 8486 _size: function() {
Daniel@0 8487 // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
Daniel@0 8488 // divs will both have width and height set, so we need to reset them
Daniel@0 8489 var nonContentHeight, minContentHeight, maxContentHeight,
Daniel@0 8490 options = this.options;
Daniel@0 8491
Daniel@0 8492 // Reset content sizing
Daniel@0 8493 this.element.show().css({
Daniel@0 8494 width: "auto",
Daniel@0 8495 minHeight: 0,
Daniel@0 8496 maxHeight: "none",
Daniel@0 8497 height: 0
Daniel@0 8498 });
Daniel@0 8499
Daniel@0 8500 if ( options.minWidth > options.width ) {
Daniel@0 8501 options.width = options.minWidth;
Daniel@0 8502 }
Daniel@0 8503
Daniel@0 8504 // reset wrapper sizing
Daniel@0 8505 // determine the height of all the non-content elements
Daniel@0 8506 nonContentHeight = this.uiDialog.css({
Daniel@0 8507 height: "auto",
Daniel@0 8508 width: options.width
Daniel@0 8509 })
Daniel@0 8510 .outerHeight();
Daniel@0 8511 minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
Daniel@0 8512 maxContentHeight = typeof options.maxHeight === "number" ?
Daniel@0 8513 Math.max( 0, options.maxHeight - nonContentHeight ) :
Daniel@0 8514 "none";
Daniel@0 8515
Daniel@0 8516 if ( options.height === "auto" ) {
Daniel@0 8517 this.element.css({
Daniel@0 8518 minHeight: minContentHeight,
Daniel@0 8519 maxHeight: maxContentHeight,
Daniel@0 8520 height: "auto"
Daniel@0 8521 });
Daniel@0 8522 } else {
Daniel@0 8523 this.element.height( Math.max( 0, options.height - nonContentHeight ) );
Daniel@0 8524 }
Daniel@0 8525
Daniel@0 8526 if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
Daniel@0 8527 this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
Daniel@0 8528 }
Daniel@0 8529 },
Daniel@0 8530
Daniel@0 8531 _blockFrames: function() {
Daniel@0 8532 this.iframeBlocks = this.document.find( "iframe" ).map(function() {
Daniel@0 8533 var iframe = $( this );
Daniel@0 8534
Daniel@0 8535 return $( "<div>" )
Daniel@0 8536 .css({
Daniel@0 8537 position: "absolute",
Daniel@0 8538 width: iframe.outerWidth(),
Daniel@0 8539 height: iframe.outerHeight()
Daniel@0 8540 })
Daniel@0 8541 .appendTo( iframe.parent() )
Daniel@0 8542 .offset( iframe.offset() )[0];
Daniel@0 8543 });
Daniel@0 8544 },
Daniel@0 8545
Daniel@0 8546 _unblockFrames: function() {
Daniel@0 8547 if ( this.iframeBlocks ) {
Daniel@0 8548 this.iframeBlocks.remove();
Daniel@0 8549 delete this.iframeBlocks;
Daniel@0 8550 }
Daniel@0 8551 },
Daniel@0 8552
Daniel@0 8553 _allowInteraction: function( event ) {
Daniel@0 8554 if ( $( event.target ).closest( ".ui-dialog" ).length ) {
Daniel@0 8555 return true;
Daniel@0 8556 }
Daniel@0 8557
Daniel@0 8558 // TODO: Remove hack when datepicker implements
Daniel@0 8559 // the .ui-front logic (#8989)
Daniel@0 8560 return !!$( event.target ).closest( ".ui-datepicker" ).length;
Daniel@0 8561 },
Daniel@0 8562
Daniel@0 8563 _createOverlay: function() {
Daniel@0 8564 if ( !this.options.modal ) {
Daniel@0 8565 return;
Daniel@0 8566 }
Daniel@0 8567
Daniel@0 8568 // We use a delay in case the overlay is created from an
Daniel@0 8569 // event that we're going to be cancelling (#2804)
Daniel@0 8570 var isOpening = true;
Daniel@0 8571 this._delay(function() {
Daniel@0 8572 isOpening = false;
Daniel@0 8573 });
Daniel@0 8574
Daniel@0 8575 if ( !this.document.data( "ui-dialog-overlays" ) ) {
Daniel@0 8576
Daniel@0 8577 // Prevent use of anchors and inputs
Daniel@0 8578 // Using _on() for an event handler shared across many instances is
Daniel@0 8579 // safe because the dialogs stack and must be closed in reverse order
Daniel@0 8580 this._on( this.document, {
Daniel@0 8581 focusin: function( event ) {
Daniel@0 8582 if ( isOpening ) {
Daniel@0 8583 return;
Daniel@0 8584 }
Daniel@0 8585
Daniel@0 8586 if ( !this._allowInteraction( event ) ) {
Daniel@0 8587 event.preventDefault();
Daniel@0 8588 this._trackingInstances()[ 0 ]._focusTabbable();
Daniel@0 8589 }
Daniel@0 8590 }
Daniel@0 8591 });
Daniel@0 8592 }
Daniel@0 8593
Daniel@0 8594 this.overlay = $( "<div>" )
Daniel@0 8595 .addClass( "ui-widget-overlay ui-front" )
Daniel@0 8596 .appendTo( this._appendTo() );
Daniel@0 8597 this._on( this.overlay, {
Daniel@0 8598 mousedown: "_keepFocus"
Daniel@0 8599 });
Daniel@0 8600 this.document.data( "ui-dialog-overlays",
Daniel@0 8601 (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
Daniel@0 8602 },
Daniel@0 8603
Daniel@0 8604 _destroyOverlay: function() {
Daniel@0 8605 if ( !this.options.modal ) {
Daniel@0 8606 return;
Daniel@0 8607 }
Daniel@0 8608
Daniel@0 8609 if ( this.overlay ) {
Daniel@0 8610 var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
Daniel@0 8611
Daniel@0 8612 if ( !overlays ) {
Daniel@0 8613 this.document
Daniel@0 8614 .unbind( "focusin" )
Daniel@0 8615 .removeData( "ui-dialog-overlays" );
Daniel@0 8616 } else {
Daniel@0 8617 this.document.data( "ui-dialog-overlays", overlays );
Daniel@0 8618 }
Daniel@0 8619
Daniel@0 8620 this.overlay.remove();
Daniel@0 8621 this.overlay = null;
Daniel@0 8622 }
Daniel@0 8623 }
Daniel@0 8624 });
Daniel@0 8625
Daniel@0 8626
Daniel@0 8627 /*!
Daniel@0 8628 * jQuery UI Droppable 1.11.0
Daniel@0 8629 * http://jqueryui.com
Daniel@0 8630 *
Daniel@0 8631 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 8632 * Released under the MIT license.
Daniel@0 8633 * http://jquery.org/license
Daniel@0 8634 *
Daniel@0 8635 * http://api.jqueryui.com/droppable/
Daniel@0 8636 */
Daniel@0 8637
Daniel@0 8638
Daniel@0 8639 $.widget( "ui.droppable", {
Daniel@0 8640 version: "1.11.0",
Daniel@0 8641 widgetEventPrefix: "drop",
Daniel@0 8642 options: {
Daniel@0 8643 accept: "*",
Daniel@0 8644 activeClass: false,
Daniel@0 8645 addClasses: true,
Daniel@0 8646 greedy: false,
Daniel@0 8647 hoverClass: false,
Daniel@0 8648 scope: "default",
Daniel@0 8649 tolerance: "intersect",
Daniel@0 8650
Daniel@0 8651 // callbacks
Daniel@0 8652 activate: null,
Daniel@0 8653 deactivate: null,
Daniel@0 8654 drop: null,
Daniel@0 8655 out: null,
Daniel@0 8656 over: null
Daniel@0 8657 },
Daniel@0 8658 _create: function() {
Daniel@0 8659
Daniel@0 8660 var proportions,
Daniel@0 8661 o = this.options,
Daniel@0 8662 accept = o.accept;
Daniel@0 8663
Daniel@0 8664 this.isover = false;
Daniel@0 8665 this.isout = true;
Daniel@0 8666
Daniel@0 8667 this.accept = $.isFunction( accept ) ? accept : function( d ) {
Daniel@0 8668 return d.is( accept );
Daniel@0 8669 };
Daniel@0 8670
Daniel@0 8671 this.proportions = function( /* valueToWrite */ ) {
Daniel@0 8672 if ( arguments.length ) {
Daniel@0 8673 // Store the droppable's proportions
Daniel@0 8674 proportions = arguments[ 0 ];
Daniel@0 8675 } else {
Daniel@0 8676 // Retrieve or derive the droppable's proportions
Daniel@0 8677 return proportions ?
Daniel@0 8678 proportions :
Daniel@0 8679 proportions = {
Daniel@0 8680 width: this.element[ 0 ].offsetWidth,
Daniel@0 8681 height: this.element[ 0 ].offsetHeight
Daniel@0 8682 };
Daniel@0 8683 }
Daniel@0 8684 };
Daniel@0 8685
Daniel@0 8686 this._addToManager( o.scope );
Daniel@0 8687
Daniel@0 8688 o.addClasses && this.element.addClass( "ui-droppable" );
Daniel@0 8689
Daniel@0 8690 },
Daniel@0 8691
Daniel@0 8692 _addToManager: function( scope ) {
Daniel@0 8693 // Add the reference and positions to the manager
Daniel@0 8694 $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
Daniel@0 8695 $.ui.ddmanager.droppables[ scope ].push( this );
Daniel@0 8696 },
Daniel@0 8697
Daniel@0 8698 _splice: function( drop ) {
Daniel@0 8699 var i = 0;
Daniel@0 8700 for ( ; i < drop.length; i++ ) {
Daniel@0 8701 if ( drop[ i ] === this ) {
Daniel@0 8702 drop.splice( i, 1 );
Daniel@0 8703 }
Daniel@0 8704 }
Daniel@0 8705 },
Daniel@0 8706
Daniel@0 8707 _destroy: function() {
Daniel@0 8708 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
Daniel@0 8709
Daniel@0 8710 this._splice( drop );
Daniel@0 8711
Daniel@0 8712 this.element.removeClass( "ui-droppable ui-droppable-disabled" );
Daniel@0 8713 },
Daniel@0 8714
Daniel@0 8715 _setOption: function( key, value ) {
Daniel@0 8716
Daniel@0 8717 if ( key === "accept" ) {
Daniel@0 8718 this.accept = $.isFunction( value ) ? value : function( d ) {
Daniel@0 8719 return d.is( value );
Daniel@0 8720 };
Daniel@0 8721 } else if ( key === "scope" ) {
Daniel@0 8722 var drop = $.ui.ddmanager.droppables[ this.options.scope ];
Daniel@0 8723
Daniel@0 8724 this._splice( drop );
Daniel@0 8725 this._addToManager( value );
Daniel@0 8726 }
Daniel@0 8727
Daniel@0 8728 this._super( key, value );
Daniel@0 8729 },
Daniel@0 8730
Daniel@0 8731 _activate: function( event ) {
Daniel@0 8732 var draggable = $.ui.ddmanager.current;
Daniel@0 8733 if ( this.options.activeClass ) {
Daniel@0 8734 this.element.addClass( this.options.activeClass );
Daniel@0 8735 }
Daniel@0 8736 if ( draggable ){
Daniel@0 8737 this._trigger( "activate", event, this.ui( draggable ) );
Daniel@0 8738 }
Daniel@0 8739 },
Daniel@0 8740
Daniel@0 8741 _deactivate: function( event ) {
Daniel@0 8742 var draggable = $.ui.ddmanager.current;
Daniel@0 8743 if ( this.options.activeClass ) {
Daniel@0 8744 this.element.removeClass( this.options.activeClass );
Daniel@0 8745 }
Daniel@0 8746 if ( draggable ){
Daniel@0 8747 this._trigger( "deactivate", event, this.ui( draggable ) );
Daniel@0 8748 }
Daniel@0 8749 },
Daniel@0 8750
Daniel@0 8751 _over: function( event ) {
Daniel@0 8752
Daniel@0 8753 var draggable = $.ui.ddmanager.current;
Daniel@0 8754
Daniel@0 8755 // Bail if draggable and droppable are same element
Daniel@0 8756 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
Daniel@0 8757 return;
Daniel@0 8758 }
Daniel@0 8759
Daniel@0 8760 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
Daniel@0 8761 if ( this.options.hoverClass ) {
Daniel@0 8762 this.element.addClass( this.options.hoverClass );
Daniel@0 8763 }
Daniel@0 8764 this._trigger( "over", event, this.ui( draggable ) );
Daniel@0 8765 }
Daniel@0 8766
Daniel@0 8767 },
Daniel@0 8768
Daniel@0 8769 _out: function( event ) {
Daniel@0 8770
Daniel@0 8771 var draggable = $.ui.ddmanager.current;
Daniel@0 8772
Daniel@0 8773 // Bail if draggable and droppable are same element
Daniel@0 8774 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
Daniel@0 8775 return;
Daniel@0 8776 }
Daniel@0 8777
Daniel@0 8778 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
Daniel@0 8779 if ( this.options.hoverClass ) {
Daniel@0 8780 this.element.removeClass( this.options.hoverClass );
Daniel@0 8781 }
Daniel@0 8782 this._trigger( "out", event, this.ui( draggable ) );
Daniel@0 8783 }
Daniel@0 8784
Daniel@0 8785 },
Daniel@0 8786
Daniel@0 8787 _drop: function( event, custom ) {
Daniel@0 8788
Daniel@0 8789 var draggable = custom || $.ui.ddmanager.current,
Daniel@0 8790 childrenIntersection = false;
Daniel@0 8791
Daniel@0 8792 // Bail if draggable and droppable are same element
Daniel@0 8793 if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
Daniel@0 8794 return false;
Daniel@0 8795 }
Daniel@0 8796
Daniel@0 8797 this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
Daniel@0 8798 var inst = $( this ).droppable( "instance" );
Daniel@0 8799 if (
Daniel@0 8800 inst.options.greedy &&
Daniel@0 8801 !inst.options.disabled &&
Daniel@0 8802 inst.options.scope === draggable.options.scope &&
Daniel@0 8803 inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
Daniel@0 8804 $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance )
Daniel@0 8805 ) { childrenIntersection = true; return false; }
Daniel@0 8806 });
Daniel@0 8807 if ( childrenIntersection ) {
Daniel@0 8808 return false;
Daniel@0 8809 }
Daniel@0 8810
Daniel@0 8811 if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
Daniel@0 8812 if ( this.options.activeClass ) {
Daniel@0 8813 this.element.removeClass( this.options.activeClass );
Daniel@0 8814 }
Daniel@0 8815 if ( this.options.hoverClass ) {
Daniel@0 8816 this.element.removeClass( this.options.hoverClass );
Daniel@0 8817 }
Daniel@0 8818 this._trigger( "drop", event, this.ui( draggable ) );
Daniel@0 8819 return this.element;
Daniel@0 8820 }
Daniel@0 8821
Daniel@0 8822 return false;
Daniel@0 8823
Daniel@0 8824 },
Daniel@0 8825
Daniel@0 8826 ui: function( c ) {
Daniel@0 8827 return {
Daniel@0 8828 draggable: ( c.currentItem || c.element ),
Daniel@0 8829 helper: c.helper,
Daniel@0 8830 position: c.position,
Daniel@0 8831 offset: c.positionAbs
Daniel@0 8832 };
Daniel@0 8833 }
Daniel@0 8834
Daniel@0 8835 });
Daniel@0 8836
Daniel@0 8837 $.ui.intersect = (function() {
Daniel@0 8838 function isOverAxis( x, reference, size ) {
Daniel@0 8839 return ( x >= reference ) && ( x < ( reference + size ) );
Daniel@0 8840 }
Daniel@0 8841
Daniel@0 8842 return function( draggable, droppable, toleranceMode ) {
Daniel@0 8843
Daniel@0 8844 if ( !droppable.offset ) {
Daniel@0 8845 return false;
Daniel@0 8846 }
Daniel@0 8847
Daniel@0 8848 var draggableLeft, draggableTop,
Daniel@0 8849 x1 = ( draggable.positionAbs || draggable.position.absolute ).left,
Daniel@0 8850 y1 = ( draggable.positionAbs || draggable.position.absolute ).top,
Daniel@0 8851 x2 = x1 + draggable.helperProportions.width,
Daniel@0 8852 y2 = y1 + draggable.helperProportions.height,
Daniel@0 8853 l = droppable.offset.left,
Daniel@0 8854 t = droppable.offset.top,
Daniel@0 8855 r = l + droppable.proportions().width,
Daniel@0 8856 b = t + droppable.proportions().height;
Daniel@0 8857
Daniel@0 8858 switch ( toleranceMode ) {
Daniel@0 8859 case "fit":
Daniel@0 8860 return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
Daniel@0 8861 case "intersect":
Daniel@0 8862 return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
Daniel@0 8863 x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
Daniel@0 8864 t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
Daniel@0 8865 y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
Daniel@0 8866 case "pointer":
Daniel@0 8867 draggableLeft = ( ( draggable.positionAbs || draggable.position.absolute ).left + ( draggable.clickOffset || draggable.offset.click ).left );
Daniel@0 8868 draggableTop = ( ( draggable.positionAbs || draggable.position.absolute ).top + ( draggable.clickOffset || draggable.offset.click ).top );
Daniel@0 8869 return isOverAxis( draggableTop, t, droppable.proportions().height ) && isOverAxis( draggableLeft, l, droppable.proportions().width );
Daniel@0 8870 case "touch":
Daniel@0 8871 return (
Daniel@0 8872 ( y1 >= t && y1 <= b ) || // Top edge touching
Daniel@0 8873 ( y2 >= t && y2 <= b ) || // Bottom edge touching
Daniel@0 8874 ( y1 < t && y2 > b ) // Surrounded vertically
Daniel@0 8875 ) && (
Daniel@0 8876 ( x1 >= l && x1 <= r ) || // Left edge touching
Daniel@0 8877 ( x2 >= l && x2 <= r ) || // Right edge touching
Daniel@0 8878 ( x1 < l && x2 > r ) // Surrounded horizontally
Daniel@0 8879 );
Daniel@0 8880 default:
Daniel@0 8881 return false;
Daniel@0 8882 }
Daniel@0 8883 };
Daniel@0 8884 })();
Daniel@0 8885
Daniel@0 8886 /*
Daniel@0 8887 This manager tracks offsets of draggables and droppables
Daniel@0 8888 */
Daniel@0 8889 $.ui.ddmanager = {
Daniel@0 8890 current: null,
Daniel@0 8891 droppables: { "default": [] },
Daniel@0 8892 prepareOffsets: function( t, event ) {
Daniel@0 8893
Daniel@0 8894 var i, j,
Daniel@0 8895 m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
Daniel@0 8896 type = event ? event.type : null, // workaround for #2317
Daniel@0 8897 list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
Daniel@0 8898
Daniel@0 8899 droppablesLoop: for ( i = 0; i < m.length; i++ ) {
Daniel@0 8900
Daniel@0 8901 // No disabled and non-accepted
Daniel@0 8902 if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
Daniel@0 8903 continue;
Daniel@0 8904 }
Daniel@0 8905
Daniel@0 8906 // Filter out elements in the current dragged item
Daniel@0 8907 for ( j = 0; j < list.length; j++ ) {
Daniel@0 8908 if ( list[ j ] === m[ i ].element[ 0 ] ) {
Daniel@0 8909 m[ i ].proportions().height = 0;
Daniel@0 8910 continue droppablesLoop;
Daniel@0 8911 }
Daniel@0 8912 }
Daniel@0 8913
Daniel@0 8914 m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
Daniel@0 8915 if ( !m[ i ].visible ) {
Daniel@0 8916 continue;
Daniel@0 8917 }
Daniel@0 8918
Daniel@0 8919 // Activate the droppable if used directly from draggables
Daniel@0 8920 if ( type === "mousedown" ) {
Daniel@0 8921 m[ i ]._activate.call( m[ i ], event );
Daniel@0 8922 }
Daniel@0 8923
Daniel@0 8924 m[ i ].offset = m[ i ].element.offset();
Daniel@0 8925 m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
Daniel@0 8926
Daniel@0 8927 }
Daniel@0 8928
Daniel@0 8929 },
Daniel@0 8930 drop: function( draggable, event ) {
Daniel@0 8931
Daniel@0 8932 var dropped = false;
Daniel@0 8933 // Create a copy of the droppables in case the list changes during the drop (#9116)
Daniel@0 8934 $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
Daniel@0 8935
Daniel@0 8936 if ( !this.options ) {
Daniel@0 8937 return;
Daniel@0 8938 }
Daniel@0 8939 if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance ) ) {
Daniel@0 8940 dropped = this._drop.call( this, event ) || dropped;
Daniel@0 8941 }
Daniel@0 8942
Daniel@0 8943 if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
Daniel@0 8944 this.isout = true;
Daniel@0 8945 this.isover = false;
Daniel@0 8946 this._deactivate.call( this, event );
Daniel@0 8947 }
Daniel@0 8948
Daniel@0 8949 });
Daniel@0 8950 return dropped;
Daniel@0 8951
Daniel@0 8952 },
Daniel@0 8953 dragStart: function( draggable, event ) {
Daniel@0 8954 // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
Daniel@0 8955 draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
Daniel@0 8956 if ( !draggable.options.refreshPositions ) {
Daniel@0 8957 $.ui.ddmanager.prepareOffsets( draggable, event );
Daniel@0 8958 }
Daniel@0 8959 });
Daniel@0 8960 },
Daniel@0 8961 drag: function( draggable, event ) {
Daniel@0 8962
Daniel@0 8963 // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
Daniel@0 8964 if ( draggable.options.refreshPositions ) {
Daniel@0 8965 $.ui.ddmanager.prepareOffsets( draggable, event );
Daniel@0 8966 }
Daniel@0 8967
Daniel@0 8968 // Run through all droppables and check their positions based on specific tolerance options
Daniel@0 8969 $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
Daniel@0 8970
Daniel@0 8971 if ( this.options.disabled || this.greedyChild || !this.visible ) {
Daniel@0 8972 return;
Daniel@0 8973 }
Daniel@0 8974
Daniel@0 8975 var parentInstance, scope, parent,
Daniel@0 8976 intersects = $.ui.intersect( draggable, this, this.options.tolerance ),
Daniel@0 8977 c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
Daniel@0 8978 if ( !c ) {
Daniel@0 8979 return;
Daniel@0 8980 }
Daniel@0 8981
Daniel@0 8982 if ( this.options.greedy ) {
Daniel@0 8983 // find droppable parents with same scope
Daniel@0 8984 scope = this.options.scope;
Daniel@0 8985 parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
Daniel@0 8986 return $( this ).droppable( "instance" ).options.scope === scope;
Daniel@0 8987 });
Daniel@0 8988
Daniel@0 8989 if ( parent.length ) {
Daniel@0 8990 parentInstance = $( parent[ 0 ] ).droppable( "instance" );
Daniel@0 8991 parentInstance.greedyChild = ( c === "isover" );
Daniel@0 8992 }
Daniel@0 8993 }
Daniel@0 8994
Daniel@0 8995 // we just moved into a greedy child
Daniel@0 8996 if ( parentInstance && c === "isover" ) {
Daniel@0 8997 parentInstance.isover = false;
Daniel@0 8998 parentInstance.isout = true;
Daniel@0 8999 parentInstance._out.call( parentInstance, event );
Daniel@0 9000 }
Daniel@0 9001
Daniel@0 9002 this[ c ] = true;
Daniel@0 9003 this[c === "isout" ? "isover" : "isout"] = false;
Daniel@0 9004 this[c === "isover" ? "_over" : "_out"].call( this, event );
Daniel@0 9005
Daniel@0 9006 // we just moved out of a greedy child
Daniel@0 9007 if ( parentInstance && c === "isout" ) {
Daniel@0 9008 parentInstance.isout = false;
Daniel@0 9009 parentInstance.isover = true;
Daniel@0 9010 parentInstance._over.call( parentInstance, event );
Daniel@0 9011 }
Daniel@0 9012 });
Daniel@0 9013
Daniel@0 9014 },
Daniel@0 9015 dragStop: function( draggable, event ) {
Daniel@0 9016 draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
Daniel@0 9017 // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
Daniel@0 9018 if ( !draggable.options.refreshPositions ) {
Daniel@0 9019 $.ui.ddmanager.prepareOffsets( draggable, event );
Daniel@0 9020 }
Daniel@0 9021 }
Daniel@0 9022 };
Daniel@0 9023
Daniel@0 9024 var droppable = $.ui.droppable;
Daniel@0 9025
Daniel@0 9026
Daniel@0 9027 /*!
Daniel@0 9028 * jQuery UI Effects 1.11.0
Daniel@0 9029 * http://jqueryui.com
Daniel@0 9030 *
Daniel@0 9031 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 9032 * Released under the MIT license.
Daniel@0 9033 * http://jquery.org/license
Daniel@0 9034 *
Daniel@0 9035 * http://api.jqueryui.com/category/effects-core/
Daniel@0 9036 */
Daniel@0 9037
Daniel@0 9038
Daniel@0 9039 var dataSpace = "ui-effects-";
Daniel@0 9040
Daniel@0 9041 $.effects = {
Daniel@0 9042 effect: {}
Daniel@0 9043 };
Daniel@0 9044
Daniel@0 9045 /*!
Daniel@0 9046 * jQuery Color Animations v2.1.2
Daniel@0 9047 * https://github.com/jquery/jquery-color
Daniel@0 9048 *
Daniel@0 9049 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 9050 * Released under the MIT license.
Daniel@0 9051 * http://jquery.org/license
Daniel@0 9052 *
Daniel@0 9053 * Date: Wed Jan 16 08:47:09 2013 -0600
Daniel@0 9054 */
Daniel@0 9055 (function( jQuery, undefined ) {
Daniel@0 9056
Daniel@0 9057 var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
Daniel@0 9058
Daniel@0 9059 // plusequals test for += 100 -= 100
Daniel@0 9060 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
Daniel@0 9061 // a set of RE's that can match strings and generate color tuples.
Daniel@0 9062 stringParsers = [ {
Daniel@0 9063 re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
Daniel@0 9064 parse: function( execResult ) {
Daniel@0 9065 return [
Daniel@0 9066 execResult[ 1 ],
Daniel@0 9067 execResult[ 2 ],
Daniel@0 9068 execResult[ 3 ],
Daniel@0 9069 execResult[ 4 ]
Daniel@0 9070 ];
Daniel@0 9071 }
Daniel@0 9072 }, {
Daniel@0 9073 re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
Daniel@0 9074 parse: function( execResult ) {
Daniel@0 9075 return [
Daniel@0 9076 execResult[ 1 ] * 2.55,
Daniel@0 9077 execResult[ 2 ] * 2.55,
Daniel@0 9078 execResult[ 3 ] * 2.55,
Daniel@0 9079 execResult[ 4 ]
Daniel@0 9080 ];
Daniel@0 9081 }
Daniel@0 9082 }, {
Daniel@0 9083 // this regex ignores A-F because it's compared against an already lowercased string
Daniel@0 9084 re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
Daniel@0 9085 parse: function( execResult ) {
Daniel@0 9086 return [
Daniel@0 9087 parseInt( execResult[ 1 ], 16 ),
Daniel@0 9088 parseInt( execResult[ 2 ], 16 ),
Daniel@0 9089 parseInt( execResult[ 3 ], 16 )
Daniel@0 9090 ];
Daniel@0 9091 }
Daniel@0 9092 }, {
Daniel@0 9093 // this regex ignores A-F because it's compared against an already lowercased string
Daniel@0 9094 re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
Daniel@0 9095 parse: function( execResult ) {
Daniel@0 9096 return [
Daniel@0 9097 parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
Daniel@0 9098 parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
Daniel@0 9099 parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
Daniel@0 9100 ];
Daniel@0 9101 }
Daniel@0 9102 }, {
Daniel@0 9103 re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
Daniel@0 9104 space: "hsla",
Daniel@0 9105 parse: function( execResult ) {
Daniel@0 9106 return [
Daniel@0 9107 execResult[ 1 ],
Daniel@0 9108 execResult[ 2 ] / 100,
Daniel@0 9109 execResult[ 3 ] / 100,
Daniel@0 9110 execResult[ 4 ]
Daniel@0 9111 ];
Daniel@0 9112 }
Daniel@0 9113 } ],
Daniel@0 9114
Daniel@0 9115 // jQuery.Color( )
Daniel@0 9116 color = jQuery.Color = function( color, green, blue, alpha ) {
Daniel@0 9117 return new jQuery.Color.fn.parse( color, green, blue, alpha );
Daniel@0 9118 },
Daniel@0 9119 spaces = {
Daniel@0 9120 rgba: {
Daniel@0 9121 props: {
Daniel@0 9122 red: {
Daniel@0 9123 idx: 0,
Daniel@0 9124 type: "byte"
Daniel@0 9125 },
Daniel@0 9126 green: {
Daniel@0 9127 idx: 1,
Daniel@0 9128 type: "byte"
Daniel@0 9129 },
Daniel@0 9130 blue: {
Daniel@0 9131 idx: 2,
Daniel@0 9132 type: "byte"
Daniel@0 9133 }
Daniel@0 9134 }
Daniel@0 9135 },
Daniel@0 9136
Daniel@0 9137 hsla: {
Daniel@0 9138 props: {
Daniel@0 9139 hue: {
Daniel@0 9140 idx: 0,
Daniel@0 9141 type: "degrees"
Daniel@0 9142 },
Daniel@0 9143 saturation: {
Daniel@0 9144 idx: 1,
Daniel@0 9145 type: "percent"
Daniel@0 9146 },
Daniel@0 9147 lightness: {
Daniel@0 9148 idx: 2,
Daniel@0 9149 type: "percent"
Daniel@0 9150 }
Daniel@0 9151 }
Daniel@0 9152 }
Daniel@0 9153 },
Daniel@0 9154 propTypes = {
Daniel@0 9155 "byte": {
Daniel@0 9156 floor: true,
Daniel@0 9157 max: 255
Daniel@0 9158 },
Daniel@0 9159 "percent": {
Daniel@0 9160 max: 1
Daniel@0 9161 },
Daniel@0 9162 "degrees": {
Daniel@0 9163 mod: 360,
Daniel@0 9164 floor: true
Daniel@0 9165 }
Daniel@0 9166 },
Daniel@0 9167 support = color.support = {},
Daniel@0 9168
Daniel@0 9169 // element for support tests
Daniel@0 9170 supportElem = jQuery( "<p>" )[ 0 ],
Daniel@0 9171
Daniel@0 9172 // colors = jQuery.Color.names
Daniel@0 9173 colors,
Daniel@0 9174
Daniel@0 9175 // local aliases of functions called often
Daniel@0 9176 each = jQuery.each;
Daniel@0 9177
Daniel@0 9178 // determine rgba support immediately
Daniel@0 9179 supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
Daniel@0 9180 support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
Daniel@0 9181
Daniel@0 9182 // define cache name and alpha properties
Daniel@0 9183 // for rgba and hsla spaces
Daniel@0 9184 each( spaces, function( spaceName, space ) {
Daniel@0 9185 space.cache = "_" + spaceName;
Daniel@0 9186 space.props.alpha = {
Daniel@0 9187 idx: 3,
Daniel@0 9188 type: "percent",
Daniel@0 9189 def: 1
Daniel@0 9190 };
Daniel@0 9191 });
Daniel@0 9192
Daniel@0 9193 function clamp( value, prop, allowEmpty ) {
Daniel@0 9194 var type = propTypes[ prop.type ] || {};
Daniel@0 9195
Daniel@0 9196 if ( value == null ) {
Daniel@0 9197 return (allowEmpty || !prop.def) ? null : prop.def;
Daniel@0 9198 }
Daniel@0 9199
Daniel@0 9200 // ~~ is an short way of doing floor for positive numbers
Daniel@0 9201 value = type.floor ? ~~value : parseFloat( value );
Daniel@0 9202
Daniel@0 9203 // IE will pass in empty strings as value for alpha,
Daniel@0 9204 // which will hit this case
Daniel@0 9205 if ( isNaN( value ) ) {
Daniel@0 9206 return prop.def;
Daniel@0 9207 }
Daniel@0 9208
Daniel@0 9209 if ( type.mod ) {
Daniel@0 9210 // we add mod before modding to make sure that negatives values
Daniel@0 9211 // get converted properly: -10 -> 350
Daniel@0 9212 return (value + type.mod) % type.mod;
Daniel@0 9213 }
Daniel@0 9214
Daniel@0 9215 // for now all property types without mod have min and max
Daniel@0 9216 return 0 > value ? 0 : type.max < value ? type.max : value;
Daniel@0 9217 }
Daniel@0 9218
Daniel@0 9219 function stringParse( string ) {
Daniel@0 9220 var inst = color(),
Daniel@0 9221 rgba = inst._rgba = [];
Daniel@0 9222
Daniel@0 9223 string = string.toLowerCase();
Daniel@0 9224
Daniel@0 9225 each( stringParsers, function( i, parser ) {
Daniel@0 9226 var parsed,
Daniel@0 9227 match = parser.re.exec( string ),
Daniel@0 9228 values = match && parser.parse( match ),
Daniel@0 9229 spaceName = parser.space || "rgba";
Daniel@0 9230
Daniel@0 9231 if ( values ) {
Daniel@0 9232 parsed = inst[ spaceName ]( values );
Daniel@0 9233
Daniel@0 9234 // if this was an rgba parse the assignment might happen twice
Daniel@0 9235 // oh well....
Daniel@0 9236 inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
Daniel@0 9237 rgba = inst._rgba = parsed._rgba;
Daniel@0 9238
Daniel@0 9239 // exit each( stringParsers ) here because we matched
Daniel@0 9240 return false;
Daniel@0 9241 }
Daniel@0 9242 });
Daniel@0 9243
Daniel@0 9244 // Found a stringParser that handled it
Daniel@0 9245 if ( rgba.length ) {
Daniel@0 9246
Daniel@0 9247 // if this came from a parsed string, force "transparent" when alpha is 0
Daniel@0 9248 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
Daniel@0 9249 if ( rgba.join() === "0,0,0,0" ) {
Daniel@0 9250 jQuery.extend( rgba, colors.transparent );
Daniel@0 9251 }
Daniel@0 9252 return inst;
Daniel@0 9253 }
Daniel@0 9254
Daniel@0 9255 // named colors
Daniel@0 9256 return colors[ string ];
Daniel@0 9257 }
Daniel@0 9258
Daniel@0 9259 color.fn = jQuery.extend( color.prototype, {
Daniel@0 9260 parse: function( red, green, blue, alpha ) {
Daniel@0 9261 if ( red === undefined ) {
Daniel@0 9262 this._rgba = [ null, null, null, null ];
Daniel@0 9263 return this;
Daniel@0 9264 }
Daniel@0 9265 if ( red.jquery || red.nodeType ) {
Daniel@0 9266 red = jQuery( red ).css( green );
Daniel@0 9267 green = undefined;
Daniel@0 9268 }
Daniel@0 9269
Daniel@0 9270 var inst = this,
Daniel@0 9271 type = jQuery.type( red ),
Daniel@0 9272 rgba = this._rgba = [];
Daniel@0 9273
Daniel@0 9274 // more than 1 argument specified - assume ( red, green, blue, alpha )
Daniel@0 9275 if ( green !== undefined ) {
Daniel@0 9276 red = [ red, green, blue, alpha ];
Daniel@0 9277 type = "array";
Daniel@0 9278 }
Daniel@0 9279
Daniel@0 9280 if ( type === "string" ) {
Daniel@0 9281 return this.parse( stringParse( red ) || colors._default );
Daniel@0 9282 }
Daniel@0 9283
Daniel@0 9284 if ( type === "array" ) {
Daniel@0 9285 each( spaces.rgba.props, function( key, prop ) {
Daniel@0 9286 rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
Daniel@0 9287 });
Daniel@0 9288 return this;
Daniel@0 9289 }
Daniel@0 9290
Daniel@0 9291 if ( type === "object" ) {
Daniel@0 9292 if ( red instanceof color ) {
Daniel@0 9293 each( spaces, function( spaceName, space ) {
Daniel@0 9294 if ( red[ space.cache ] ) {
Daniel@0 9295 inst[ space.cache ] = red[ space.cache ].slice();
Daniel@0 9296 }
Daniel@0 9297 });
Daniel@0 9298 } else {
Daniel@0 9299 each( spaces, function( spaceName, space ) {
Daniel@0 9300 var cache = space.cache;
Daniel@0 9301 each( space.props, function( key, prop ) {
Daniel@0 9302
Daniel@0 9303 // if the cache doesn't exist, and we know how to convert
Daniel@0 9304 if ( !inst[ cache ] && space.to ) {
Daniel@0 9305
Daniel@0 9306 // if the value was null, we don't need to copy it
Daniel@0 9307 // if the key was alpha, we don't need to copy it either
Daniel@0 9308 if ( key === "alpha" || red[ key ] == null ) {
Daniel@0 9309 return;
Daniel@0 9310 }
Daniel@0 9311 inst[ cache ] = space.to( inst._rgba );
Daniel@0 9312 }
Daniel@0 9313
Daniel@0 9314 // this is the only case where we allow nulls for ALL properties.
Daniel@0 9315 // call clamp with alwaysAllowEmpty
Daniel@0 9316 inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
Daniel@0 9317 });
Daniel@0 9318
Daniel@0 9319 // everything defined but alpha?
Daniel@0 9320 if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
Daniel@0 9321 // use the default of 1
Daniel@0 9322 inst[ cache ][ 3 ] = 1;
Daniel@0 9323 if ( space.from ) {
Daniel@0 9324 inst._rgba = space.from( inst[ cache ] );
Daniel@0 9325 }
Daniel@0 9326 }
Daniel@0 9327 });
Daniel@0 9328 }
Daniel@0 9329 return this;
Daniel@0 9330 }
Daniel@0 9331 },
Daniel@0 9332 is: function( compare ) {
Daniel@0 9333 var is = color( compare ),
Daniel@0 9334 same = true,
Daniel@0 9335 inst = this;
Daniel@0 9336
Daniel@0 9337 each( spaces, function( _, space ) {
Daniel@0 9338 var localCache,
Daniel@0 9339 isCache = is[ space.cache ];
Daniel@0 9340 if (isCache) {
Daniel@0 9341 localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
Daniel@0 9342 each( space.props, function( _, prop ) {
Daniel@0 9343 if ( isCache[ prop.idx ] != null ) {
Daniel@0 9344 same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
Daniel@0 9345 return same;
Daniel@0 9346 }
Daniel@0 9347 });
Daniel@0 9348 }
Daniel@0 9349 return same;
Daniel@0 9350 });
Daniel@0 9351 return same;
Daniel@0 9352 },
Daniel@0 9353 _space: function() {
Daniel@0 9354 var used = [],
Daniel@0 9355 inst = this;
Daniel@0 9356 each( spaces, function( spaceName, space ) {
Daniel@0 9357 if ( inst[ space.cache ] ) {
Daniel@0 9358 used.push( spaceName );
Daniel@0 9359 }
Daniel@0 9360 });
Daniel@0 9361 return used.pop();
Daniel@0 9362 },
Daniel@0 9363 transition: function( other, distance ) {
Daniel@0 9364 var end = color( other ),
Daniel@0 9365 spaceName = end._space(),
Daniel@0 9366 space = spaces[ spaceName ],
Daniel@0 9367 startColor = this.alpha() === 0 ? color( "transparent" ) : this,
Daniel@0 9368 start = startColor[ space.cache ] || space.to( startColor._rgba ),
Daniel@0 9369 result = start.slice();
Daniel@0 9370
Daniel@0 9371 end = end[ space.cache ];
Daniel@0 9372 each( space.props, function( key, prop ) {
Daniel@0 9373 var index = prop.idx,
Daniel@0 9374 startValue = start[ index ],
Daniel@0 9375 endValue = end[ index ],
Daniel@0 9376 type = propTypes[ prop.type ] || {};
Daniel@0 9377
Daniel@0 9378 // if null, don't override start value
Daniel@0 9379 if ( endValue === null ) {
Daniel@0 9380 return;
Daniel@0 9381 }
Daniel@0 9382 // if null - use end
Daniel@0 9383 if ( startValue === null ) {
Daniel@0 9384 result[ index ] = endValue;
Daniel@0 9385 } else {
Daniel@0 9386 if ( type.mod ) {
Daniel@0 9387 if ( endValue - startValue > type.mod / 2 ) {
Daniel@0 9388 startValue += type.mod;
Daniel@0 9389 } else if ( startValue - endValue > type.mod / 2 ) {
Daniel@0 9390 startValue -= type.mod;
Daniel@0 9391 }
Daniel@0 9392 }
Daniel@0 9393 result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
Daniel@0 9394 }
Daniel@0 9395 });
Daniel@0 9396 return this[ spaceName ]( result );
Daniel@0 9397 },
Daniel@0 9398 blend: function( opaque ) {
Daniel@0 9399 // if we are already opaque - return ourself
Daniel@0 9400 if ( this._rgba[ 3 ] === 1 ) {
Daniel@0 9401 return this;
Daniel@0 9402 }
Daniel@0 9403
Daniel@0 9404 var rgb = this._rgba.slice(),
Daniel@0 9405 a = rgb.pop(),
Daniel@0 9406 blend = color( opaque )._rgba;
Daniel@0 9407
Daniel@0 9408 return color( jQuery.map( rgb, function( v, i ) {
Daniel@0 9409 return ( 1 - a ) * blend[ i ] + a * v;
Daniel@0 9410 }));
Daniel@0 9411 },
Daniel@0 9412 toRgbaString: function() {
Daniel@0 9413 var prefix = "rgba(",
Daniel@0 9414 rgba = jQuery.map( this._rgba, function( v, i ) {
Daniel@0 9415 return v == null ? ( i > 2 ? 1 : 0 ) : v;
Daniel@0 9416 });
Daniel@0 9417
Daniel@0 9418 if ( rgba[ 3 ] === 1 ) {
Daniel@0 9419 rgba.pop();
Daniel@0 9420 prefix = "rgb(";
Daniel@0 9421 }
Daniel@0 9422
Daniel@0 9423 return prefix + rgba.join() + ")";
Daniel@0 9424 },
Daniel@0 9425 toHslaString: function() {
Daniel@0 9426 var prefix = "hsla(",
Daniel@0 9427 hsla = jQuery.map( this.hsla(), function( v, i ) {
Daniel@0 9428 if ( v == null ) {
Daniel@0 9429 v = i > 2 ? 1 : 0;
Daniel@0 9430 }
Daniel@0 9431
Daniel@0 9432 // catch 1 and 2
Daniel@0 9433 if ( i && i < 3 ) {
Daniel@0 9434 v = Math.round( v * 100 ) + "%";
Daniel@0 9435 }
Daniel@0 9436 return v;
Daniel@0 9437 });
Daniel@0 9438
Daniel@0 9439 if ( hsla[ 3 ] === 1 ) {
Daniel@0 9440 hsla.pop();
Daniel@0 9441 prefix = "hsl(";
Daniel@0 9442 }
Daniel@0 9443 return prefix + hsla.join() + ")";
Daniel@0 9444 },
Daniel@0 9445 toHexString: function( includeAlpha ) {
Daniel@0 9446 var rgba = this._rgba.slice(),
Daniel@0 9447 alpha = rgba.pop();
Daniel@0 9448
Daniel@0 9449 if ( includeAlpha ) {
Daniel@0 9450 rgba.push( ~~( alpha * 255 ) );
Daniel@0 9451 }
Daniel@0 9452
Daniel@0 9453 return "#" + jQuery.map( rgba, function( v ) {
Daniel@0 9454
Daniel@0 9455 // default to 0 when nulls exist
Daniel@0 9456 v = ( v || 0 ).toString( 16 );
Daniel@0 9457 return v.length === 1 ? "0" + v : v;
Daniel@0 9458 }).join("");
Daniel@0 9459 },
Daniel@0 9460 toString: function() {
Daniel@0 9461 return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
Daniel@0 9462 }
Daniel@0 9463 });
Daniel@0 9464 color.fn.parse.prototype = color.fn;
Daniel@0 9465
Daniel@0 9466 // hsla conversions adapted from:
Daniel@0 9467 // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
Daniel@0 9468
Daniel@0 9469 function hue2rgb( p, q, h ) {
Daniel@0 9470 h = ( h + 1 ) % 1;
Daniel@0 9471 if ( h * 6 < 1 ) {
Daniel@0 9472 return p + ( q - p ) * h * 6;
Daniel@0 9473 }
Daniel@0 9474 if ( h * 2 < 1) {
Daniel@0 9475 return q;
Daniel@0 9476 }
Daniel@0 9477 if ( h * 3 < 2 ) {
Daniel@0 9478 return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
Daniel@0 9479 }
Daniel@0 9480 return p;
Daniel@0 9481 }
Daniel@0 9482
Daniel@0 9483 spaces.hsla.to = function( rgba ) {
Daniel@0 9484 if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
Daniel@0 9485 return [ null, null, null, rgba[ 3 ] ];
Daniel@0 9486 }
Daniel@0 9487 var r = rgba[ 0 ] / 255,
Daniel@0 9488 g = rgba[ 1 ] / 255,
Daniel@0 9489 b = rgba[ 2 ] / 255,
Daniel@0 9490 a = rgba[ 3 ],
Daniel@0 9491 max = Math.max( r, g, b ),
Daniel@0 9492 min = Math.min( r, g, b ),
Daniel@0 9493 diff = max - min,
Daniel@0 9494 add = max + min,
Daniel@0 9495 l = add * 0.5,
Daniel@0 9496 h, s;
Daniel@0 9497
Daniel@0 9498 if ( min === max ) {
Daniel@0 9499 h = 0;
Daniel@0 9500 } else if ( r === max ) {
Daniel@0 9501 h = ( 60 * ( g - b ) / diff ) + 360;
Daniel@0 9502 } else if ( g === max ) {
Daniel@0 9503 h = ( 60 * ( b - r ) / diff ) + 120;
Daniel@0 9504 } else {
Daniel@0 9505 h = ( 60 * ( r - g ) / diff ) + 240;
Daniel@0 9506 }
Daniel@0 9507
Daniel@0 9508 // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
Daniel@0 9509 // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
Daniel@0 9510 if ( diff === 0 ) {
Daniel@0 9511 s = 0;
Daniel@0 9512 } else if ( l <= 0.5 ) {
Daniel@0 9513 s = diff / add;
Daniel@0 9514 } else {
Daniel@0 9515 s = diff / ( 2 - add );
Daniel@0 9516 }
Daniel@0 9517 return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
Daniel@0 9518 };
Daniel@0 9519
Daniel@0 9520 spaces.hsla.from = function( hsla ) {
Daniel@0 9521 if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
Daniel@0 9522 return [ null, null, null, hsla[ 3 ] ];
Daniel@0 9523 }
Daniel@0 9524 var h = hsla[ 0 ] / 360,
Daniel@0 9525 s = hsla[ 1 ],
Daniel@0 9526 l = hsla[ 2 ],
Daniel@0 9527 a = hsla[ 3 ],
Daniel@0 9528 q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
Daniel@0 9529 p = 2 * l - q;
Daniel@0 9530
Daniel@0 9531 return [
Daniel@0 9532 Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
Daniel@0 9533 Math.round( hue2rgb( p, q, h ) * 255 ),
Daniel@0 9534 Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
Daniel@0 9535 a
Daniel@0 9536 ];
Daniel@0 9537 };
Daniel@0 9538
Daniel@0 9539 each( spaces, function( spaceName, space ) {
Daniel@0 9540 var props = space.props,
Daniel@0 9541 cache = space.cache,
Daniel@0 9542 to = space.to,
Daniel@0 9543 from = space.from;
Daniel@0 9544
Daniel@0 9545 // makes rgba() and hsla()
Daniel@0 9546 color.fn[ spaceName ] = function( value ) {
Daniel@0 9547
Daniel@0 9548 // generate a cache for this space if it doesn't exist
Daniel@0 9549 if ( to && !this[ cache ] ) {
Daniel@0 9550 this[ cache ] = to( this._rgba );
Daniel@0 9551 }
Daniel@0 9552 if ( value === undefined ) {
Daniel@0 9553 return this[ cache ].slice();
Daniel@0 9554 }
Daniel@0 9555
Daniel@0 9556 var ret,
Daniel@0 9557 type = jQuery.type( value ),
Daniel@0 9558 arr = ( type === "array" || type === "object" ) ? value : arguments,
Daniel@0 9559 local = this[ cache ].slice();
Daniel@0 9560
Daniel@0 9561 each( props, function( key, prop ) {
Daniel@0 9562 var val = arr[ type === "object" ? key : prop.idx ];
Daniel@0 9563 if ( val == null ) {
Daniel@0 9564 val = local[ prop.idx ];
Daniel@0 9565 }
Daniel@0 9566 local[ prop.idx ] = clamp( val, prop );
Daniel@0 9567 });
Daniel@0 9568
Daniel@0 9569 if ( from ) {
Daniel@0 9570 ret = color( from( local ) );
Daniel@0 9571 ret[ cache ] = local;
Daniel@0 9572 return ret;
Daniel@0 9573 } else {
Daniel@0 9574 return color( local );
Daniel@0 9575 }
Daniel@0 9576 };
Daniel@0 9577
Daniel@0 9578 // makes red() green() blue() alpha() hue() saturation() lightness()
Daniel@0 9579 each( props, function( key, prop ) {
Daniel@0 9580 // alpha is included in more than one space
Daniel@0 9581 if ( color.fn[ key ] ) {
Daniel@0 9582 return;
Daniel@0 9583 }
Daniel@0 9584 color.fn[ key ] = function( value ) {
Daniel@0 9585 var vtype = jQuery.type( value ),
Daniel@0 9586 fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
Daniel@0 9587 local = this[ fn ](),
Daniel@0 9588 cur = local[ prop.idx ],
Daniel@0 9589 match;
Daniel@0 9590
Daniel@0 9591 if ( vtype === "undefined" ) {
Daniel@0 9592 return cur;
Daniel@0 9593 }
Daniel@0 9594
Daniel@0 9595 if ( vtype === "function" ) {
Daniel@0 9596 value = value.call( this, cur );
Daniel@0 9597 vtype = jQuery.type( value );
Daniel@0 9598 }
Daniel@0 9599 if ( value == null && prop.empty ) {
Daniel@0 9600 return this;
Daniel@0 9601 }
Daniel@0 9602 if ( vtype === "string" ) {
Daniel@0 9603 match = rplusequals.exec( value );
Daniel@0 9604 if ( match ) {
Daniel@0 9605 value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
Daniel@0 9606 }
Daniel@0 9607 }
Daniel@0 9608 local[ prop.idx ] = value;
Daniel@0 9609 return this[ fn ]( local );
Daniel@0 9610 };
Daniel@0 9611 });
Daniel@0 9612 });
Daniel@0 9613
Daniel@0 9614 // add cssHook and .fx.step function for each named hook.
Daniel@0 9615 // accept a space separated string of properties
Daniel@0 9616 color.hook = function( hook ) {
Daniel@0 9617 var hooks = hook.split( " " );
Daniel@0 9618 each( hooks, function( i, hook ) {
Daniel@0 9619 jQuery.cssHooks[ hook ] = {
Daniel@0 9620 set: function( elem, value ) {
Daniel@0 9621 var parsed, curElem,
Daniel@0 9622 backgroundColor = "";
Daniel@0 9623
Daniel@0 9624 if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
Daniel@0 9625 value = color( parsed || value );
Daniel@0 9626 if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
Daniel@0 9627 curElem = hook === "backgroundColor" ? elem.parentNode : elem;
Daniel@0 9628 while (
Daniel@0 9629 (backgroundColor === "" || backgroundColor === "transparent") &&
Daniel@0 9630 curElem && curElem.style
Daniel@0 9631 ) {
Daniel@0 9632 try {
Daniel@0 9633 backgroundColor = jQuery.css( curElem, "backgroundColor" );
Daniel@0 9634 curElem = curElem.parentNode;
Daniel@0 9635 } catch ( e ) {
Daniel@0 9636 }
Daniel@0 9637 }
Daniel@0 9638
Daniel@0 9639 value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
Daniel@0 9640 backgroundColor :
Daniel@0 9641 "_default" );
Daniel@0 9642 }
Daniel@0 9643
Daniel@0 9644 value = value.toRgbaString();
Daniel@0 9645 }
Daniel@0 9646 try {
Daniel@0 9647 elem.style[ hook ] = value;
Daniel@0 9648 } catch( e ) {
Daniel@0 9649 // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
Daniel@0 9650 }
Daniel@0 9651 }
Daniel@0 9652 };
Daniel@0 9653 jQuery.fx.step[ hook ] = function( fx ) {
Daniel@0 9654 if ( !fx.colorInit ) {
Daniel@0 9655 fx.start = color( fx.elem, hook );
Daniel@0 9656 fx.end = color( fx.end );
Daniel@0 9657 fx.colorInit = true;
Daniel@0 9658 }
Daniel@0 9659 jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
Daniel@0 9660 };
Daniel@0 9661 });
Daniel@0 9662
Daniel@0 9663 };
Daniel@0 9664
Daniel@0 9665 color.hook( stepHooks );
Daniel@0 9666
Daniel@0 9667 jQuery.cssHooks.borderColor = {
Daniel@0 9668 expand: function( value ) {
Daniel@0 9669 var expanded = {};
Daniel@0 9670
Daniel@0 9671 each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
Daniel@0 9672 expanded[ "border" + part + "Color" ] = value;
Daniel@0 9673 });
Daniel@0 9674 return expanded;
Daniel@0 9675 }
Daniel@0 9676 };
Daniel@0 9677
Daniel@0 9678 // Basic color names only.
Daniel@0 9679 // Usage of any of the other color names requires adding yourself or including
Daniel@0 9680 // jquery.color.svg-names.js.
Daniel@0 9681 colors = jQuery.Color.names = {
Daniel@0 9682 // 4.1. Basic color keywords
Daniel@0 9683 aqua: "#00ffff",
Daniel@0 9684 black: "#000000",
Daniel@0 9685 blue: "#0000ff",
Daniel@0 9686 fuchsia: "#ff00ff",
Daniel@0 9687 gray: "#808080",
Daniel@0 9688 green: "#008000",
Daniel@0 9689 lime: "#00ff00",
Daniel@0 9690 maroon: "#800000",
Daniel@0 9691 navy: "#000080",
Daniel@0 9692 olive: "#808000",
Daniel@0 9693 purple: "#800080",
Daniel@0 9694 red: "#ff0000",
Daniel@0 9695 silver: "#c0c0c0",
Daniel@0 9696 teal: "#008080",
Daniel@0 9697 white: "#ffffff",
Daniel@0 9698 yellow: "#ffff00",
Daniel@0 9699
Daniel@0 9700 // 4.2.3. "transparent" color keyword
Daniel@0 9701 transparent: [ null, null, null, 0 ],
Daniel@0 9702
Daniel@0 9703 _default: "#ffffff"
Daniel@0 9704 };
Daniel@0 9705
Daniel@0 9706 })( jQuery );
Daniel@0 9707
Daniel@0 9708 /******************************************************************************/
Daniel@0 9709 /****************************** CLASS ANIMATIONS ******************************/
Daniel@0 9710 /******************************************************************************/
Daniel@0 9711 (function() {
Daniel@0 9712
Daniel@0 9713 var classAnimationActions = [ "add", "remove", "toggle" ],
Daniel@0 9714 shorthandStyles = {
Daniel@0 9715 border: 1,
Daniel@0 9716 borderBottom: 1,
Daniel@0 9717 borderColor: 1,
Daniel@0 9718 borderLeft: 1,
Daniel@0 9719 borderRight: 1,
Daniel@0 9720 borderTop: 1,
Daniel@0 9721 borderWidth: 1,
Daniel@0 9722 margin: 1,
Daniel@0 9723 padding: 1
Daniel@0 9724 };
Daniel@0 9725
Daniel@0 9726 $.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
Daniel@0 9727 $.fx.step[ prop ] = function( fx ) {
Daniel@0 9728 if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
Daniel@0 9729 jQuery.style( fx.elem, prop, fx.end );
Daniel@0 9730 fx.setAttr = true;
Daniel@0 9731 }
Daniel@0 9732 };
Daniel@0 9733 });
Daniel@0 9734
Daniel@0 9735 function getElementStyles( elem ) {
Daniel@0 9736 var key, len,
Daniel@0 9737 style = elem.ownerDocument.defaultView ?
Daniel@0 9738 elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
Daniel@0 9739 elem.currentStyle,
Daniel@0 9740 styles = {};
Daniel@0 9741
Daniel@0 9742 if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
Daniel@0 9743 len = style.length;
Daniel@0 9744 while ( len-- ) {
Daniel@0 9745 key = style[ len ];
Daniel@0 9746 if ( typeof style[ key ] === "string" ) {
Daniel@0 9747 styles[ $.camelCase( key ) ] = style[ key ];
Daniel@0 9748 }
Daniel@0 9749 }
Daniel@0 9750 // support: Opera, IE <9
Daniel@0 9751 } else {
Daniel@0 9752 for ( key in style ) {
Daniel@0 9753 if ( typeof style[ key ] === "string" ) {
Daniel@0 9754 styles[ key ] = style[ key ];
Daniel@0 9755 }
Daniel@0 9756 }
Daniel@0 9757 }
Daniel@0 9758
Daniel@0 9759 return styles;
Daniel@0 9760 }
Daniel@0 9761
Daniel@0 9762 function styleDifference( oldStyle, newStyle ) {
Daniel@0 9763 var diff = {},
Daniel@0 9764 name, value;
Daniel@0 9765
Daniel@0 9766 for ( name in newStyle ) {
Daniel@0 9767 value = newStyle[ name ];
Daniel@0 9768 if ( oldStyle[ name ] !== value ) {
Daniel@0 9769 if ( !shorthandStyles[ name ] ) {
Daniel@0 9770 if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
Daniel@0 9771 diff[ name ] = value;
Daniel@0 9772 }
Daniel@0 9773 }
Daniel@0 9774 }
Daniel@0 9775 }
Daniel@0 9776
Daniel@0 9777 return diff;
Daniel@0 9778 }
Daniel@0 9779
Daniel@0 9780 // support: jQuery <1.8
Daniel@0 9781 if ( !$.fn.addBack ) {
Daniel@0 9782 $.fn.addBack = function( selector ) {
Daniel@0 9783 return this.add( selector == null ?
Daniel@0 9784 this.prevObject : this.prevObject.filter( selector )
Daniel@0 9785 );
Daniel@0 9786 };
Daniel@0 9787 }
Daniel@0 9788
Daniel@0 9789 $.effects.animateClass = function( value, duration, easing, callback ) {
Daniel@0 9790 var o = $.speed( duration, easing, callback );
Daniel@0 9791
Daniel@0 9792 return this.queue( function() {
Daniel@0 9793 var animated = $( this ),
Daniel@0 9794 baseClass = animated.attr( "class" ) || "",
Daniel@0 9795 applyClassChange,
Daniel@0 9796 allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
Daniel@0 9797
Daniel@0 9798 // map the animated objects to store the original styles.
Daniel@0 9799 allAnimations = allAnimations.map(function() {
Daniel@0 9800 var el = $( this );
Daniel@0 9801 return {
Daniel@0 9802 el: el,
Daniel@0 9803 start: getElementStyles( this )
Daniel@0 9804 };
Daniel@0 9805 });
Daniel@0 9806
Daniel@0 9807 // apply class change
Daniel@0 9808 applyClassChange = function() {
Daniel@0 9809 $.each( classAnimationActions, function(i, action) {
Daniel@0 9810 if ( value[ action ] ) {
Daniel@0 9811 animated[ action + "Class" ]( value[ action ] );
Daniel@0 9812 }
Daniel@0 9813 });
Daniel@0 9814 };
Daniel@0 9815 applyClassChange();
Daniel@0 9816
Daniel@0 9817 // map all animated objects again - calculate new styles and diff
Daniel@0 9818 allAnimations = allAnimations.map(function() {
Daniel@0 9819 this.end = getElementStyles( this.el[ 0 ] );
Daniel@0 9820 this.diff = styleDifference( this.start, this.end );
Daniel@0 9821 return this;
Daniel@0 9822 });
Daniel@0 9823
Daniel@0 9824 // apply original class
Daniel@0 9825 animated.attr( "class", baseClass );
Daniel@0 9826
Daniel@0 9827 // map all animated objects again - this time collecting a promise
Daniel@0 9828 allAnimations = allAnimations.map(function() {
Daniel@0 9829 var styleInfo = this,
Daniel@0 9830 dfd = $.Deferred(),
Daniel@0 9831 opts = $.extend({}, o, {
Daniel@0 9832 queue: false,
Daniel@0 9833 complete: function() {
Daniel@0 9834 dfd.resolve( styleInfo );
Daniel@0 9835 }
Daniel@0 9836 });
Daniel@0 9837
Daniel@0 9838 this.el.animate( this.diff, opts );
Daniel@0 9839 return dfd.promise();
Daniel@0 9840 });
Daniel@0 9841
Daniel@0 9842 // once all animations have completed:
Daniel@0 9843 $.when.apply( $, allAnimations.get() ).done(function() {
Daniel@0 9844
Daniel@0 9845 // set the final class
Daniel@0 9846 applyClassChange();
Daniel@0 9847
Daniel@0 9848 // for each animated element,
Daniel@0 9849 // clear all css properties that were animated
Daniel@0 9850 $.each( arguments, function() {
Daniel@0 9851 var el = this.el;
Daniel@0 9852 $.each( this.diff, function(key) {
Daniel@0 9853 el.css( key, "" );
Daniel@0 9854 });
Daniel@0 9855 });
Daniel@0 9856
Daniel@0 9857 // this is guarnteed to be there if you use jQuery.speed()
Daniel@0 9858 // it also handles dequeuing the next anim...
Daniel@0 9859 o.complete.call( animated[ 0 ] );
Daniel@0 9860 });
Daniel@0 9861 });
Daniel@0 9862 };
Daniel@0 9863
Daniel@0 9864 $.fn.extend({
Daniel@0 9865 addClass: (function( orig ) {
Daniel@0 9866 return function( classNames, speed, easing, callback ) {
Daniel@0 9867 return speed ?
Daniel@0 9868 $.effects.animateClass.call( this,
Daniel@0 9869 { add: classNames }, speed, easing, callback ) :
Daniel@0 9870 orig.apply( this, arguments );
Daniel@0 9871 };
Daniel@0 9872 })( $.fn.addClass ),
Daniel@0 9873
Daniel@0 9874 removeClass: (function( orig ) {
Daniel@0 9875 return function( classNames, speed, easing, callback ) {
Daniel@0 9876 return arguments.length > 1 ?
Daniel@0 9877 $.effects.animateClass.call( this,
Daniel@0 9878 { remove: classNames }, speed, easing, callback ) :
Daniel@0 9879 orig.apply( this, arguments );
Daniel@0 9880 };
Daniel@0 9881 })( $.fn.removeClass ),
Daniel@0 9882
Daniel@0 9883 toggleClass: (function( orig ) {
Daniel@0 9884 return function( classNames, force, speed, easing, callback ) {
Daniel@0 9885 if ( typeof force === "boolean" || force === undefined ) {
Daniel@0 9886 if ( !speed ) {
Daniel@0 9887 // without speed parameter
Daniel@0 9888 return orig.apply( this, arguments );
Daniel@0 9889 } else {
Daniel@0 9890 return $.effects.animateClass.call( this,
Daniel@0 9891 (force ? { add: classNames } : { remove: classNames }),
Daniel@0 9892 speed, easing, callback );
Daniel@0 9893 }
Daniel@0 9894 } else {
Daniel@0 9895 // without force parameter
Daniel@0 9896 return $.effects.animateClass.call( this,
Daniel@0 9897 { toggle: classNames }, force, speed, easing );
Daniel@0 9898 }
Daniel@0 9899 };
Daniel@0 9900 })( $.fn.toggleClass ),
Daniel@0 9901
Daniel@0 9902 switchClass: function( remove, add, speed, easing, callback) {
Daniel@0 9903 return $.effects.animateClass.call( this, {
Daniel@0 9904 add: add,
Daniel@0 9905 remove: remove
Daniel@0 9906 }, speed, easing, callback );
Daniel@0 9907 }
Daniel@0 9908 });
Daniel@0 9909
Daniel@0 9910 })();
Daniel@0 9911
Daniel@0 9912 /******************************************************************************/
Daniel@0 9913 /*********************************** EFFECTS **********************************/
Daniel@0 9914 /******************************************************************************/
Daniel@0 9915
Daniel@0 9916 (function() {
Daniel@0 9917
Daniel@0 9918 $.extend( $.effects, {
Daniel@0 9919 version: "1.11.0",
Daniel@0 9920
Daniel@0 9921 // Saves a set of properties in a data storage
Daniel@0 9922 save: function( element, set ) {
Daniel@0 9923 for ( var i = 0; i < set.length; i++ ) {
Daniel@0 9924 if ( set[ i ] !== null ) {
Daniel@0 9925 element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
Daniel@0 9926 }
Daniel@0 9927 }
Daniel@0 9928 },
Daniel@0 9929
Daniel@0 9930 // Restores a set of previously saved properties from a data storage
Daniel@0 9931 restore: function( element, set ) {
Daniel@0 9932 var val, i;
Daniel@0 9933 for ( i = 0; i < set.length; i++ ) {
Daniel@0 9934 if ( set[ i ] !== null ) {
Daniel@0 9935 val = element.data( dataSpace + set[ i ] );
Daniel@0 9936 // support: jQuery 1.6.2
Daniel@0 9937 // http://bugs.jquery.com/ticket/9917
Daniel@0 9938 // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
Daniel@0 9939 // We can't differentiate between "" and 0 here, so we just assume
Daniel@0 9940 // empty string since it's likely to be a more common value...
Daniel@0 9941 if ( val === undefined ) {
Daniel@0 9942 val = "";
Daniel@0 9943 }
Daniel@0 9944 element.css( set[ i ], val );
Daniel@0 9945 }
Daniel@0 9946 }
Daniel@0 9947 },
Daniel@0 9948
Daniel@0 9949 setMode: function( el, mode ) {
Daniel@0 9950 if (mode === "toggle") {
Daniel@0 9951 mode = el.is( ":hidden" ) ? "show" : "hide";
Daniel@0 9952 }
Daniel@0 9953 return mode;
Daniel@0 9954 },
Daniel@0 9955
Daniel@0 9956 // Translates a [top,left] array into a baseline value
Daniel@0 9957 // this should be a little more flexible in the future to handle a string & hash
Daniel@0 9958 getBaseline: function( origin, original ) {
Daniel@0 9959 var y, x;
Daniel@0 9960 switch ( origin[ 0 ] ) {
Daniel@0 9961 case "top": y = 0; break;
Daniel@0 9962 case "middle": y = 0.5; break;
Daniel@0 9963 case "bottom": y = 1; break;
Daniel@0 9964 default: y = origin[ 0 ] / original.height;
Daniel@0 9965 }
Daniel@0 9966 switch ( origin[ 1 ] ) {
Daniel@0 9967 case "left": x = 0; break;
Daniel@0 9968 case "center": x = 0.5; break;
Daniel@0 9969 case "right": x = 1; break;
Daniel@0 9970 default: x = origin[ 1 ] / original.width;
Daniel@0 9971 }
Daniel@0 9972 return {
Daniel@0 9973 x: x,
Daniel@0 9974 y: y
Daniel@0 9975 };
Daniel@0 9976 },
Daniel@0 9977
Daniel@0 9978 // Wraps the element around a wrapper that copies position properties
Daniel@0 9979 createWrapper: function( element ) {
Daniel@0 9980
Daniel@0 9981 // if the element is already wrapped, return it
Daniel@0 9982 if ( element.parent().is( ".ui-effects-wrapper" )) {
Daniel@0 9983 return element.parent();
Daniel@0 9984 }
Daniel@0 9985
Daniel@0 9986 // wrap the element
Daniel@0 9987 var props = {
Daniel@0 9988 width: element.outerWidth(true),
Daniel@0 9989 height: element.outerHeight(true),
Daniel@0 9990 "float": element.css( "float" )
Daniel@0 9991 },
Daniel@0 9992 wrapper = $( "<div></div>" )
Daniel@0 9993 .addClass( "ui-effects-wrapper" )
Daniel@0 9994 .css({
Daniel@0 9995 fontSize: "100%",
Daniel@0 9996 background: "transparent",
Daniel@0 9997 border: "none",
Daniel@0 9998 margin: 0,
Daniel@0 9999 padding: 0
Daniel@0 10000 }),
Daniel@0 10001 // Store the size in case width/height are defined in % - Fixes #5245
Daniel@0 10002 size = {
Daniel@0 10003 width: element.width(),
Daniel@0 10004 height: element.height()
Daniel@0 10005 },
Daniel@0 10006 active = document.activeElement;
Daniel@0 10007
Daniel@0 10008 // support: Firefox
Daniel@0 10009 // Firefox incorrectly exposes anonymous content
Daniel@0 10010 // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
Daniel@0 10011 try {
Daniel@0 10012 active.id;
Daniel@0 10013 } catch( e ) {
Daniel@0 10014 active = document.body;
Daniel@0 10015 }
Daniel@0 10016
Daniel@0 10017 element.wrap( wrapper );
Daniel@0 10018
Daniel@0 10019 // Fixes #7595 - Elements lose focus when wrapped.
Daniel@0 10020 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
Daniel@0 10021 $( active ).focus();
Daniel@0 10022 }
Daniel@0 10023
Daniel@0 10024 wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
Daniel@0 10025
Daniel@0 10026 // transfer positioning properties to the wrapper
Daniel@0 10027 if ( element.css( "position" ) === "static" ) {
Daniel@0 10028 wrapper.css({ position: "relative" });
Daniel@0 10029 element.css({ position: "relative" });
Daniel@0 10030 } else {
Daniel@0 10031 $.extend( props, {
Daniel@0 10032 position: element.css( "position" ),
Daniel@0 10033 zIndex: element.css( "z-index" )
Daniel@0 10034 });
Daniel@0 10035 $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
Daniel@0 10036 props[ pos ] = element.css( pos );
Daniel@0 10037 if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
Daniel@0 10038 props[ pos ] = "auto";
Daniel@0 10039 }
Daniel@0 10040 });
Daniel@0 10041 element.css({
Daniel@0 10042 position: "relative",
Daniel@0 10043 top: 0,
Daniel@0 10044 left: 0,
Daniel@0 10045 right: "auto",
Daniel@0 10046 bottom: "auto"
Daniel@0 10047 });
Daniel@0 10048 }
Daniel@0 10049 element.css(size);
Daniel@0 10050
Daniel@0 10051 return wrapper.css( props ).show();
Daniel@0 10052 },
Daniel@0 10053
Daniel@0 10054 removeWrapper: function( element ) {
Daniel@0 10055 var active = document.activeElement;
Daniel@0 10056
Daniel@0 10057 if ( element.parent().is( ".ui-effects-wrapper" ) ) {
Daniel@0 10058 element.parent().replaceWith( element );
Daniel@0 10059
Daniel@0 10060 // Fixes #7595 - Elements lose focus when wrapped.
Daniel@0 10061 if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
Daniel@0 10062 $( active ).focus();
Daniel@0 10063 }
Daniel@0 10064 }
Daniel@0 10065
Daniel@0 10066 return element;
Daniel@0 10067 },
Daniel@0 10068
Daniel@0 10069 setTransition: function( element, list, factor, value ) {
Daniel@0 10070 value = value || {};
Daniel@0 10071 $.each( list, function( i, x ) {
Daniel@0 10072 var unit = element.cssUnit( x );
Daniel@0 10073 if ( unit[ 0 ] > 0 ) {
Daniel@0 10074 value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
Daniel@0 10075 }
Daniel@0 10076 });
Daniel@0 10077 return value;
Daniel@0 10078 }
Daniel@0 10079 });
Daniel@0 10080
Daniel@0 10081 // return an effect options object for the given parameters:
Daniel@0 10082 function _normalizeArguments( effect, options, speed, callback ) {
Daniel@0 10083
Daniel@0 10084 // allow passing all options as the first parameter
Daniel@0 10085 if ( $.isPlainObject( effect ) ) {
Daniel@0 10086 options = effect;
Daniel@0 10087 effect = effect.effect;
Daniel@0 10088 }
Daniel@0 10089
Daniel@0 10090 // convert to an object
Daniel@0 10091 effect = { effect: effect };
Daniel@0 10092
Daniel@0 10093 // catch (effect, null, ...)
Daniel@0 10094 if ( options == null ) {
Daniel@0 10095 options = {};
Daniel@0 10096 }
Daniel@0 10097
Daniel@0 10098 // catch (effect, callback)
Daniel@0 10099 if ( $.isFunction( options ) ) {
Daniel@0 10100 callback = options;
Daniel@0 10101 speed = null;
Daniel@0 10102 options = {};
Daniel@0 10103 }
Daniel@0 10104
Daniel@0 10105 // catch (effect, speed, ?)
Daniel@0 10106 if ( typeof options === "number" || $.fx.speeds[ options ] ) {
Daniel@0 10107 callback = speed;
Daniel@0 10108 speed = options;
Daniel@0 10109 options = {};
Daniel@0 10110 }
Daniel@0 10111
Daniel@0 10112 // catch (effect, options, callback)
Daniel@0 10113 if ( $.isFunction( speed ) ) {
Daniel@0 10114 callback = speed;
Daniel@0 10115 speed = null;
Daniel@0 10116 }
Daniel@0 10117
Daniel@0 10118 // add options to effect
Daniel@0 10119 if ( options ) {
Daniel@0 10120 $.extend( effect, options );
Daniel@0 10121 }
Daniel@0 10122
Daniel@0 10123 speed = speed || options.duration;
Daniel@0 10124 effect.duration = $.fx.off ? 0 :
Daniel@0 10125 typeof speed === "number" ? speed :
Daniel@0 10126 speed in $.fx.speeds ? $.fx.speeds[ speed ] :
Daniel@0 10127 $.fx.speeds._default;
Daniel@0 10128
Daniel@0 10129 effect.complete = callback || options.complete;
Daniel@0 10130
Daniel@0 10131 return effect;
Daniel@0 10132 }
Daniel@0 10133
Daniel@0 10134 function standardAnimationOption( option ) {
Daniel@0 10135 // Valid standard speeds (nothing, number, named speed)
Daniel@0 10136 if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
Daniel@0 10137 return true;
Daniel@0 10138 }
Daniel@0 10139
Daniel@0 10140 // Invalid strings - treat as "normal" speed
Daniel@0 10141 if ( typeof option === "string" && !$.effects.effect[ option ] ) {
Daniel@0 10142 return true;
Daniel@0 10143 }
Daniel@0 10144
Daniel@0 10145 // Complete callback
Daniel@0 10146 if ( $.isFunction( option ) ) {
Daniel@0 10147 return true;
Daniel@0 10148 }
Daniel@0 10149
Daniel@0 10150 // Options hash (but not naming an effect)
Daniel@0 10151 if ( typeof option === "object" && !option.effect ) {
Daniel@0 10152 return true;
Daniel@0 10153 }
Daniel@0 10154
Daniel@0 10155 // Didn't match any standard API
Daniel@0 10156 return false;
Daniel@0 10157 }
Daniel@0 10158
Daniel@0 10159 $.fn.extend({
Daniel@0 10160 effect: function( /* effect, options, speed, callback */ ) {
Daniel@0 10161 var args = _normalizeArguments.apply( this, arguments ),
Daniel@0 10162 mode = args.mode,
Daniel@0 10163 queue = args.queue,
Daniel@0 10164 effectMethod = $.effects.effect[ args.effect ];
Daniel@0 10165
Daniel@0 10166 if ( $.fx.off || !effectMethod ) {
Daniel@0 10167 // delegate to the original method (e.g., .show()) if possible
Daniel@0 10168 if ( mode ) {
Daniel@0 10169 return this[ mode ]( args.duration, args.complete );
Daniel@0 10170 } else {
Daniel@0 10171 return this.each( function() {
Daniel@0 10172 if ( args.complete ) {
Daniel@0 10173 args.complete.call( this );
Daniel@0 10174 }
Daniel@0 10175 });
Daniel@0 10176 }
Daniel@0 10177 }
Daniel@0 10178
Daniel@0 10179 function run( next ) {
Daniel@0 10180 var elem = $( this ),
Daniel@0 10181 complete = args.complete,
Daniel@0 10182 mode = args.mode;
Daniel@0 10183
Daniel@0 10184 function done() {
Daniel@0 10185 if ( $.isFunction( complete ) ) {
Daniel@0 10186 complete.call( elem[0] );
Daniel@0 10187 }
Daniel@0 10188 if ( $.isFunction( next ) ) {
Daniel@0 10189 next();
Daniel@0 10190 }
Daniel@0 10191 }
Daniel@0 10192
Daniel@0 10193 // If the element already has the correct final state, delegate to
Daniel@0 10194 // the core methods so the internal tracking of "olddisplay" works.
Daniel@0 10195 if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
Daniel@0 10196 elem[ mode ]();
Daniel@0 10197 done();
Daniel@0 10198 } else {
Daniel@0 10199 effectMethod.call( elem[0], args, done );
Daniel@0 10200 }
Daniel@0 10201 }
Daniel@0 10202
Daniel@0 10203 return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
Daniel@0 10204 },
Daniel@0 10205
Daniel@0 10206 show: (function( orig ) {
Daniel@0 10207 return function( option ) {
Daniel@0 10208 if ( standardAnimationOption( option ) ) {
Daniel@0 10209 return orig.apply( this, arguments );
Daniel@0 10210 } else {
Daniel@0 10211 var args = _normalizeArguments.apply( this, arguments );
Daniel@0 10212 args.mode = "show";
Daniel@0 10213 return this.effect.call( this, args );
Daniel@0 10214 }
Daniel@0 10215 };
Daniel@0 10216 })( $.fn.show ),
Daniel@0 10217
Daniel@0 10218 hide: (function( orig ) {
Daniel@0 10219 return function( option ) {
Daniel@0 10220 if ( standardAnimationOption( option ) ) {
Daniel@0 10221 return orig.apply( this, arguments );
Daniel@0 10222 } else {
Daniel@0 10223 var args = _normalizeArguments.apply( this, arguments );
Daniel@0 10224 args.mode = "hide";
Daniel@0 10225 return this.effect.call( this, args );
Daniel@0 10226 }
Daniel@0 10227 };
Daniel@0 10228 })( $.fn.hide ),
Daniel@0 10229
Daniel@0 10230 toggle: (function( orig ) {
Daniel@0 10231 return function( option ) {
Daniel@0 10232 if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
Daniel@0 10233 return orig.apply( this, arguments );
Daniel@0 10234 } else {
Daniel@0 10235 var args = _normalizeArguments.apply( this, arguments );
Daniel@0 10236 args.mode = "toggle";
Daniel@0 10237 return this.effect.call( this, args );
Daniel@0 10238 }
Daniel@0 10239 };
Daniel@0 10240 })( $.fn.toggle ),
Daniel@0 10241
Daniel@0 10242 // helper functions
Daniel@0 10243 cssUnit: function(key) {
Daniel@0 10244 var style = this.css( key ),
Daniel@0 10245 val = [];
Daniel@0 10246
Daniel@0 10247 $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
Daniel@0 10248 if ( style.indexOf( unit ) > 0 ) {
Daniel@0 10249 val = [ parseFloat( style ), unit ];
Daniel@0 10250 }
Daniel@0 10251 });
Daniel@0 10252 return val;
Daniel@0 10253 }
Daniel@0 10254 });
Daniel@0 10255
Daniel@0 10256 })();
Daniel@0 10257
Daniel@0 10258 /******************************************************************************/
Daniel@0 10259 /*********************************** EASING ***********************************/
Daniel@0 10260 /******************************************************************************/
Daniel@0 10261
Daniel@0 10262 (function() {
Daniel@0 10263
Daniel@0 10264 // based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
Daniel@0 10265
Daniel@0 10266 var baseEasings = {};
Daniel@0 10267
Daniel@0 10268 $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
Daniel@0 10269 baseEasings[ name ] = function( p ) {
Daniel@0 10270 return Math.pow( p, i + 2 );
Daniel@0 10271 };
Daniel@0 10272 });
Daniel@0 10273
Daniel@0 10274 $.extend( baseEasings, {
Daniel@0 10275 Sine: function( p ) {
Daniel@0 10276 return 1 - Math.cos( p * Math.PI / 2 );
Daniel@0 10277 },
Daniel@0 10278 Circ: function( p ) {
Daniel@0 10279 return 1 - Math.sqrt( 1 - p * p );
Daniel@0 10280 },
Daniel@0 10281 Elastic: function( p ) {
Daniel@0 10282 return p === 0 || p === 1 ? p :
Daniel@0 10283 -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
Daniel@0 10284 },
Daniel@0 10285 Back: function( p ) {
Daniel@0 10286 return p * p * ( 3 * p - 2 );
Daniel@0 10287 },
Daniel@0 10288 Bounce: function( p ) {
Daniel@0 10289 var pow2,
Daniel@0 10290 bounce = 4;
Daniel@0 10291
Daniel@0 10292 while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
Daniel@0 10293 return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
Daniel@0 10294 }
Daniel@0 10295 });
Daniel@0 10296
Daniel@0 10297 $.each( baseEasings, function( name, easeIn ) {
Daniel@0 10298 $.easing[ "easeIn" + name ] = easeIn;
Daniel@0 10299 $.easing[ "easeOut" + name ] = function( p ) {
Daniel@0 10300 return 1 - easeIn( 1 - p );
Daniel@0 10301 };
Daniel@0 10302 $.easing[ "easeInOut" + name ] = function( p ) {
Daniel@0 10303 return p < 0.5 ?
Daniel@0 10304 easeIn( p * 2 ) / 2 :
Daniel@0 10305 1 - easeIn( p * -2 + 2 ) / 2;
Daniel@0 10306 };
Daniel@0 10307 });
Daniel@0 10308
Daniel@0 10309 })();
Daniel@0 10310
Daniel@0 10311 var effect = $.effects;
Daniel@0 10312
Daniel@0 10313
Daniel@0 10314 /*!
Daniel@0 10315 * jQuery UI Effects Blind 1.11.0
Daniel@0 10316 * http://jqueryui.com
Daniel@0 10317 *
Daniel@0 10318 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10319 * Released under the MIT license.
Daniel@0 10320 * http://jquery.org/license
Daniel@0 10321 *
Daniel@0 10322 * http://api.jqueryui.com/blind-effect/
Daniel@0 10323 */
Daniel@0 10324
Daniel@0 10325
Daniel@0 10326 var effectBlind = $.effects.effect.blind = function( o, done ) {
Daniel@0 10327 // Create element
Daniel@0 10328 var el = $( this ),
Daniel@0 10329 rvertical = /up|down|vertical/,
Daniel@0 10330 rpositivemotion = /up|left|vertical|horizontal/,
Daniel@0 10331 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
Daniel@0 10332 mode = $.effects.setMode( el, o.mode || "hide" ),
Daniel@0 10333 direction = o.direction || "up",
Daniel@0 10334 vertical = rvertical.test( direction ),
Daniel@0 10335 ref = vertical ? "height" : "width",
Daniel@0 10336 ref2 = vertical ? "top" : "left",
Daniel@0 10337 motion = rpositivemotion.test( direction ),
Daniel@0 10338 animation = {},
Daniel@0 10339 show = mode === "show",
Daniel@0 10340 wrapper, distance, margin;
Daniel@0 10341
Daniel@0 10342 // if already wrapped, the wrapper's properties are my property. #6245
Daniel@0 10343 if ( el.parent().is( ".ui-effects-wrapper" ) ) {
Daniel@0 10344 $.effects.save( el.parent(), props );
Daniel@0 10345 } else {
Daniel@0 10346 $.effects.save( el, props );
Daniel@0 10347 }
Daniel@0 10348 el.show();
Daniel@0 10349 wrapper = $.effects.createWrapper( el ).css({
Daniel@0 10350 overflow: "hidden"
Daniel@0 10351 });
Daniel@0 10352
Daniel@0 10353 distance = wrapper[ ref ]();
Daniel@0 10354 margin = parseFloat( wrapper.css( ref2 ) ) || 0;
Daniel@0 10355
Daniel@0 10356 animation[ ref ] = show ? distance : 0;
Daniel@0 10357 if ( !motion ) {
Daniel@0 10358 el
Daniel@0 10359 .css( vertical ? "bottom" : "right", 0 )
Daniel@0 10360 .css( vertical ? "top" : "left", "auto" )
Daniel@0 10361 .css({ position: "absolute" });
Daniel@0 10362
Daniel@0 10363 animation[ ref2 ] = show ? margin : distance + margin;
Daniel@0 10364 }
Daniel@0 10365
Daniel@0 10366 // start at 0 if we are showing
Daniel@0 10367 if ( show ) {
Daniel@0 10368 wrapper.css( ref, 0 );
Daniel@0 10369 if ( !motion ) {
Daniel@0 10370 wrapper.css( ref2, margin + distance );
Daniel@0 10371 }
Daniel@0 10372 }
Daniel@0 10373
Daniel@0 10374 // Animate
Daniel@0 10375 wrapper.animate( animation, {
Daniel@0 10376 duration: o.duration,
Daniel@0 10377 easing: o.easing,
Daniel@0 10378 queue: false,
Daniel@0 10379 complete: function() {
Daniel@0 10380 if ( mode === "hide" ) {
Daniel@0 10381 el.hide();
Daniel@0 10382 }
Daniel@0 10383 $.effects.restore( el, props );
Daniel@0 10384 $.effects.removeWrapper( el );
Daniel@0 10385 done();
Daniel@0 10386 }
Daniel@0 10387 });
Daniel@0 10388 };
Daniel@0 10389
Daniel@0 10390
Daniel@0 10391 /*!
Daniel@0 10392 * jQuery UI Effects Bounce 1.11.0
Daniel@0 10393 * http://jqueryui.com
Daniel@0 10394 *
Daniel@0 10395 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10396 * Released under the MIT license.
Daniel@0 10397 * http://jquery.org/license
Daniel@0 10398 *
Daniel@0 10399 * http://api.jqueryui.com/bounce-effect/
Daniel@0 10400 */
Daniel@0 10401
Daniel@0 10402
Daniel@0 10403 var effectBounce = $.effects.effect.bounce = function( o, done ) {
Daniel@0 10404 var el = $( this ),
Daniel@0 10405 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
Daniel@0 10406
Daniel@0 10407 // defaults:
Daniel@0 10408 mode = $.effects.setMode( el, o.mode || "effect" ),
Daniel@0 10409 hide = mode === "hide",
Daniel@0 10410 show = mode === "show",
Daniel@0 10411 direction = o.direction || "up",
Daniel@0 10412 distance = o.distance,
Daniel@0 10413 times = o.times || 5,
Daniel@0 10414
Daniel@0 10415 // number of internal animations
Daniel@0 10416 anims = times * 2 + ( show || hide ? 1 : 0 ),
Daniel@0 10417 speed = o.duration / anims,
Daniel@0 10418 easing = o.easing,
Daniel@0 10419
Daniel@0 10420 // utility:
Daniel@0 10421 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
Daniel@0 10422 motion = ( direction === "up" || direction === "left" ),
Daniel@0 10423 i,
Daniel@0 10424 upAnim,
Daniel@0 10425 downAnim,
Daniel@0 10426
Daniel@0 10427 // we will need to re-assemble the queue to stack our animations in place
Daniel@0 10428 queue = el.queue(),
Daniel@0 10429 queuelen = queue.length;
Daniel@0 10430
Daniel@0 10431 // Avoid touching opacity to prevent clearType and PNG issues in IE
Daniel@0 10432 if ( show || hide ) {
Daniel@0 10433 props.push( "opacity" );
Daniel@0 10434 }
Daniel@0 10435
Daniel@0 10436 $.effects.save( el, props );
Daniel@0 10437 el.show();
Daniel@0 10438 $.effects.createWrapper( el ); // Create Wrapper
Daniel@0 10439
Daniel@0 10440 // default distance for the BIGGEST bounce is the outer Distance / 3
Daniel@0 10441 if ( !distance ) {
Daniel@0 10442 distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
Daniel@0 10443 }
Daniel@0 10444
Daniel@0 10445 if ( show ) {
Daniel@0 10446 downAnim = { opacity: 1 };
Daniel@0 10447 downAnim[ ref ] = 0;
Daniel@0 10448
Daniel@0 10449 // if we are showing, force opacity 0 and set the initial position
Daniel@0 10450 // then do the "first" animation
Daniel@0 10451 el.css( "opacity", 0 )
Daniel@0 10452 .css( ref, motion ? -distance * 2 : distance * 2 )
Daniel@0 10453 .animate( downAnim, speed, easing );
Daniel@0 10454 }
Daniel@0 10455
Daniel@0 10456 // start at the smallest distance if we are hiding
Daniel@0 10457 if ( hide ) {
Daniel@0 10458 distance = distance / Math.pow( 2, times - 1 );
Daniel@0 10459 }
Daniel@0 10460
Daniel@0 10461 downAnim = {};
Daniel@0 10462 downAnim[ ref ] = 0;
Daniel@0 10463 // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
Daniel@0 10464 for ( i = 0; i < times; i++ ) {
Daniel@0 10465 upAnim = {};
Daniel@0 10466 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
Daniel@0 10467
Daniel@0 10468 el.animate( upAnim, speed, easing )
Daniel@0 10469 .animate( downAnim, speed, easing );
Daniel@0 10470
Daniel@0 10471 distance = hide ? distance * 2 : distance / 2;
Daniel@0 10472 }
Daniel@0 10473
Daniel@0 10474 // Last Bounce when Hiding
Daniel@0 10475 if ( hide ) {
Daniel@0 10476 upAnim = { opacity: 0 };
Daniel@0 10477 upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
Daniel@0 10478
Daniel@0 10479 el.animate( upAnim, speed, easing );
Daniel@0 10480 }
Daniel@0 10481
Daniel@0 10482 el.queue(function() {
Daniel@0 10483 if ( hide ) {
Daniel@0 10484 el.hide();
Daniel@0 10485 }
Daniel@0 10486 $.effects.restore( el, props );
Daniel@0 10487 $.effects.removeWrapper( el );
Daniel@0 10488 done();
Daniel@0 10489 });
Daniel@0 10490
Daniel@0 10491 // inject all the animations we just queued to be first in line (after "inprogress")
Daniel@0 10492 if ( queuelen > 1) {
Daniel@0 10493 queue.splice.apply( queue,
Daniel@0 10494 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
Daniel@0 10495 }
Daniel@0 10496 el.dequeue();
Daniel@0 10497
Daniel@0 10498 };
Daniel@0 10499
Daniel@0 10500
Daniel@0 10501 /*!
Daniel@0 10502 * jQuery UI Effects Clip 1.11.0
Daniel@0 10503 * http://jqueryui.com
Daniel@0 10504 *
Daniel@0 10505 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10506 * Released under the MIT license.
Daniel@0 10507 * http://jquery.org/license
Daniel@0 10508 *
Daniel@0 10509 * http://api.jqueryui.com/clip-effect/
Daniel@0 10510 */
Daniel@0 10511
Daniel@0 10512
Daniel@0 10513 var effectClip = $.effects.effect.clip = function( o, done ) {
Daniel@0 10514 // Create element
Daniel@0 10515 var el = $( this ),
Daniel@0 10516 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
Daniel@0 10517 mode = $.effects.setMode( el, o.mode || "hide" ),
Daniel@0 10518 show = mode === "show",
Daniel@0 10519 direction = o.direction || "vertical",
Daniel@0 10520 vert = direction === "vertical",
Daniel@0 10521 size = vert ? "height" : "width",
Daniel@0 10522 position = vert ? "top" : "left",
Daniel@0 10523 animation = {},
Daniel@0 10524 wrapper, animate, distance;
Daniel@0 10525
Daniel@0 10526 // Save & Show
Daniel@0 10527 $.effects.save( el, props );
Daniel@0 10528 el.show();
Daniel@0 10529
Daniel@0 10530 // Create Wrapper
Daniel@0 10531 wrapper = $.effects.createWrapper( el ).css({
Daniel@0 10532 overflow: "hidden"
Daniel@0 10533 });
Daniel@0 10534 animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
Daniel@0 10535 distance = animate[ size ]();
Daniel@0 10536
Daniel@0 10537 // Shift
Daniel@0 10538 if ( show ) {
Daniel@0 10539 animate.css( size, 0 );
Daniel@0 10540 animate.css( position, distance / 2 );
Daniel@0 10541 }
Daniel@0 10542
Daniel@0 10543 // Create Animation Object:
Daniel@0 10544 animation[ size ] = show ? distance : 0;
Daniel@0 10545 animation[ position ] = show ? 0 : distance / 2;
Daniel@0 10546
Daniel@0 10547 // Animate
Daniel@0 10548 animate.animate( animation, {
Daniel@0 10549 queue: false,
Daniel@0 10550 duration: o.duration,
Daniel@0 10551 easing: o.easing,
Daniel@0 10552 complete: function() {
Daniel@0 10553 if ( !show ) {
Daniel@0 10554 el.hide();
Daniel@0 10555 }
Daniel@0 10556 $.effects.restore( el, props );
Daniel@0 10557 $.effects.removeWrapper( el );
Daniel@0 10558 done();
Daniel@0 10559 }
Daniel@0 10560 });
Daniel@0 10561
Daniel@0 10562 };
Daniel@0 10563
Daniel@0 10564
Daniel@0 10565 /*!
Daniel@0 10566 * jQuery UI Effects Drop 1.11.0
Daniel@0 10567 * http://jqueryui.com
Daniel@0 10568 *
Daniel@0 10569 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10570 * Released under the MIT license.
Daniel@0 10571 * http://jquery.org/license
Daniel@0 10572 *
Daniel@0 10573 * http://api.jqueryui.com/drop-effect/
Daniel@0 10574 */
Daniel@0 10575
Daniel@0 10576
Daniel@0 10577 var effectDrop = $.effects.effect.drop = function( o, done ) {
Daniel@0 10578
Daniel@0 10579 var el = $( this ),
Daniel@0 10580 props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
Daniel@0 10581 mode = $.effects.setMode( el, o.mode || "hide" ),
Daniel@0 10582 show = mode === "show",
Daniel@0 10583 direction = o.direction || "left",
Daniel@0 10584 ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
Daniel@0 10585 motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
Daniel@0 10586 animation = {
Daniel@0 10587 opacity: show ? 1 : 0
Daniel@0 10588 },
Daniel@0 10589 distance;
Daniel@0 10590
Daniel@0 10591 // Adjust
Daniel@0 10592 $.effects.save( el, props );
Daniel@0 10593 el.show();
Daniel@0 10594 $.effects.createWrapper( el );
Daniel@0 10595
Daniel@0 10596 distance = o.distance || el[ ref === "top" ? "outerHeight": "outerWidth" ]( true ) / 2;
Daniel@0 10597
Daniel@0 10598 if ( show ) {
Daniel@0 10599 el
Daniel@0 10600 .css( "opacity", 0 )
Daniel@0 10601 .css( ref, motion === "pos" ? -distance : distance );
Daniel@0 10602 }
Daniel@0 10603
Daniel@0 10604 // Animation
Daniel@0 10605 animation[ ref ] = ( show ?
Daniel@0 10606 ( motion === "pos" ? "+=" : "-=" ) :
Daniel@0 10607 ( motion === "pos" ? "-=" : "+=" ) ) +
Daniel@0 10608 distance;
Daniel@0 10609
Daniel@0 10610 // Animate
Daniel@0 10611 el.animate( animation, {
Daniel@0 10612 queue: false,
Daniel@0 10613 duration: o.duration,
Daniel@0 10614 easing: o.easing,
Daniel@0 10615 complete: function() {
Daniel@0 10616 if ( mode === "hide" ) {
Daniel@0 10617 el.hide();
Daniel@0 10618 }
Daniel@0 10619 $.effects.restore( el, props );
Daniel@0 10620 $.effects.removeWrapper( el );
Daniel@0 10621 done();
Daniel@0 10622 }
Daniel@0 10623 });
Daniel@0 10624 };
Daniel@0 10625
Daniel@0 10626
Daniel@0 10627 /*!
Daniel@0 10628 * jQuery UI Effects Explode 1.11.0
Daniel@0 10629 * http://jqueryui.com
Daniel@0 10630 *
Daniel@0 10631 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10632 * Released under the MIT license.
Daniel@0 10633 * http://jquery.org/license
Daniel@0 10634 *
Daniel@0 10635 * http://api.jqueryui.com/explode-effect/
Daniel@0 10636 */
Daniel@0 10637
Daniel@0 10638
Daniel@0 10639 var effectExplode = $.effects.effect.explode = function( o, done ) {
Daniel@0 10640
Daniel@0 10641 var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
Daniel@0 10642 cells = rows,
Daniel@0 10643 el = $( this ),
Daniel@0 10644 mode = $.effects.setMode( el, o.mode || "hide" ),
Daniel@0 10645 show = mode === "show",
Daniel@0 10646
Daniel@0 10647 // show and then visibility:hidden the element before calculating offset
Daniel@0 10648 offset = el.show().css( "visibility", "hidden" ).offset(),
Daniel@0 10649
Daniel@0 10650 // width and height of a piece
Daniel@0 10651 width = Math.ceil( el.outerWidth() / cells ),
Daniel@0 10652 height = Math.ceil( el.outerHeight() / rows ),
Daniel@0 10653 pieces = [],
Daniel@0 10654
Daniel@0 10655 // loop
Daniel@0 10656 i, j, left, top, mx, my;
Daniel@0 10657
Daniel@0 10658 // children animate complete:
Daniel@0 10659 function childComplete() {
Daniel@0 10660 pieces.push( this );
Daniel@0 10661 if ( pieces.length === rows * cells ) {
Daniel@0 10662 animComplete();
Daniel@0 10663 }
Daniel@0 10664 }
Daniel@0 10665
Daniel@0 10666 // clone the element for each row and cell.
Daniel@0 10667 for ( i = 0; i < rows ; i++ ) { // ===>
Daniel@0 10668 top = offset.top + i * height;
Daniel@0 10669 my = i - ( rows - 1 ) / 2 ;
Daniel@0 10670
Daniel@0 10671 for ( j = 0; j < cells ; j++ ) { // |||
Daniel@0 10672 left = offset.left + j * width;
Daniel@0 10673 mx = j - ( cells - 1 ) / 2 ;
Daniel@0 10674
Daniel@0 10675 // Create a clone of the now hidden main element that will be absolute positioned
Daniel@0 10676 // within a wrapper div off the -left and -top equal to size of our pieces
Daniel@0 10677 el
Daniel@0 10678 .clone()
Daniel@0 10679 .appendTo( "body" )
Daniel@0 10680 .wrap( "<div></div>" )
Daniel@0 10681 .css({
Daniel@0 10682 position: "absolute",
Daniel@0 10683 visibility: "visible",
Daniel@0 10684 left: -j * width,
Daniel@0 10685 top: -i * height
Daniel@0 10686 })
Daniel@0 10687
Daniel@0 10688 // select the wrapper - make it overflow: hidden and absolute positioned based on
Daniel@0 10689 // where the original was located +left and +top equal to the size of pieces
Daniel@0 10690 .parent()
Daniel@0 10691 .addClass( "ui-effects-explode" )
Daniel@0 10692 .css({
Daniel@0 10693 position: "absolute",
Daniel@0 10694 overflow: "hidden",
Daniel@0 10695 width: width,
Daniel@0 10696 height: height,
Daniel@0 10697 left: left + ( show ? mx * width : 0 ),
Daniel@0 10698 top: top + ( show ? my * height : 0 ),
Daniel@0 10699 opacity: show ? 0 : 1
Daniel@0 10700 }).animate({
Daniel@0 10701 left: left + ( show ? 0 : mx * width ),
Daniel@0 10702 top: top + ( show ? 0 : my * height ),
Daniel@0 10703 opacity: show ? 1 : 0
Daniel@0 10704 }, o.duration || 500, o.easing, childComplete );
Daniel@0 10705 }
Daniel@0 10706 }
Daniel@0 10707
Daniel@0 10708 function animComplete() {
Daniel@0 10709 el.css({
Daniel@0 10710 visibility: "visible"
Daniel@0 10711 });
Daniel@0 10712 $( pieces ).remove();
Daniel@0 10713 if ( !show ) {
Daniel@0 10714 el.hide();
Daniel@0 10715 }
Daniel@0 10716 done();
Daniel@0 10717 }
Daniel@0 10718 };
Daniel@0 10719
Daniel@0 10720
Daniel@0 10721 /*!
Daniel@0 10722 * jQuery UI Effects Fade 1.11.0
Daniel@0 10723 * http://jqueryui.com
Daniel@0 10724 *
Daniel@0 10725 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10726 * Released under the MIT license.
Daniel@0 10727 * http://jquery.org/license
Daniel@0 10728 *
Daniel@0 10729 * http://api.jqueryui.com/fade-effect/
Daniel@0 10730 */
Daniel@0 10731
Daniel@0 10732
Daniel@0 10733 var effectFade = $.effects.effect.fade = function( o, done ) {
Daniel@0 10734 var el = $( this ),
Daniel@0 10735 mode = $.effects.setMode( el, o.mode || "toggle" );
Daniel@0 10736
Daniel@0 10737 el.animate({
Daniel@0 10738 opacity: mode
Daniel@0 10739 }, {
Daniel@0 10740 queue: false,
Daniel@0 10741 duration: o.duration,
Daniel@0 10742 easing: o.easing,
Daniel@0 10743 complete: done
Daniel@0 10744 });
Daniel@0 10745 };
Daniel@0 10746
Daniel@0 10747
Daniel@0 10748 /*!
Daniel@0 10749 * jQuery UI Effects Fold 1.11.0
Daniel@0 10750 * http://jqueryui.com
Daniel@0 10751 *
Daniel@0 10752 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10753 * Released under the MIT license.
Daniel@0 10754 * http://jquery.org/license
Daniel@0 10755 *
Daniel@0 10756 * http://api.jqueryui.com/fold-effect/
Daniel@0 10757 */
Daniel@0 10758
Daniel@0 10759
Daniel@0 10760 var effectFold = $.effects.effect.fold = function( o, done ) {
Daniel@0 10761
Daniel@0 10762 // Create element
Daniel@0 10763 var el = $( this ),
Daniel@0 10764 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
Daniel@0 10765 mode = $.effects.setMode( el, o.mode || "hide" ),
Daniel@0 10766 show = mode === "show",
Daniel@0 10767 hide = mode === "hide",
Daniel@0 10768 size = o.size || 15,
Daniel@0 10769 percent = /([0-9]+)%/.exec( size ),
Daniel@0 10770 horizFirst = !!o.horizFirst,
Daniel@0 10771 widthFirst = show !== horizFirst,
Daniel@0 10772 ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
Daniel@0 10773 duration = o.duration / 2,
Daniel@0 10774 wrapper, distance,
Daniel@0 10775 animation1 = {},
Daniel@0 10776 animation2 = {};
Daniel@0 10777
Daniel@0 10778 $.effects.save( el, props );
Daniel@0 10779 el.show();
Daniel@0 10780
Daniel@0 10781 // Create Wrapper
Daniel@0 10782 wrapper = $.effects.createWrapper( el ).css({
Daniel@0 10783 overflow: "hidden"
Daniel@0 10784 });
Daniel@0 10785 distance = widthFirst ?
Daniel@0 10786 [ wrapper.width(), wrapper.height() ] :
Daniel@0 10787 [ wrapper.height(), wrapper.width() ];
Daniel@0 10788
Daniel@0 10789 if ( percent ) {
Daniel@0 10790 size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
Daniel@0 10791 }
Daniel@0 10792 if ( show ) {
Daniel@0 10793 wrapper.css( horizFirst ? {
Daniel@0 10794 height: 0,
Daniel@0 10795 width: size
Daniel@0 10796 } : {
Daniel@0 10797 height: size,
Daniel@0 10798 width: 0
Daniel@0 10799 });
Daniel@0 10800 }
Daniel@0 10801
Daniel@0 10802 // Animation
Daniel@0 10803 animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
Daniel@0 10804 animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
Daniel@0 10805
Daniel@0 10806 // Animate
Daniel@0 10807 wrapper
Daniel@0 10808 .animate( animation1, duration, o.easing )
Daniel@0 10809 .animate( animation2, duration, o.easing, function() {
Daniel@0 10810 if ( hide ) {
Daniel@0 10811 el.hide();
Daniel@0 10812 }
Daniel@0 10813 $.effects.restore( el, props );
Daniel@0 10814 $.effects.removeWrapper( el );
Daniel@0 10815 done();
Daniel@0 10816 });
Daniel@0 10817
Daniel@0 10818 };
Daniel@0 10819
Daniel@0 10820
Daniel@0 10821 /*!
Daniel@0 10822 * jQuery UI Effects Highlight 1.11.0
Daniel@0 10823 * http://jqueryui.com
Daniel@0 10824 *
Daniel@0 10825 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10826 * Released under the MIT license.
Daniel@0 10827 * http://jquery.org/license
Daniel@0 10828 *
Daniel@0 10829 * http://api.jqueryui.com/highlight-effect/
Daniel@0 10830 */
Daniel@0 10831
Daniel@0 10832
Daniel@0 10833 var effectHighlight = $.effects.effect.highlight = function( o, done ) {
Daniel@0 10834 var elem = $( this ),
Daniel@0 10835 props = [ "backgroundImage", "backgroundColor", "opacity" ],
Daniel@0 10836 mode = $.effects.setMode( elem, o.mode || "show" ),
Daniel@0 10837 animation = {
Daniel@0 10838 backgroundColor: elem.css( "backgroundColor" )
Daniel@0 10839 };
Daniel@0 10840
Daniel@0 10841 if (mode === "hide") {
Daniel@0 10842 animation.opacity = 0;
Daniel@0 10843 }
Daniel@0 10844
Daniel@0 10845 $.effects.save( elem, props );
Daniel@0 10846
Daniel@0 10847 elem
Daniel@0 10848 .show()
Daniel@0 10849 .css({
Daniel@0 10850 backgroundImage: "none",
Daniel@0 10851 backgroundColor: o.color || "#ffff99"
Daniel@0 10852 })
Daniel@0 10853 .animate( animation, {
Daniel@0 10854 queue: false,
Daniel@0 10855 duration: o.duration,
Daniel@0 10856 easing: o.easing,
Daniel@0 10857 complete: function() {
Daniel@0 10858 if ( mode === "hide" ) {
Daniel@0 10859 elem.hide();
Daniel@0 10860 }
Daniel@0 10861 $.effects.restore( elem, props );
Daniel@0 10862 done();
Daniel@0 10863 }
Daniel@0 10864 });
Daniel@0 10865 };
Daniel@0 10866
Daniel@0 10867
Daniel@0 10868 /*!
Daniel@0 10869 * jQuery UI Effects Size 1.11.0
Daniel@0 10870 * http://jqueryui.com
Daniel@0 10871 *
Daniel@0 10872 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 10873 * Released under the MIT license.
Daniel@0 10874 * http://jquery.org/license
Daniel@0 10875 *
Daniel@0 10876 * http://api.jqueryui.com/size-effect/
Daniel@0 10877 */
Daniel@0 10878
Daniel@0 10879
Daniel@0 10880 var effectSize = $.effects.effect.size = function( o, done ) {
Daniel@0 10881
Daniel@0 10882 // Create element
Daniel@0 10883 var original, baseline, factor,
Daniel@0 10884 el = $( this ),
Daniel@0 10885 props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
Daniel@0 10886
Daniel@0 10887 // Always restore
Daniel@0 10888 props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
Daniel@0 10889
Daniel@0 10890 // Copy for children
Daniel@0 10891 props2 = [ "width", "height", "overflow" ],
Daniel@0 10892 cProps = [ "fontSize" ],
Daniel@0 10893 vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
Daniel@0 10894 hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
Daniel@0 10895
Daniel@0 10896 // Set options
Daniel@0 10897 mode = $.effects.setMode( el, o.mode || "effect" ),
Daniel@0 10898 restore = o.restore || mode !== "effect",
Daniel@0 10899 scale = o.scale || "both",
Daniel@0 10900 origin = o.origin || [ "middle", "center" ],
Daniel@0 10901 position = el.css( "position" ),
Daniel@0 10902 props = restore ? props0 : props1,
Daniel@0 10903 zero = {
Daniel@0 10904 height: 0,
Daniel@0 10905 width: 0,
Daniel@0 10906 outerHeight: 0,
Daniel@0 10907 outerWidth: 0
Daniel@0 10908 };
Daniel@0 10909
Daniel@0 10910 if ( mode === "show" ) {
Daniel@0 10911 el.show();
Daniel@0 10912 }
Daniel@0 10913 original = {
Daniel@0 10914 height: el.height(),
Daniel@0 10915 width: el.width(),
Daniel@0 10916 outerHeight: el.outerHeight(),
Daniel@0 10917 outerWidth: el.outerWidth()
Daniel@0 10918 };
Daniel@0 10919
Daniel@0 10920 if ( o.mode === "toggle" && mode === "show" ) {
Daniel@0 10921 el.from = o.to || zero;
Daniel@0 10922 el.to = o.from || original;
Daniel@0 10923 } else {
Daniel@0 10924 el.from = o.from || ( mode === "show" ? zero : original );
Daniel@0 10925 el.to = o.to || ( mode === "hide" ? zero : original );
Daniel@0 10926 }
Daniel@0 10927
Daniel@0 10928 // Set scaling factor
Daniel@0 10929 factor = {
Daniel@0 10930 from: {
Daniel@0 10931 y: el.from.height / original.height,
Daniel@0 10932 x: el.from.width / original.width
Daniel@0 10933 },
Daniel@0 10934 to: {
Daniel@0 10935 y: el.to.height / original.height,
Daniel@0 10936 x: el.to.width / original.width
Daniel@0 10937 }
Daniel@0 10938 };
Daniel@0 10939
Daniel@0 10940 // Scale the css box
Daniel@0 10941 if ( scale === "box" || scale === "both" ) {
Daniel@0 10942
Daniel@0 10943 // Vertical props scaling
Daniel@0 10944 if ( factor.from.y !== factor.to.y ) {
Daniel@0 10945 props = props.concat( vProps );
Daniel@0 10946 el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
Daniel@0 10947 el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
Daniel@0 10948 }
Daniel@0 10949
Daniel@0 10950 // Horizontal props scaling
Daniel@0 10951 if ( factor.from.x !== factor.to.x ) {
Daniel@0 10952 props = props.concat( hProps );
Daniel@0 10953 el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
Daniel@0 10954 el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
Daniel@0 10955 }
Daniel@0 10956 }
Daniel@0 10957
Daniel@0 10958 // Scale the content
Daniel@0 10959 if ( scale === "content" || scale === "both" ) {
Daniel@0 10960
Daniel@0 10961 // Vertical props scaling
Daniel@0 10962 if ( factor.from.y !== factor.to.y ) {
Daniel@0 10963 props = props.concat( cProps ).concat( props2 );
Daniel@0 10964 el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
Daniel@0 10965 el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
Daniel@0 10966 }
Daniel@0 10967 }
Daniel@0 10968
Daniel@0 10969 $.effects.save( el, props );
Daniel@0 10970 el.show();
Daniel@0 10971 $.effects.createWrapper( el );
Daniel@0 10972 el.css( "overflow", "hidden" ).css( el.from );
Daniel@0 10973
Daniel@0 10974 // Adjust
Daniel@0 10975 if (origin) { // Calculate baseline shifts
Daniel@0 10976 baseline = $.effects.getBaseline( origin, original );
Daniel@0 10977 el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
Daniel@0 10978 el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
Daniel@0 10979 el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
Daniel@0 10980 el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
Daniel@0 10981 }
Daniel@0 10982 el.css( el.from ); // set top & left
Daniel@0 10983
Daniel@0 10984 // Animate
Daniel@0 10985 if ( scale === "content" || scale === "both" ) { // Scale the children
Daniel@0 10986
Daniel@0 10987 // Add margins/font-size
Daniel@0 10988 vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
Daniel@0 10989 hProps = hProps.concat([ "marginLeft", "marginRight" ]);
Daniel@0 10990 props2 = props0.concat(vProps).concat(hProps);
Daniel@0 10991
Daniel@0 10992 el.find( "*[width]" ).each( function() {
Daniel@0 10993 var child = $( this ),
Daniel@0 10994 c_original = {
Daniel@0 10995 height: child.height(),
Daniel@0 10996 width: child.width(),
Daniel@0 10997 outerHeight: child.outerHeight(),
Daniel@0 10998 outerWidth: child.outerWidth()
Daniel@0 10999 };
Daniel@0 11000 if (restore) {
Daniel@0 11001 $.effects.save(child, props2);
Daniel@0 11002 }
Daniel@0 11003
Daniel@0 11004 child.from = {
Daniel@0 11005 height: c_original.height * factor.from.y,
Daniel@0 11006 width: c_original.width * factor.from.x,
Daniel@0 11007 outerHeight: c_original.outerHeight * factor.from.y,
Daniel@0 11008 outerWidth: c_original.outerWidth * factor.from.x
Daniel@0 11009 };
Daniel@0 11010 child.to = {
Daniel@0 11011 height: c_original.height * factor.to.y,
Daniel@0 11012 width: c_original.width * factor.to.x,
Daniel@0 11013 outerHeight: c_original.height * factor.to.y,
Daniel@0 11014 outerWidth: c_original.width * factor.to.x
Daniel@0 11015 };
Daniel@0 11016
Daniel@0 11017 // Vertical props scaling
Daniel@0 11018 if ( factor.from.y !== factor.to.y ) {
Daniel@0 11019 child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
Daniel@0 11020 child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
Daniel@0 11021 }
Daniel@0 11022
Daniel@0 11023 // Horizontal props scaling
Daniel@0 11024 if ( factor.from.x !== factor.to.x ) {
Daniel@0 11025 child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
Daniel@0 11026 child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
Daniel@0 11027 }
Daniel@0 11028
Daniel@0 11029 // Animate children
Daniel@0 11030 child.css( child.from );
Daniel@0 11031 child.animate( child.to, o.duration, o.easing, function() {
Daniel@0 11032
Daniel@0 11033 // Restore children
Daniel@0 11034 if ( restore ) {
Daniel@0 11035 $.effects.restore( child, props2 );
Daniel@0 11036 }
Daniel@0 11037 });
Daniel@0 11038 });
Daniel@0 11039 }
Daniel@0 11040
Daniel@0 11041 // Animate
Daniel@0 11042 el.animate( el.to, {
Daniel@0 11043 queue: false,
Daniel@0 11044 duration: o.duration,
Daniel@0 11045 easing: o.easing,
Daniel@0 11046 complete: function() {
Daniel@0 11047 if ( el.to.opacity === 0 ) {
Daniel@0 11048 el.css( "opacity", el.from.opacity );
Daniel@0 11049 }
Daniel@0 11050 if ( mode === "hide" ) {
Daniel@0 11051 el.hide();
Daniel@0 11052 }
Daniel@0 11053 $.effects.restore( el, props );
Daniel@0 11054 if ( !restore ) {
Daniel@0 11055
Daniel@0 11056 // we need to calculate our new positioning based on the scaling
Daniel@0 11057 if ( position === "static" ) {
Daniel@0 11058 el.css({
Daniel@0 11059 position: "relative",
Daniel@0 11060 top: el.to.top,
Daniel@0 11061 left: el.to.left
Daniel@0 11062 });
Daniel@0 11063 } else {
Daniel@0 11064 $.each([ "top", "left" ], function( idx, pos ) {
Daniel@0 11065 el.css( pos, function( _, str ) {
Daniel@0 11066 var val = parseInt( str, 10 ),
Daniel@0 11067 toRef = idx ? el.to.left : el.to.top;
Daniel@0 11068
Daniel@0 11069 // if original was "auto", recalculate the new value from wrapper
Daniel@0 11070 if ( str === "auto" ) {
Daniel@0 11071 return toRef + "px";
Daniel@0 11072 }
Daniel@0 11073
Daniel@0 11074 return val + toRef + "px";
Daniel@0 11075 });
Daniel@0 11076 });
Daniel@0 11077 }
Daniel@0 11078 }
Daniel@0 11079
Daniel@0 11080 $.effects.removeWrapper( el );
Daniel@0 11081 done();
Daniel@0 11082 }
Daniel@0 11083 });
Daniel@0 11084
Daniel@0 11085 };
Daniel@0 11086
Daniel@0 11087
Daniel@0 11088 /*!
Daniel@0 11089 * jQuery UI Effects Scale 1.11.0
Daniel@0 11090 * http://jqueryui.com
Daniel@0 11091 *
Daniel@0 11092 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11093 * Released under the MIT license.
Daniel@0 11094 * http://jquery.org/license
Daniel@0 11095 *
Daniel@0 11096 * http://api.jqueryui.com/scale-effect/
Daniel@0 11097 */
Daniel@0 11098
Daniel@0 11099
Daniel@0 11100 var effectScale = $.effects.effect.scale = function( o, done ) {
Daniel@0 11101
Daniel@0 11102 // Create element
Daniel@0 11103 var el = $( this ),
Daniel@0 11104 options = $.extend( true, {}, o ),
Daniel@0 11105 mode = $.effects.setMode( el, o.mode || "effect" ),
Daniel@0 11106 percent = parseInt( o.percent, 10 ) ||
Daniel@0 11107 ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
Daniel@0 11108 direction = o.direction || "both",
Daniel@0 11109 origin = o.origin,
Daniel@0 11110 original = {
Daniel@0 11111 height: el.height(),
Daniel@0 11112 width: el.width(),
Daniel@0 11113 outerHeight: el.outerHeight(),
Daniel@0 11114 outerWidth: el.outerWidth()
Daniel@0 11115 },
Daniel@0 11116 factor = {
Daniel@0 11117 y: direction !== "horizontal" ? (percent / 100) : 1,
Daniel@0 11118 x: direction !== "vertical" ? (percent / 100) : 1
Daniel@0 11119 };
Daniel@0 11120
Daniel@0 11121 // We are going to pass this effect to the size effect:
Daniel@0 11122 options.effect = "size";
Daniel@0 11123 options.queue = false;
Daniel@0 11124 options.complete = done;
Daniel@0 11125
Daniel@0 11126 // Set default origin and restore for show/hide
Daniel@0 11127 if ( mode !== "effect" ) {
Daniel@0 11128 options.origin = origin || [ "middle", "center" ];
Daniel@0 11129 options.restore = true;
Daniel@0 11130 }
Daniel@0 11131
Daniel@0 11132 options.from = o.from || ( mode === "show" ? {
Daniel@0 11133 height: 0,
Daniel@0 11134 width: 0,
Daniel@0 11135 outerHeight: 0,
Daniel@0 11136 outerWidth: 0
Daniel@0 11137 } : original );
Daniel@0 11138 options.to = {
Daniel@0 11139 height: original.height * factor.y,
Daniel@0 11140 width: original.width * factor.x,
Daniel@0 11141 outerHeight: original.outerHeight * factor.y,
Daniel@0 11142 outerWidth: original.outerWidth * factor.x
Daniel@0 11143 };
Daniel@0 11144
Daniel@0 11145 // Fade option to support puff
Daniel@0 11146 if ( options.fade ) {
Daniel@0 11147 if ( mode === "show" ) {
Daniel@0 11148 options.from.opacity = 0;
Daniel@0 11149 options.to.opacity = 1;
Daniel@0 11150 }
Daniel@0 11151 if ( mode === "hide" ) {
Daniel@0 11152 options.from.opacity = 1;
Daniel@0 11153 options.to.opacity = 0;
Daniel@0 11154 }
Daniel@0 11155 }
Daniel@0 11156
Daniel@0 11157 // Animate
Daniel@0 11158 el.effect( options );
Daniel@0 11159
Daniel@0 11160 };
Daniel@0 11161
Daniel@0 11162
Daniel@0 11163 /*!
Daniel@0 11164 * jQuery UI Effects Puff 1.11.0
Daniel@0 11165 * http://jqueryui.com
Daniel@0 11166 *
Daniel@0 11167 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11168 * Released under the MIT license.
Daniel@0 11169 * http://jquery.org/license
Daniel@0 11170 *
Daniel@0 11171 * http://api.jqueryui.com/puff-effect/
Daniel@0 11172 */
Daniel@0 11173
Daniel@0 11174
Daniel@0 11175 var effectPuff = $.effects.effect.puff = function( o, done ) {
Daniel@0 11176 var elem = $( this ),
Daniel@0 11177 mode = $.effects.setMode( elem, o.mode || "hide" ),
Daniel@0 11178 hide = mode === "hide",
Daniel@0 11179 percent = parseInt( o.percent, 10 ) || 150,
Daniel@0 11180 factor = percent / 100,
Daniel@0 11181 original = {
Daniel@0 11182 height: elem.height(),
Daniel@0 11183 width: elem.width(),
Daniel@0 11184 outerHeight: elem.outerHeight(),
Daniel@0 11185 outerWidth: elem.outerWidth()
Daniel@0 11186 };
Daniel@0 11187
Daniel@0 11188 $.extend( o, {
Daniel@0 11189 effect: "scale",
Daniel@0 11190 queue: false,
Daniel@0 11191 fade: true,
Daniel@0 11192 mode: mode,
Daniel@0 11193 complete: done,
Daniel@0 11194 percent: hide ? percent : 100,
Daniel@0 11195 from: hide ?
Daniel@0 11196 original :
Daniel@0 11197 {
Daniel@0 11198 height: original.height * factor,
Daniel@0 11199 width: original.width * factor,
Daniel@0 11200 outerHeight: original.outerHeight * factor,
Daniel@0 11201 outerWidth: original.outerWidth * factor
Daniel@0 11202 }
Daniel@0 11203 });
Daniel@0 11204
Daniel@0 11205 elem.effect( o );
Daniel@0 11206 };
Daniel@0 11207
Daniel@0 11208
Daniel@0 11209 /*!
Daniel@0 11210 * jQuery UI Effects Pulsate 1.11.0
Daniel@0 11211 * http://jqueryui.com
Daniel@0 11212 *
Daniel@0 11213 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11214 * Released under the MIT license.
Daniel@0 11215 * http://jquery.org/license
Daniel@0 11216 *
Daniel@0 11217 * http://api.jqueryui.com/pulsate-effect/
Daniel@0 11218 */
Daniel@0 11219
Daniel@0 11220
Daniel@0 11221 var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
Daniel@0 11222 var elem = $( this ),
Daniel@0 11223 mode = $.effects.setMode( elem, o.mode || "show" ),
Daniel@0 11224 show = mode === "show",
Daniel@0 11225 hide = mode === "hide",
Daniel@0 11226 showhide = ( show || mode === "hide" ),
Daniel@0 11227
Daniel@0 11228 // showing or hiding leaves of the "last" animation
Daniel@0 11229 anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
Daniel@0 11230 duration = o.duration / anims,
Daniel@0 11231 animateTo = 0,
Daniel@0 11232 queue = elem.queue(),
Daniel@0 11233 queuelen = queue.length,
Daniel@0 11234 i;
Daniel@0 11235
Daniel@0 11236 if ( show || !elem.is(":visible")) {
Daniel@0 11237 elem.css( "opacity", 0 ).show();
Daniel@0 11238 animateTo = 1;
Daniel@0 11239 }
Daniel@0 11240
Daniel@0 11241 // anims - 1 opacity "toggles"
Daniel@0 11242 for ( i = 1; i < anims; i++ ) {
Daniel@0 11243 elem.animate({
Daniel@0 11244 opacity: animateTo
Daniel@0 11245 }, duration, o.easing );
Daniel@0 11246 animateTo = 1 - animateTo;
Daniel@0 11247 }
Daniel@0 11248
Daniel@0 11249 elem.animate({
Daniel@0 11250 opacity: animateTo
Daniel@0 11251 }, duration, o.easing);
Daniel@0 11252
Daniel@0 11253 elem.queue(function() {
Daniel@0 11254 if ( hide ) {
Daniel@0 11255 elem.hide();
Daniel@0 11256 }
Daniel@0 11257 done();
Daniel@0 11258 });
Daniel@0 11259
Daniel@0 11260 // We just queued up "anims" animations, we need to put them next in the queue
Daniel@0 11261 if ( queuelen > 1 ) {
Daniel@0 11262 queue.splice.apply( queue,
Daniel@0 11263 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
Daniel@0 11264 }
Daniel@0 11265 elem.dequeue();
Daniel@0 11266 };
Daniel@0 11267
Daniel@0 11268
Daniel@0 11269 /*!
Daniel@0 11270 * jQuery UI Effects Shake 1.11.0
Daniel@0 11271 * http://jqueryui.com
Daniel@0 11272 *
Daniel@0 11273 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11274 * Released under the MIT license.
Daniel@0 11275 * http://jquery.org/license
Daniel@0 11276 *
Daniel@0 11277 * http://api.jqueryui.com/shake-effect/
Daniel@0 11278 */
Daniel@0 11279
Daniel@0 11280
Daniel@0 11281 var effectShake = $.effects.effect.shake = function( o, done ) {
Daniel@0 11282
Daniel@0 11283 var el = $( this ),
Daniel@0 11284 props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
Daniel@0 11285 mode = $.effects.setMode( el, o.mode || "effect" ),
Daniel@0 11286 direction = o.direction || "left",
Daniel@0 11287 distance = o.distance || 20,
Daniel@0 11288 times = o.times || 3,
Daniel@0 11289 anims = times * 2 + 1,
Daniel@0 11290 speed = Math.round( o.duration / anims ),
Daniel@0 11291 ref = (direction === "up" || direction === "down") ? "top" : "left",
Daniel@0 11292 positiveMotion = (direction === "up" || direction === "left"),
Daniel@0 11293 animation = {},
Daniel@0 11294 animation1 = {},
Daniel@0 11295 animation2 = {},
Daniel@0 11296 i,
Daniel@0 11297
Daniel@0 11298 // we will need to re-assemble the queue to stack our animations in place
Daniel@0 11299 queue = el.queue(),
Daniel@0 11300 queuelen = queue.length;
Daniel@0 11301
Daniel@0 11302 $.effects.save( el, props );
Daniel@0 11303 el.show();
Daniel@0 11304 $.effects.createWrapper( el );
Daniel@0 11305
Daniel@0 11306 // Animation
Daniel@0 11307 animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
Daniel@0 11308 animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
Daniel@0 11309 animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
Daniel@0 11310
Daniel@0 11311 // Animate
Daniel@0 11312 el.animate( animation, speed, o.easing );
Daniel@0 11313
Daniel@0 11314 // Shakes
Daniel@0 11315 for ( i = 1; i < times; i++ ) {
Daniel@0 11316 el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
Daniel@0 11317 }
Daniel@0 11318 el
Daniel@0 11319 .animate( animation1, speed, o.easing )
Daniel@0 11320 .animate( animation, speed / 2, o.easing )
Daniel@0 11321 .queue(function() {
Daniel@0 11322 if ( mode === "hide" ) {
Daniel@0 11323 el.hide();
Daniel@0 11324 }
Daniel@0 11325 $.effects.restore( el, props );
Daniel@0 11326 $.effects.removeWrapper( el );
Daniel@0 11327 done();
Daniel@0 11328 });
Daniel@0 11329
Daniel@0 11330 // inject all the animations we just queued to be first in line (after "inprogress")
Daniel@0 11331 if ( queuelen > 1) {
Daniel@0 11332 queue.splice.apply( queue,
Daniel@0 11333 [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
Daniel@0 11334 }
Daniel@0 11335 el.dequeue();
Daniel@0 11336
Daniel@0 11337 };
Daniel@0 11338
Daniel@0 11339
Daniel@0 11340 /*!
Daniel@0 11341 * jQuery UI Effects Slide 1.11.0
Daniel@0 11342 * http://jqueryui.com
Daniel@0 11343 *
Daniel@0 11344 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11345 * Released under the MIT license.
Daniel@0 11346 * http://jquery.org/license
Daniel@0 11347 *
Daniel@0 11348 * http://api.jqueryui.com/slide-effect/
Daniel@0 11349 */
Daniel@0 11350
Daniel@0 11351
Daniel@0 11352 var effectSlide = $.effects.effect.slide = function( o, done ) {
Daniel@0 11353
Daniel@0 11354 // Create element
Daniel@0 11355 var el = $( this ),
Daniel@0 11356 props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
Daniel@0 11357 mode = $.effects.setMode( el, o.mode || "show" ),
Daniel@0 11358 show = mode === "show",
Daniel@0 11359 direction = o.direction || "left",
Daniel@0 11360 ref = (direction === "up" || direction === "down") ? "top" : "left",
Daniel@0 11361 positiveMotion = (direction === "up" || direction === "left"),
Daniel@0 11362 distance,
Daniel@0 11363 animation = {};
Daniel@0 11364
Daniel@0 11365 // Adjust
Daniel@0 11366 $.effects.save( el, props );
Daniel@0 11367 el.show();
Daniel@0 11368 distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
Daniel@0 11369
Daniel@0 11370 $.effects.createWrapper( el ).css({
Daniel@0 11371 overflow: "hidden"
Daniel@0 11372 });
Daniel@0 11373
Daniel@0 11374 if ( show ) {
Daniel@0 11375 el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
Daniel@0 11376 }
Daniel@0 11377
Daniel@0 11378 // Animation
Daniel@0 11379 animation[ ref ] = ( show ?
Daniel@0 11380 ( positiveMotion ? "+=" : "-=") :
Daniel@0 11381 ( positiveMotion ? "-=" : "+=")) +
Daniel@0 11382 distance;
Daniel@0 11383
Daniel@0 11384 // Animate
Daniel@0 11385 el.animate( animation, {
Daniel@0 11386 queue: false,
Daniel@0 11387 duration: o.duration,
Daniel@0 11388 easing: o.easing,
Daniel@0 11389 complete: function() {
Daniel@0 11390 if ( mode === "hide" ) {
Daniel@0 11391 el.hide();
Daniel@0 11392 }
Daniel@0 11393 $.effects.restore( el, props );
Daniel@0 11394 $.effects.removeWrapper( el );
Daniel@0 11395 done();
Daniel@0 11396 }
Daniel@0 11397 });
Daniel@0 11398 };
Daniel@0 11399
Daniel@0 11400
Daniel@0 11401 /*!
Daniel@0 11402 * jQuery UI Effects Transfer 1.11.0
Daniel@0 11403 * http://jqueryui.com
Daniel@0 11404 *
Daniel@0 11405 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11406 * Released under the MIT license.
Daniel@0 11407 * http://jquery.org/license
Daniel@0 11408 *
Daniel@0 11409 * http://api.jqueryui.com/transfer-effect/
Daniel@0 11410 */
Daniel@0 11411
Daniel@0 11412
Daniel@0 11413 var effectTransfer = $.effects.effect.transfer = function( o, done ) {
Daniel@0 11414 var elem = $( this ),
Daniel@0 11415 target = $( o.to ),
Daniel@0 11416 targetFixed = target.css( "position" ) === "fixed",
Daniel@0 11417 body = $("body"),
Daniel@0 11418 fixTop = targetFixed ? body.scrollTop() : 0,
Daniel@0 11419 fixLeft = targetFixed ? body.scrollLeft() : 0,
Daniel@0 11420 endPosition = target.offset(),
Daniel@0 11421 animation = {
Daniel@0 11422 top: endPosition.top - fixTop,
Daniel@0 11423 left: endPosition.left - fixLeft,
Daniel@0 11424 height: target.innerHeight(),
Daniel@0 11425 width: target.innerWidth()
Daniel@0 11426 },
Daniel@0 11427 startPosition = elem.offset(),
Daniel@0 11428 transfer = $( "<div class='ui-effects-transfer'></div>" )
Daniel@0 11429 .appendTo( document.body )
Daniel@0 11430 .addClass( o.className )
Daniel@0 11431 .css({
Daniel@0 11432 top: startPosition.top - fixTop,
Daniel@0 11433 left: startPosition.left - fixLeft,
Daniel@0 11434 height: elem.innerHeight(),
Daniel@0 11435 width: elem.innerWidth(),
Daniel@0 11436 position: targetFixed ? "fixed" : "absolute"
Daniel@0 11437 })
Daniel@0 11438 .animate( animation, o.duration, o.easing, function() {
Daniel@0 11439 transfer.remove();
Daniel@0 11440 done();
Daniel@0 11441 });
Daniel@0 11442 };
Daniel@0 11443
Daniel@0 11444
Daniel@0 11445 /*!
Daniel@0 11446 * jQuery UI Progressbar 1.11.0
Daniel@0 11447 * http://jqueryui.com
Daniel@0 11448 *
Daniel@0 11449 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11450 * Released under the MIT license.
Daniel@0 11451 * http://jquery.org/license
Daniel@0 11452 *
Daniel@0 11453 * http://api.jqueryui.com/progressbar/
Daniel@0 11454 */
Daniel@0 11455
Daniel@0 11456
Daniel@0 11457 var progressbar = $.widget( "ui.progressbar", {
Daniel@0 11458 version: "1.11.0",
Daniel@0 11459 options: {
Daniel@0 11460 max: 100,
Daniel@0 11461 value: 0,
Daniel@0 11462
Daniel@0 11463 change: null,
Daniel@0 11464 complete: null
Daniel@0 11465 },
Daniel@0 11466
Daniel@0 11467 min: 0,
Daniel@0 11468
Daniel@0 11469 _create: function() {
Daniel@0 11470 // Constrain initial value
Daniel@0 11471 this.oldValue = this.options.value = this._constrainedValue();
Daniel@0 11472
Daniel@0 11473 this.element
Daniel@0 11474 .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
Daniel@0 11475 .attr({
Daniel@0 11476 // Only set static values, aria-valuenow and aria-valuemax are
Daniel@0 11477 // set inside _refreshValue()
Daniel@0 11478 role: "progressbar",
Daniel@0 11479 "aria-valuemin": this.min
Daniel@0 11480 });
Daniel@0 11481
Daniel@0 11482 this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
Daniel@0 11483 .appendTo( this.element );
Daniel@0 11484
Daniel@0 11485 this._refreshValue();
Daniel@0 11486 },
Daniel@0 11487
Daniel@0 11488 _destroy: function() {
Daniel@0 11489 this.element
Daniel@0 11490 .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
Daniel@0 11491 .removeAttr( "role" )
Daniel@0 11492 .removeAttr( "aria-valuemin" )
Daniel@0 11493 .removeAttr( "aria-valuemax" )
Daniel@0 11494 .removeAttr( "aria-valuenow" );
Daniel@0 11495
Daniel@0 11496 this.valueDiv.remove();
Daniel@0 11497 },
Daniel@0 11498
Daniel@0 11499 value: function( newValue ) {
Daniel@0 11500 if ( newValue === undefined ) {
Daniel@0 11501 return this.options.value;
Daniel@0 11502 }
Daniel@0 11503
Daniel@0 11504 this.options.value = this._constrainedValue( newValue );
Daniel@0 11505 this._refreshValue();
Daniel@0 11506 },
Daniel@0 11507
Daniel@0 11508 _constrainedValue: function( newValue ) {
Daniel@0 11509 if ( newValue === undefined ) {
Daniel@0 11510 newValue = this.options.value;
Daniel@0 11511 }
Daniel@0 11512
Daniel@0 11513 this.indeterminate = newValue === false;
Daniel@0 11514
Daniel@0 11515 // sanitize value
Daniel@0 11516 if ( typeof newValue !== "number" ) {
Daniel@0 11517 newValue = 0;
Daniel@0 11518 }
Daniel@0 11519
Daniel@0 11520 return this.indeterminate ? false :
Daniel@0 11521 Math.min( this.options.max, Math.max( this.min, newValue ) );
Daniel@0 11522 },
Daniel@0 11523
Daniel@0 11524 _setOptions: function( options ) {
Daniel@0 11525 // Ensure "value" option is set after other values (like max)
Daniel@0 11526 var value = options.value;
Daniel@0 11527 delete options.value;
Daniel@0 11528
Daniel@0 11529 this._super( options );
Daniel@0 11530
Daniel@0 11531 this.options.value = this._constrainedValue( value );
Daniel@0 11532 this._refreshValue();
Daniel@0 11533 },
Daniel@0 11534
Daniel@0 11535 _setOption: function( key, value ) {
Daniel@0 11536 if ( key === "max" ) {
Daniel@0 11537 // Don't allow a max less than min
Daniel@0 11538 value = Math.max( this.min, value );
Daniel@0 11539 }
Daniel@0 11540 if ( key === "disabled" ) {
Daniel@0 11541 this.element
Daniel@0 11542 .toggleClass( "ui-state-disabled", !!value )
Daniel@0 11543 .attr( "aria-disabled", value );
Daniel@0 11544 }
Daniel@0 11545 this._super( key, value );
Daniel@0 11546 },
Daniel@0 11547
Daniel@0 11548 _percentage: function() {
Daniel@0 11549 return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
Daniel@0 11550 },
Daniel@0 11551
Daniel@0 11552 _refreshValue: function() {
Daniel@0 11553 var value = this.options.value,
Daniel@0 11554 percentage = this._percentage();
Daniel@0 11555
Daniel@0 11556 this.valueDiv
Daniel@0 11557 .toggle( this.indeterminate || value > this.min )
Daniel@0 11558 .toggleClass( "ui-corner-right", value === this.options.max )
Daniel@0 11559 .width( percentage.toFixed(0) + "%" );
Daniel@0 11560
Daniel@0 11561 this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
Daniel@0 11562
Daniel@0 11563 if ( this.indeterminate ) {
Daniel@0 11564 this.element.removeAttr( "aria-valuenow" );
Daniel@0 11565 if ( !this.overlayDiv ) {
Daniel@0 11566 this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
Daniel@0 11567 }
Daniel@0 11568 } else {
Daniel@0 11569 this.element.attr({
Daniel@0 11570 "aria-valuemax": this.options.max,
Daniel@0 11571 "aria-valuenow": value
Daniel@0 11572 });
Daniel@0 11573 if ( this.overlayDiv ) {
Daniel@0 11574 this.overlayDiv.remove();
Daniel@0 11575 this.overlayDiv = null;
Daniel@0 11576 }
Daniel@0 11577 }
Daniel@0 11578
Daniel@0 11579 if ( this.oldValue !== value ) {
Daniel@0 11580 this.oldValue = value;
Daniel@0 11581 this._trigger( "change" );
Daniel@0 11582 }
Daniel@0 11583 if ( value === this.options.max ) {
Daniel@0 11584 this._trigger( "complete" );
Daniel@0 11585 }
Daniel@0 11586 }
Daniel@0 11587 });
Daniel@0 11588
Daniel@0 11589
Daniel@0 11590 /*!
Daniel@0 11591 * jQuery UI Selectable 1.11.0
Daniel@0 11592 * http://jqueryui.com
Daniel@0 11593 *
Daniel@0 11594 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11595 * Released under the MIT license.
Daniel@0 11596 * http://jquery.org/license
Daniel@0 11597 *
Daniel@0 11598 * http://api.jqueryui.com/selectable/
Daniel@0 11599 */
Daniel@0 11600
Daniel@0 11601
Daniel@0 11602 var selectable = $.widget("ui.selectable", $.ui.mouse, {
Daniel@0 11603 version: "1.11.0",
Daniel@0 11604 options: {
Daniel@0 11605 appendTo: "body",
Daniel@0 11606 autoRefresh: true,
Daniel@0 11607 distance: 0,
Daniel@0 11608 filter: "*",
Daniel@0 11609 tolerance: "touch",
Daniel@0 11610
Daniel@0 11611 // callbacks
Daniel@0 11612 selected: null,
Daniel@0 11613 selecting: null,
Daniel@0 11614 start: null,
Daniel@0 11615 stop: null,
Daniel@0 11616 unselected: null,
Daniel@0 11617 unselecting: null
Daniel@0 11618 },
Daniel@0 11619 _create: function() {
Daniel@0 11620 var selectees,
Daniel@0 11621 that = this;
Daniel@0 11622
Daniel@0 11623 this.element.addClass("ui-selectable");
Daniel@0 11624
Daniel@0 11625 this.dragged = false;
Daniel@0 11626
Daniel@0 11627 // cache selectee children based on filter
Daniel@0 11628 this.refresh = function() {
Daniel@0 11629 selectees = $(that.options.filter, that.element[0]);
Daniel@0 11630 selectees.addClass("ui-selectee");
Daniel@0 11631 selectees.each(function() {
Daniel@0 11632 var $this = $(this),
Daniel@0 11633 pos = $this.offset();
Daniel@0 11634 $.data(this, "selectable-item", {
Daniel@0 11635 element: this,
Daniel@0 11636 $element: $this,
Daniel@0 11637 left: pos.left,
Daniel@0 11638 top: pos.top,
Daniel@0 11639 right: pos.left + $this.outerWidth(),
Daniel@0 11640 bottom: pos.top + $this.outerHeight(),
Daniel@0 11641 startselected: false,
Daniel@0 11642 selected: $this.hasClass("ui-selected"),
Daniel@0 11643 selecting: $this.hasClass("ui-selecting"),
Daniel@0 11644 unselecting: $this.hasClass("ui-unselecting")
Daniel@0 11645 });
Daniel@0 11646 });
Daniel@0 11647 };
Daniel@0 11648 this.refresh();
Daniel@0 11649
Daniel@0 11650 this.selectees = selectees.addClass("ui-selectee");
Daniel@0 11651
Daniel@0 11652 this._mouseInit();
Daniel@0 11653
Daniel@0 11654 this.helper = $("<div class='ui-selectable-helper'></div>");
Daniel@0 11655 },
Daniel@0 11656
Daniel@0 11657 _destroy: function() {
Daniel@0 11658 this.selectees
Daniel@0 11659 .removeClass("ui-selectee")
Daniel@0 11660 .removeData("selectable-item");
Daniel@0 11661 this.element
Daniel@0 11662 .removeClass("ui-selectable ui-selectable-disabled");
Daniel@0 11663 this._mouseDestroy();
Daniel@0 11664 },
Daniel@0 11665
Daniel@0 11666 _mouseStart: function(event) {
Daniel@0 11667 var that = this,
Daniel@0 11668 options = this.options;
Daniel@0 11669
Daniel@0 11670 this.opos = [ event.pageX, event.pageY ];
Daniel@0 11671
Daniel@0 11672 if (this.options.disabled) {
Daniel@0 11673 return;
Daniel@0 11674 }
Daniel@0 11675
Daniel@0 11676 this.selectees = $(options.filter, this.element[0]);
Daniel@0 11677
Daniel@0 11678 this._trigger("start", event);
Daniel@0 11679
Daniel@0 11680 $(options.appendTo).append(this.helper);
Daniel@0 11681 // position helper (lasso)
Daniel@0 11682 this.helper.css({
Daniel@0 11683 "left": event.pageX,
Daniel@0 11684 "top": event.pageY,
Daniel@0 11685 "width": 0,
Daniel@0 11686 "height": 0
Daniel@0 11687 });
Daniel@0 11688
Daniel@0 11689 if (options.autoRefresh) {
Daniel@0 11690 this.refresh();
Daniel@0 11691 }
Daniel@0 11692
Daniel@0 11693 this.selectees.filter(".ui-selected").each(function() {
Daniel@0 11694 var selectee = $.data(this, "selectable-item");
Daniel@0 11695 selectee.startselected = true;
Daniel@0 11696 if (!event.metaKey && !event.ctrlKey) {
Daniel@0 11697 selectee.$element.removeClass("ui-selected");
Daniel@0 11698 selectee.selected = false;
Daniel@0 11699 selectee.$element.addClass("ui-unselecting");
Daniel@0 11700 selectee.unselecting = true;
Daniel@0 11701 // selectable UNSELECTING callback
Daniel@0 11702 that._trigger("unselecting", event, {
Daniel@0 11703 unselecting: selectee.element
Daniel@0 11704 });
Daniel@0 11705 }
Daniel@0 11706 });
Daniel@0 11707
Daniel@0 11708 $(event.target).parents().addBack().each(function() {
Daniel@0 11709 var doSelect,
Daniel@0 11710 selectee = $.data(this, "selectable-item");
Daniel@0 11711 if (selectee) {
Daniel@0 11712 doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
Daniel@0 11713 selectee.$element
Daniel@0 11714 .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
Daniel@0 11715 .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
Daniel@0 11716 selectee.unselecting = !doSelect;
Daniel@0 11717 selectee.selecting = doSelect;
Daniel@0 11718 selectee.selected = doSelect;
Daniel@0 11719 // selectable (UN)SELECTING callback
Daniel@0 11720 if (doSelect) {
Daniel@0 11721 that._trigger("selecting", event, {
Daniel@0 11722 selecting: selectee.element
Daniel@0 11723 });
Daniel@0 11724 } else {
Daniel@0 11725 that._trigger("unselecting", event, {
Daniel@0 11726 unselecting: selectee.element
Daniel@0 11727 });
Daniel@0 11728 }
Daniel@0 11729 return false;
Daniel@0 11730 }
Daniel@0 11731 });
Daniel@0 11732
Daniel@0 11733 },
Daniel@0 11734
Daniel@0 11735 _mouseDrag: function(event) {
Daniel@0 11736
Daniel@0 11737 this.dragged = true;
Daniel@0 11738
Daniel@0 11739 if (this.options.disabled) {
Daniel@0 11740 return;
Daniel@0 11741 }
Daniel@0 11742
Daniel@0 11743 var tmp,
Daniel@0 11744 that = this,
Daniel@0 11745 options = this.options,
Daniel@0 11746 x1 = this.opos[0],
Daniel@0 11747 y1 = this.opos[1],
Daniel@0 11748 x2 = event.pageX,
Daniel@0 11749 y2 = event.pageY;
Daniel@0 11750
Daniel@0 11751 if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
Daniel@0 11752 if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
Daniel@0 11753 this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
Daniel@0 11754
Daniel@0 11755 this.selectees.each(function() {
Daniel@0 11756 var selectee = $.data(this, "selectable-item"),
Daniel@0 11757 hit = false;
Daniel@0 11758
Daniel@0 11759 //prevent helper from being selected if appendTo: selectable
Daniel@0 11760 if (!selectee || selectee.element === that.element[0]) {
Daniel@0 11761 return;
Daniel@0 11762 }
Daniel@0 11763
Daniel@0 11764 if (options.tolerance === "touch") {
Daniel@0 11765 hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
Daniel@0 11766 } else if (options.tolerance === "fit") {
Daniel@0 11767 hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
Daniel@0 11768 }
Daniel@0 11769
Daniel@0 11770 if (hit) {
Daniel@0 11771 // SELECT
Daniel@0 11772 if (selectee.selected) {
Daniel@0 11773 selectee.$element.removeClass("ui-selected");
Daniel@0 11774 selectee.selected = false;
Daniel@0 11775 }
Daniel@0 11776 if (selectee.unselecting) {
Daniel@0 11777 selectee.$element.removeClass("ui-unselecting");
Daniel@0 11778 selectee.unselecting = false;
Daniel@0 11779 }
Daniel@0 11780 if (!selectee.selecting) {
Daniel@0 11781 selectee.$element.addClass("ui-selecting");
Daniel@0 11782 selectee.selecting = true;
Daniel@0 11783 // selectable SELECTING callback
Daniel@0 11784 that._trigger("selecting", event, {
Daniel@0 11785 selecting: selectee.element
Daniel@0 11786 });
Daniel@0 11787 }
Daniel@0 11788 } else {
Daniel@0 11789 // UNSELECT
Daniel@0 11790 if (selectee.selecting) {
Daniel@0 11791 if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
Daniel@0 11792 selectee.$element.removeClass("ui-selecting");
Daniel@0 11793 selectee.selecting = false;
Daniel@0 11794 selectee.$element.addClass("ui-selected");
Daniel@0 11795 selectee.selected = true;
Daniel@0 11796 } else {
Daniel@0 11797 selectee.$element.removeClass("ui-selecting");
Daniel@0 11798 selectee.selecting = false;
Daniel@0 11799 if (selectee.startselected) {
Daniel@0 11800 selectee.$element.addClass("ui-unselecting");
Daniel@0 11801 selectee.unselecting = true;
Daniel@0 11802 }
Daniel@0 11803 // selectable UNSELECTING callback
Daniel@0 11804 that._trigger("unselecting", event, {
Daniel@0 11805 unselecting: selectee.element
Daniel@0 11806 });
Daniel@0 11807 }
Daniel@0 11808 }
Daniel@0 11809 if (selectee.selected) {
Daniel@0 11810 if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
Daniel@0 11811 selectee.$element.removeClass("ui-selected");
Daniel@0 11812 selectee.selected = false;
Daniel@0 11813
Daniel@0 11814 selectee.$element.addClass("ui-unselecting");
Daniel@0 11815 selectee.unselecting = true;
Daniel@0 11816 // selectable UNSELECTING callback
Daniel@0 11817 that._trigger("unselecting", event, {
Daniel@0 11818 unselecting: selectee.element
Daniel@0 11819 });
Daniel@0 11820 }
Daniel@0 11821 }
Daniel@0 11822 }
Daniel@0 11823 });
Daniel@0 11824
Daniel@0 11825 return false;
Daniel@0 11826 },
Daniel@0 11827
Daniel@0 11828 _mouseStop: function(event) {
Daniel@0 11829 var that = this;
Daniel@0 11830
Daniel@0 11831 this.dragged = false;
Daniel@0 11832
Daniel@0 11833 $(".ui-unselecting", this.element[0]).each(function() {
Daniel@0 11834 var selectee = $.data(this, "selectable-item");
Daniel@0 11835 selectee.$element.removeClass("ui-unselecting");
Daniel@0 11836 selectee.unselecting = false;
Daniel@0 11837 selectee.startselected = false;
Daniel@0 11838 that._trigger("unselected", event, {
Daniel@0 11839 unselected: selectee.element
Daniel@0 11840 });
Daniel@0 11841 });
Daniel@0 11842 $(".ui-selecting", this.element[0]).each(function() {
Daniel@0 11843 var selectee = $.data(this, "selectable-item");
Daniel@0 11844 selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
Daniel@0 11845 selectee.selecting = false;
Daniel@0 11846 selectee.selected = true;
Daniel@0 11847 selectee.startselected = true;
Daniel@0 11848 that._trigger("selected", event, {
Daniel@0 11849 selected: selectee.element
Daniel@0 11850 });
Daniel@0 11851 });
Daniel@0 11852 this._trigger("stop", event);
Daniel@0 11853
Daniel@0 11854 this.helper.remove();
Daniel@0 11855
Daniel@0 11856 return false;
Daniel@0 11857 }
Daniel@0 11858
Daniel@0 11859 });
Daniel@0 11860
Daniel@0 11861
Daniel@0 11862 /*!
Daniel@0 11863 * jQuery UI Selectmenu 1.11.0
Daniel@0 11864 * http://jqueryui.com
Daniel@0 11865 *
Daniel@0 11866 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 11867 * Released under the MIT license.
Daniel@0 11868 * http://jquery.org/license
Daniel@0 11869 *
Daniel@0 11870 * http://api.jqueryui.com/selectmenu
Daniel@0 11871 */
Daniel@0 11872
Daniel@0 11873
Daniel@0 11874 var selectmenu = $.widget( "ui.selectmenu", {
Daniel@0 11875 version: "1.11.0",
Daniel@0 11876 defaultElement: "<select>",
Daniel@0 11877 options: {
Daniel@0 11878 appendTo: null,
Daniel@0 11879 disabled: null,
Daniel@0 11880 icons: {
Daniel@0 11881 button: "ui-icon-triangle-1-s"
Daniel@0 11882 },
Daniel@0 11883 position: {
Daniel@0 11884 my: "left top",
Daniel@0 11885 at: "left bottom",
Daniel@0 11886 collision: "none"
Daniel@0 11887 },
Daniel@0 11888 width: null,
Daniel@0 11889
Daniel@0 11890 // callbacks
Daniel@0 11891 change: null,
Daniel@0 11892 close: null,
Daniel@0 11893 focus: null,
Daniel@0 11894 open: null,
Daniel@0 11895 select: null
Daniel@0 11896 },
Daniel@0 11897
Daniel@0 11898 _create: function() {
Daniel@0 11899 var selectmenuId = this.element.uniqueId().attr( "id" );
Daniel@0 11900 this.ids = {
Daniel@0 11901 element: selectmenuId,
Daniel@0 11902 button: selectmenuId + "-button",
Daniel@0 11903 menu: selectmenuId + "-menu"
Daniel@0 11904 };
Daniel@0 11905
Daniel@0 11906 this._drawButton();
Daniel@0 11907 this._drawMenu();
Daniel@0 11908
Daniel@0 11909 if ( this.options.disabled ) {
Daniel@0 11910 this.disable();
Daniel@0 11911 }
Daniel@0 11912 },
Daniel@0 11913
Daniel@0 11914 _drawButton: function() {
Daniel@0 11915 var that = this,
Daniel@0 11916 tabindex = this.element.attr( "tabindex" );
Daniel@0 11917
Daniel@0 11918 // Associate existing label with the new button
Daniel@0 11919 this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
Daniel@0 11920 this._on( this.label, {
Daniel@0 11921 click: function( event ) {
Daniel@0 11922 this.button.focus();
Daniel@0 11923 event.preventDefault();
Daniel@0 11924 }
Daniel@0 11925 });
Daniel@0 11926
Daniel@0 11927 // Hide original select element
Daniel@0 11928 this.element.hide();
Daniel@0 11929
Daniel@0 11930 // Create button
Daniel@0 11931 this.button = $( "<span>", {
Daniel@0 11932 "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
Daniel@0 11933 tabindex: tabindex || this.options.disabled ? -1 : 0,
Daniel@0 11934 id: this.ids.button,
Daniel@0 11935 role: "combobox",
Daniel@0 11936 "aria-expanded": "false",
Daniel@0 11937 "aria-autocomplete": "list",
Daniel@0 11938 "aria-owns": this.ids.menu,
Daniel@0 11939 "aria-haspopup": "true"
Daniel@0 11940 })
Daniel@0 11941 .insertAfter( this.element );
Daniel@0 11942
Daniel@0 11943 $( "<span>", {
Daniel@0 11944 "class": "ui-icon " + this.options.icons.button
Daniel@0 11945 })
Daniel@0 11946 .prependTo( this.button );
Daniel@0 11947
Daniel@0 11948 this.buttonText = $( "<span>", {
Daniel@0 11949 "class": "ui-selectmenu-text"
Daniel@0 11950 })
Daniel@0 11951 .appendTo( this.button );
Daniel@0 11952
Daniel@0 11953 this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
Daniel@0 11954 this._setOption( "width", this.options.width );
Daniel@0 11955
Daniel@0 11956 this._on( this.button, this._buttonEvents );
Daniel@0 11957 this.button.one( "focusin", function() {
Daniel@0 11958
Daniel@0 11959 // Delay rendering the menu items until the button receives focus.
Daniel@0 11960 // The menu may have already been rendered via a programmatic open.
Daniel@0 11961 if ( !that.menuItems ) {
Daniel@0 11962 that._refreshMenu();
Daniel@0 11963 }
Daniel@0 11964 });
Daniel@0 11965 this._hoverable( this.button );
Daniel@0 11966 this._focusable( this.button );
Daniel@0 11967 },
Daniel@0 11968
Daniel@0 11969 _drawMenu: function() {
Daniel@0 11970 var that = this;
Daniel@0 11971
Daniel@0 11972 // Create menu
Daniel@0 11973 this.menu = $( "<ul>", {
Daniel@0 11974 "aria-hidden": "true",
Daniel@0 11975 "aria-labelledby": this.ids.button,
Daniel@0 11976 id: this.ids.menu
Daniel@0 11977 });
Daniel@0 11978
Daniel@0 11979 // Wrap menu
Daniel@0 11980 this.menuWrap = $( "<div>", {
Daniel@0 11981 "class": "ui-selectmenu-menu ui-front"
Daniel@0 11982 })
Daniel@0 11983 .append( this.menu )
Daniel@0 11984 .appendTo( this._appendTo() );
Daniel@0 11985
Daniel@0 11986 // Initialize menu widget
Daniel@0 11987 this.menuInstance = this.menu
Daniel@0 11988 .menu({
Daniel@0 11989 role: "listbox",
Daniel@0 11990 select: function( event, ui ) {
Daniel@0 11991 event.preventDefault();
Daniel@0 11992 that._select( ui.item.data( "ui-selectmenu-item" ), event );
Daniel@0 11993 },
Daniel@0 11994 focus: function( event, ui ) {
Daniel@0 11995 var item = ui.item.data( "ui-selectmenu-item" );
Daniel@0 11996
Daniel@0 11997 // Prevent inital focus from firing and check if its a newly focused item
Daniel@0 11998 if ( that.focusIndex != null && item.index !== that.focusIndex ) {
Daniel@0 11999 that._trigger( "focus", event, { item: item } );
Daniel@0 12000 if ( !that.isOpen ) {
Daniel@0 12001 that._select( item, event );
Daniel@0 12002 }
Daniel@0 12003 }
Daniel@0 12004 that.focusIndex = item.index;
Daniel@0 12005
Daniel@0 12006 that.button.attr( "aria-activedescendant",
Daniel@0 12007 that.menuItems.eq( item.index ).attr( "id" ) );
Daniel@0 12008 }
Daniel@0 12009 })
Daniel@0 12010 .menu( "instance" );
Daniel@0 12011
Daniel@0 12012 // Adjust menu styles to dropdown
Daniel@0 12013 this.menu
Daniel@0 12014 .addClass( "ui-corner-bottom" )
Daniel@0 12015 .removeClass( "ui-corner-all" );
Daniel@0 12016
Daniel@0 12017 // Don't close the menu on mouseleave
Daniel@0 12018 this.menuInstance._off( this.menu, "mouseleave" );
Daniel@0 12019
Daniel@0 12020 // Cancel the menu's collapseAll on document click
Daniel@0 12021 this.menuInstance._closeOnDocumentClick = function() {
Daniel@0 12022 return false;
Daniel@0 12023 };
Daniel@0 12024
Daniel@0 12025 // Selects often contain empty items, but never contain dividers
Daniel@0 12026 this.menuInstance._isDivider = function() {
Daniel@0 12027 return false;
Daniel@0 12028 };
Daniel@0 12029 },
Daniel@0 12030
Daniel@0 12031 refresh: function() {
Daniel@0 12032 this._refreshMenu();
Daniel@0 12033 this._setText( this.buttonText, this._getSelectedItem().text() );
Daniel@0 12034 this._setOption( "width", this.options.width );
Daniel@0 12035 },
Daniel@0 12036
Daniel@0 12037 _refreshMenu: function() {
Daniel@0 12038 this.menu.empty();
Daniel@0 12039
Daniel@0 12040 var item,
Daniel@0 12041 options = this.element.find( "option" );
Daniel@0 12042
Daniel@0 12043 if ( !options.length ) {
Daniel@0 12044 return;
Daniel@0 12045 }
Daniel@0 12046
Daniel@0 12047 this._parseOptions( options );
Daniel@0 12048 this._renderMenu( this.menu, this.items );
Daniel@0 12049
Daniel@0 12050 this.menuInstance.refresh();
Daniel@0 12051 this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
Daniel@0 12052
Daniel@0 12053 item = this._getSelectedItem();
Daniel@0 12054
Daniel@0 12055 // Update the menu to have the correct item focused
Daniel@0 12056 this.menuInstance.focus( null, item );
Daniel@0 12057 this._setAria( item.data( "ui-selectmenu-item" ) );
Daniel@0 12058
Daniel@0 12059 // Set disabled state
Daniel@0 12060 this._setOption( "disabled", this.element.prop( "disabled" ) );
Daniel@0 12061 },
Daniel@0 12062
Daniel@0 12063 open: function( event ) {
Daniel@0 12064 if ( this.options.disabled ) {
Daniel@0 12065 return;
Daniel@0 12066 }
Daniel@0 12067
Daniel@0 12068 // If this is the first time the menu is being opened, render the items
Daniel@0 12069 if ( !this.menuItems ) {
Daniel@0 12070 this._refreshMenu();
Daniel@0 12071 } else {
Daniel@0 12072
Daniel@0 12073 // Menu clears focus on close, reset focus to selected item
Daniel@0 12074 this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
Daniel@0 12075 this.menuInstance.focus( null, this._getSelectedItem() );
Daniel@0 12076 }
Daniel@0 12077
Daniel@0 12078 this.isOpen = true;
Daniel@0 12079 this._toggleAttr();
Daniel@0 12080 this._resizeMenu();
Daniel@0 12081 this._position();
Daniel@0 12082
Daniel@0 12083 this._on( this.document, this._documentClick );
Daniel@0 12084
Daniel@0 12085 this._trigger( "open", event );
Daniel@0 12086 },
Daniel@0 12087
Daniel@0 12088 _position: function() {
Daniel@0 12089 this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
Daniel@0 12090 },
Daniel@0 12091
Daniel@0 12092 close: function( event ) {
Daniel@0 12093 if ( !this.isOpen ) {
Daniel@0 12094 return;
Daniel@0 12095 }
Daniel@0 12096
Daniel@0 12097 this.isOpen = false;
Daniel@0 12098 this._toggleAttr();
Daniel@0 12099
Daniel@0 12100 this._off( this.document );
Daniel@0 12101
Daniel@0 12102 this._trigger( "close", event );
Daniel@0 12103 },
Daniel@0 12104
Daniel@0 12105 widget: function() {
Daniel@0 12106 return this.button;
Daniel@0 12107 },
Daniel@0 12108
Daniel@0 12109 menuWidget: function() {
Daniel@0 12110 return this.menu;
Daniel@0 12111 },
Daniel@0 12112
Daniel@0 12113 _renderMenu: function( ul, items ) {
Daniel@0 12114 var that = this,
Daniel@0 12115 currentOptgroup = "";
Daniel@0 12116
Daniel@0 12117 $.each( items, function( index, item ) {
Daniel@0 12118 if ( item.optgroup !== currentOptgroup ) {
Daniel@0 12119 $( "<li>", {
Daniel@0 12120 "class": "ui-selectmenu-optgroup ui-menu-divider" +
Daniel@0 12121 ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
Daniel@0 12122 " ui-state-disabled" :
Daniel@0 12123 "" ),
Daniel@0 12124 text: item.optgroup
Daniel@0 12125 })
Daniel@0 12126 .appendTo( ul );
Daniel@0 12127
Daniel@0 12128 currentOptgroup = item.optgroup;
Daniel@0 12129 }
Daniel@0 12130
Daniel@0 12131 that._renderItemData( ul, item );
Daniel@0 12132 });
Daniel@0 12133 },
Daniel@0 12134
Daniel@0 12135 _renderItemData: function( ul, item ) {
Daniel@0 12136 return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
Daniel@0 12137 },
Daniel@0 12138
Daniel@0 12139 _renderItem: function( ul, item ) {
Daniel@0 12140 var li = $( "<li>" );
Daniel@0 12141
Daniel@0 12142 if ( item.disabled ) {
Daniel@0 12143 li.addClass( "ui-state-disabled" );
Daniel@0 12144 }
Daniel@0 12145 this._setText( li, item.label );
Daniel@0 12146
Daniel@0 12147 return li.appendTo( ul );
Daniel@0 12148 },
Daniel@0 12149
Daniel@0 12150 _setText: function( element, value ) {
Daniel@0 12151 if ( value ) {
Daniel@0 12152 element.text( value );
Daniel@0 12153 } else {
Daniel@0 12154 element.html( "&#160;" );
Daniel@0 12155 }
Daniel@0 12156 },
Daniel@0 12157
Daniel@0 12158 _move: function( direction, event ) {
Daniel@0 12159 var item, next,
Daniel@0 12160 filter = ".ui-menu-item";
Daniel@0 12161
Daniel@0 12162 if ( this.isOpen ) {
Daniel@0 12163 item = this.menuItems.eq( this.focusIndex );
Daniel@0 12164 } else {
Daniel@0 12165 item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
Daniel@0 12166 filter += ":not(.ui-state-disabled)";
Daniel@0 12167 }
Daniel@0 12168
Daniel@0 12169 if ( direction === "first" || direction === "last" ) {
Daniel@0 12170 next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
Daniel@0 12171 } else {
Daniel@0 12172 next = item[ direction + "All" ]( filter ).eq( 0 );
Daniel@0 12173 }
Daniel@0 12174
Daniel@0 12175 if ( next.length ) {
Daniel@0 12176 this.menuInstance.focus( event, next );
Daniel@0 12177 }
Daniel@0 12178 },
Daniel@0 12179
Daniel@0 12180 _getSelectedItem: function() {
Daniel@0 12181 return this.menuItems.eq( this.element[ 0 ].selectedIndex );
Daniel@0 12182 },
Daniel@0 12183
Daniel@0 12184 _toggle: function( event ) {
Daniel@0 12185 this[ this.isOpen ? "close" : "open" ]( event );
Daniel@0 12186 },
Daniel@0 12187
Daniel@0 12188 _documentClick: {
Daniel@0 12189 mousedown: function( event ) {
Daniel@0 12190 if ( !this.isOpen ) {
Daniel@0 12191 return;
Daniel@0 12192 }
Daniel@0 12193
Daniel@0 12194 if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
Daniel@0 12195 this.close( event );
Daniel@0 12196 }
Daniel@0 12197 }
Daniel@0 12198 },
Daniel@0 12199
Daniel@0 12200 _buttonEvents: {
Daniel@0 12201 click: "_toggle",
Daniel@0 12202 keydown: function( event ) {
Daniel@0 12203 var preventDefault = true;
Daniel@0 12204 switch ( event.keyCode ) {
Daniel@0 12205 case $.ui.keyCode.TAB:
Daniel@0 12206 case $.ui.keyCode.ESCAPE:
Daniel@0 12207 this.close( event );
Daniel@0 12208 preventDefault = false;
Daniel@0 12209 break;
Daniel@0 12210 case $.ui.keyCode.ENTER:
Daniel@0 12211 if ( this.isOpen ) {
Daniel@0 12212 this._selectFocusedItem( event );
Daniel@0 12213 }
Daniel@0 12214 break;
Daniel@0 12215 case $.ui.keyCode.UP:
Daniel@0 12216 if ( event.altKey ) {
Daniel@0 12217 this._toggle( event );
Daniel@0 12218 } else {
Daniel@0 12219 this._move( "prev", event );
Daniel@0 12220 }
Daniel@0 12221 break;
Daniel@0 12222 case $.ui.keyCode.DOWN:
Daniel@0 12223 if ( event.altKey ) {
Daniel@0 12224 this._toggle( event );
Daniel@0 12225 } else {
Daniel@0 12226 this._move( "next", event );
Daniel@0 12227 }
Daniel@0 12228 break;
Daniel@0 12229 case $.ui.keyCode.SPACE:
Daniel@0 12230 if ( this.isOpen ) {
Daniel@0 12231 this._selectFocusedItem( event );
Daniel@0 12232 } else {
Daniel@0 12233 this._toggle( event );
Daniel@0 12234 }
Daniel@0 12235 break;
Daniel@0 12236 case $.ui.keyCode.LEFT:
Daniel@0 12237 this._move( "prev", event );
Daniel@0 12238 break;
Daniel@0 12239 case $.ui.keyCode.RIGHT:
Daniel@0 12240 this._move( "next", event );
Daniel@0 12241 break;
Daniel@0 12242 case $.ui.keyCode.HOME:
Daniel@0 12243 case $.ui.keyCode.PAGE_UP:
Daniel@0 12244 this._move( "first", event );
Daniel@0 12245 break;
Daniel@0 12246 case $.ui.keyCode.END:
Daniel@0 12247 case $.ui.keyCode.PAGE_DOWN:
Daniel@0 12248 this._move( "last", event );
Daniel@0 12249 break;
Daniel@0 12250 default:
Daniel@0 12251 this.menu.trigger( event );
Daniel@0 12252 preventDefault = false;
Daniel@0 12253 }
Daniel@0 12254
Daniel@0 12255 if ( preventDefault ) {
Daniel@0 12256 event.preventDefault();
Daniel@0 12257 }
Daniel@0 12258 }
Daniel@0 12259 },
Daniel@0 12260
Daniel@0 12261 _selectFocusedItem: function( event ) {
Daniel@0 12262 var item = this.menuItems.eq( this.focusIndex );
Daniel@0 12263 if ( !item.hasClass( "ui-state-disabled" ) ) {
Daniel@0 12264 this._select( item.data( "ui-selectmenu-item" ), event );
Daniel@0 12265 }
Daniel@0 12266 },
Daniel@0 12267
Daniel@0 12268 _select: function( item, event ) {
Daniel@0 12269 var oldIndex = this.element[ 0 ].selectedIndex;
Daniel@0 12270
Daniel@0 12271 // Change native select element
Daniel@0 12272 this.element[ 0 ].selectedIndex = item.index;
Daniel@0 12273 this._setText( this.buttonText, item.label );
Daniel@0 12274 this._setAria( item );
Daniel@0 12275 this._trigger( "select", event, { item: item } );
Daniel@0 12276
Daniel@0 12277 if ( item.index !== oldIndex ) {
Daniel@0 12278 this._trigger( "change", event, { item: item } );
Daniel@0 12279 }
Daniel@0 12280
Daniel@0 12281 this.close( event );
Daniel@0 12282 },
Daniel@0 12283
Daniel@0 12284 _setAria: function( item ) {
Daniel@0 12285 var id = this.menuItems.eq( item.index ).attr( "id" );
Daniel@0 12286
Daniel@0 12287 this.button.attr({
Daniel@0 12288 "aria-labelledby": id,
Daniel@0 12289 "aria-activedescendant": id
Daniel@0 12290 });
Daniel@0 12291 this.menu.attr( "aria-activedescendant", id );
Daniel@0 12292 },
Daniel@0 12293
Daniel@0 12294 _setOption: function( key, value ) {
Daniel@0 12295 if ( key === "icons" ) {
Daniel@0 12296 this.button.find( "span.ui-icon" )
Daniel@0 12297 .removeClass( this.options.icons.button )
Daniel@0 12298 .addClass( value.button );
Daniel@0 12299 }
Daniel@0 12300
Daniel@0 12301 this._super( key, value );
Daniel@0 12302
Daniel@0 12303 if ( key === "appendTo" ) {
Daniel@0 12304 this.menuWrap.appendTo( this._appendTo() );
Daniel@0 12305 }
Daniel@0 12306
Daniel@0 12307 if ( key === "disabled" ) {
Daniel@0 12308 this.menuInstance.option( "disabled", value );
Daniel@0 12309 this.button
Daniel@0 12310 .toggleClass( "ui-state-disabled", value )
Daniel@0 12311 .attr( "aria-disabled", value );
Daniel@0 12312
Daniel@0 12313 this.element.prop( "disabled", value );
Daniel@0 12314 if ( value ) {
Daniel@0 12315 this.button.attr( "tabindex", -1 );
Daniel@0 12316 this.close();
Daniel@0 12317 } else {
Daniel@0 12318 this.button.attr( "tabindex", 0 );
Daniel@0 12319 }
Daniel@0 12320 }
Daniel@0 12321
Daniel@0 12322 if ( key === "width" ) {
Daniel@0 12323 if ( !value ) {
Daniel@0 12324 value = this.element.outerWidth();
Daniel@0 12325 }
Daniel@0 12326 this.button.outerWidth( value );
Daniel@0 12327 }
Daniel@0 12328 },
Daniel@0 12329
Daniel@0 12330 _appendTo: function() {
Daniel@0 12331 var element = this.options.appendTo;
Daniel@0 12332
Daniel@0 12333 if ( element ) {
Daniel@0 12334 element = element.jquery || element.nodeType ?
Daniel@0 12335 $( element ) :
Daniel@0 12336 this.document.find( element ).eq( 0 );
Daniel@0 12337 }
Daniel@0 12338
Daniel@0 12339 if ( !element || !element[ 0 ] ) {
Daniel@0 12340 element = this.element.closest( ".ui-front" );
Daniel@0 12341 }
Daniel@0 12342
Daniel@0 12343 if ( !element.length ) {
Daniel@0 12344 element = this.document[ 0 ].body;
Daniel@0 12345 }
Daniel@0 12346
Daniel@0 12347 return element;
Daniel@0 12348 },
Daniel@0 12349
Daniel@0 12350 _toggleAttr: function() {
Daniel@0 12351 this.button
Daniel@0 12352 .toggleClass( "ui-corner-top", this.isOpen )
Daniel@0 12353 .toggleClass( "ui-corner-all", !this.isOpen )
Daniel@0 12354 .attr( "aria-expanded", this.isOpen );
Daniel@0 12355 this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
Daniel@0 12356 this.menu.attr( "aria-hidden", !this.isOpen );
Daniel@0 12357 },
Daniel@0 12358
Daniel@0 12359 _resizeMenu: function() {
Daniel@0 12360 this.menu.outerWidth( Math.max(
Daniel@0 12361 this.button.outerWidth(),
Daniel@0 12362
Daniel@0 12363 // support: IE10
Daniel@0 12364 // IE10 wraps long text (possibly a rounding bug)
Daniel@0 12365 // so we add 1px to avoid the wrapping
Daniel@0 12366 this.menu.width( "" ).outerWidth() + 1
Daniel@0 12367 ) );
Daniel@0 12368 },
Daniel@0 12369
Daniel@0 12370 _getCreateOptions: function() {
Daniel@0 12371 return { disabled: this.element.prop( "disabled" ) };
Daniel@0 12372 },
Daniel@0 12373
Daniel@0 12374 _parseOptions: function( options ) {
Daniel@0 12375 var data = [];
Daniel@0 12376 options.each(function( index, item ) {
Daniel@0 12377 var option = $( item ),
Daniel@0 12378 optgroup = option.parent( "optgroup" );
Daniel@0 12379 data.push({
Daniel@0 12380 element: option,
Daniel@0 12381 index: index,
Daniel@0 12382 value: option.attr( "value" ),
Daniel@0 12383 label: option.text(),
Daniel@0 12384 optgroup: optgroup.attr( "label" ) || "",
Daniel@0 12385 disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
Daniel@0 12386 });
Daniel@0 12387 });
Daniel@0 12388 this.items = data;
Daniel@0 12389 },
Daniel@0 12390
Daniel@0 12391 _destroy: function() {
Daniel@0 12392 this.menuWrap.remove();
Daniel@0 12393 this.button.remove();
Daniel@0 12394 this.element.show();
Daniel@0 12395 this.element.removeUniqueId();
Daniel@0 12396 this.label.attr( "for", this.ids.element );
Daniel@0 12397 }
Daniel@0 12398 });
Daniel@0 12399
Daniel@0 12400
Daniel@0 12401 /*!
Daniel@0 12402 * jQuery UI Slider 1.11.0
Daniel@0 12403 * http://jqueryui.com
Daniel@0 12404 *
Daniel@0 12405 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 12406 * Released under the MIT license.
Daniel@0 12407 * http://jquery.org/license
Daniel@0 12408 *
Daniel@0 12409 * http://api.jqueryui.com/slider/
Daniel@0 12410 */
Daniel@0 12411
Daniel@0 12412
Daniel@0 12413 var slider = $.widget( "ui.slider", $.ui.mouse, {
Daniel@0 12414 version: "1.11.0",
Daniel@0 12415 widgetEventPrefix: "slide",
Daniel@0 12416
Daniel@0 12417 options: {
Daniel@0 12418 animate: false,
Daniel@0 12419 distance: 0,
Daniel@0 12420 max: 100,
Daniel@0 12421 min: 0,
Daniel@0 12422 orientation: "horizontal",
Daniel@0 12423 range: false,
Daniel@0 12424 step: 1,
Daniel@0 12425 value: 0,
Daniel@0 12426 values: null,
Daniel@0 12427
Daniel@0 12428 // callbacks
Daniel@0 12429 change: null,
Daniel@0 12430 slide: null,
Daniel@0 12431 start: null,
Daniel@0 12432 stop: null
Daniel@0 12433 },
Daniel@0 12434
Daniel@0 12435 // number of pages in a slider
Daniel@0 12436 // (how many times can you page up/down to go through the whole range)
Daniel@0 12437 numPages: 5,
Daniel@0 12438
Daniel@0 12439 _create: function() {
Daniel@0 12440 this._keySliding = false;
Daniel@0 12441 this._mouseSliding = false;
Daniel@0 12442 this._animateOff = true;
Daniel@0 12443 this._handleIndex = null;
Daniel@0 12444 this._detectOrientation();
Daniel@0 12445 this._mouseInit();
Daniel@0 12446
Daniel@0 12447 this.element
Daniel@0 12448 .addClass( "ui-slider" +
Daniel@0 12449 " ui-slider-" + this.orientation +
Daniel@0 12450 " ui-widget" +
Daniel@0 12451 " ui-widget-content" +
Daniel@0 12452 " ui-corner-all");
Daniel@0 12453
Daniel@0 12454 this._refresh();
Daniel@0 12455 this._setOption( "disabled", this.options.disabled );
Daniel@0 12456
Daniel@0 12457 this._animateOff = false;
Daniel@0 12458 },
Daniel@0 12459
Daniel@0 12460 _refresh: function() {
Daniel@0 12461 this._createRange();
Daniel@0 12462 this._createHandles();
Daniel@0 12463 this._setupEvents();
Daniel@0 12464 this._refreshValue();
Daniel@0 12465 },
Daniel@0 12466
Daniel@0 12467 _createHandles: function() {
Daniel@0 12468 var i, handleCount,
Daniel@0 12469 options = this.options,
Daniel@0 12470 existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
Daniel@0 12471 handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
Daniel@0 12472 handles = [];
Daniel@0 12473
Daniel@0 12474 handleCount = ( options.values && options.values.length ) || 1;
Daniel@0 12475
Daniel@0 12476 if ( existingHandles.length > handleCount ) {
Daniel@0 12477 existingHandles.slice( handleCount ).remove();
Daniel@0 12478 existingHandles = existingHandles.slice( 0, handleCount );
Daniel@0 12479 }
Daniel@0 12480
Daniel@0 12481 for ( i = existingHandles.length; i < handleCount; i++ ) {
Daniel@0 12482 handles.push( handle );
Daniel@0 12483 }
Daniel@0 12484
Daniel@0 12485 this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
Daniel@0 12486
Daniel@0 12487 this.handle = this.handles.eq( 0 );
Daniel@0 12488
Daniel@0 12489 this.handles.each(function( i ) {
Daniel@0 12490 $( this ).data( "ui-slider-handle-index", i );
Daniel@0 12491 });
Daniel@0 12492 },
Daniel@0 12493
Daniel@0 12494 _createRange: function() {
Daniel@0 12495 var options = this.options,
Daniel@0 12496 classes = "";
Daniel@0 12497
Daniel@0 12498 if ( options.range ) {
Daniel@0 12499 if ( options.range === true ) {
Daniel@0 12500 if ( !options.values ) {
Daniel@0 12501 options.values = [ this._valueMin(), this._valueMin() ];
Daniel@0 12502 } else if ( options.values.length && options.values.length !== 2 ) {
Daniel@0 12503 options.values = [ options.values[0], options.values[0] ];
Daniel@0 12504 } else if ( $.isArray( options.values ) ) {
Daniel@0 12505 options.values = options.values.slice(0);
Daniel@0 12506 }
Daniel@0 12507 }
Daniel@0 12508
Daniel@0 12509 if ( !this.range || !this.range.length ) {
Daniel@0 12510 this.range = $( "<div></div>" )
Daniel@0 12511 .appendTo( this.element );
Daniel@0 12512
Daniel@0 12513 classes = "ui-slider-range" +
Daniel@0 12514 // note: this isn't the most fittingly semantic framework class for this element,
Daniel@0 12515 // but worked best visually with a variety of themes
Daniel@0 12516 " ui-widget-header ui-corner-all";
Daniel@0 12517 } else {
Daniel@0 12518 this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
Daniel@0 12519 // Handle range switching from true to min/max
Daniel@0 12520 .css({
Daniel@0 12521 "left": "",
Daniel@0 12522 "bottom": ""
Daniel@0 12523 });
Daniel@0 12524 }
Daniel@0 12525
Daniel@0 12526 this.range.addClass( classes +
Daniel@0 12527 ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
Daniel@0 12528 } else {
Daniel@0 12529 if ( this.range ) {
Daniel@0 12530 this.range.remove();
Daniel@0 12531 }
Daniel@0 12532 this.range = null;
Daniel@0 12533 }
Daniel@0 12534 },
Daniel@0 12535
Daniel@0 12536 _setupEvents: function() {
Daniel@0 12537 this._off( this.handles );
Daniel@0 12538 this._on( this.handles, this._handleEvents );
Daniel@0 12539 this._hoverable( this.handles );
Daniel@0 12540 this._focusable( this.handles );
Daniel@0 12541 },
Daniel@0 12542
Daniel@0 12543 _destroy: function() {
Daniel@0 12544 this.handles.remove();
Daniel@0 12545 if ( this.range ) {
Daniel@0 12546 this.range.remove();
Daniel@0 12547 }
Daniel@0 12548
Daniel@0 12549 this.element
Daniel@0 12550 .removeClass( "ui-slider" +
Daniel@0 12551 " ui-slider-horizontal" +
Daniel@0 12552 " ui-slider-vertical" +
Daniel@0 12553 " ui-widget" +
Daniel@0 12554 " ui-widget-content" +
Daniel@0 12555 " ui-corner-all" );
Daniel@0 12556
Daniel@0 12557 this._mouseDestroy();
Daniel@0 12558 },
Daniel@0 12559
Daniel@0 12560 _mouseCapture: function( event ) {
Daniel@0 12561 var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
Daniel@0 12562 that = this,
Daniel@0 12563 o = this.options;
Daniel@0 12564
Daniel@0 12565 if ( o.disabled ) {
Daniel@0 12566 return false;
Daniel@0 12567 }
Daniel@0 12568
Daniel@0 12569 this.elementSize = {
Daniel@0 12570 width: this.element.outerWidth(),
Daniel@0 12571 height: this.element.outerHeight()
Daniel@0 12572 };
Daniel@0 12573 this.elementOffset = this.element.offset();
Daniel@0 12574
Daniel@0 12575 position = { x: event.pageX, y: event.pageY };
Daniel@0 12576 normValue = this._normValueFromMouse( position );
Daniel@0 12577 distance = this._valueMax() - this._valueMin() + 1;
Daniel@0 12578 this.handles.each(function( i ) {
Daniel@0 12579 var thisDistance = Math.abs( normValue - that.values(i) );
Daniel@0 12580 if (( distance > thisDistance ) ||
Daniel@0 12581 ( distance === thisDistance &&
Daniel@0 12582 (i === that._lastChangedValue || that.values(i) === o.min ))) {
Daniel@0 12583 distance = thisDistance;
Daniel@0 12584 closestHandle = $( this );
Daniel@0 12585 index = i;
Daniel@0 12586 }
Daniel@0 12587 });
Daniel@0 12588
Daniel@0 12589 allowed = this._start( event, index );
Daniel@0 12590 if ( allowed === false ) {
Daniel@0 12591 return false;
Daniel@0 12592 }
Daniel@0 12593 this._mouseSliding = true;
Daniel@0 12594
Daniel@0 12595 this._handleIndex = index;
Daniel@0 12596
Daniel@0 12597 closestHandle
Daniel@0 12598 .addClass( "ui-state-active" )
Daniel@0 12599 .focus();
Daniel@0 12600
Daniel@0 12601 offset = closestHandle.offset();
Daniel@0 12602 mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
Daniel@0 12603 this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
Daniel@0 12604 left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
Daniel@0 12605 top: event.pageY - offset.top -
Daniel@0 12606 ( closestHandle.height() / 2 ) -
Daniel@0 12607 ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
Daniel@0 12608 ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
Daniel@0 12609 ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
Daniel@0 12610 };
Daniel@0 12611
Daniel@0 12612 if ( !this.handles.hasClass( "ui-state-hover" ) ) {
Daniel@0 12613 this._slide( event, index, normValue );
Daniel@0 12614 }
Daniel@0 12615 this._animateOff = true;
Daniel@0 12616 return true;
Daniel@0 12617 },
Daniel@0 12618
Daniel@0 12619 _mouseStart: function() {
Daniel@0 12620 return true;
Daniel@0 12621 },
Daniel@0 12622
Daniel@0 12623 _mouseDrag: function( event ) {
Daniel@0 12624 var position = { x: event.pageX, y: event.pageY },
Daniel@0 12625 normValue = this._normValueFromMouse( position );
Daniel@0 12626
Daniel@0 12627 this._slide( event, this._handleIndex, normValue );
Daniel@0 12628
Daniel@0 12629 return false;
Daniel@0 12630 },
Daniel@0 12631
Daniel@0 12632 _mouseStop: function( event ) {
Daniel@0 12633 this.handles.removeClass( "ui-state-active" );
Daniel@0 12634 this._mouseSliding = false;
Daniel@0 12635
Daniel@0 12636 this._stop( event, this._handleIndex );
Daniel@0 12637 this._change( event, this._handleIndex );
Daniel@0 12638
Daniel@0 12639 this._handleIndex = null;
Daniel@0 12640 this._clickOffset = null;
Daniel@0 12641 this._animateOff = false;
Daniel@0 12642
Daniel@0 12643 return false;
Daniel@0 12644 },
Daniel@0 12645
Daniel@0 12646 _detectOrientation: function() {
Daniel@0 12647 this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
Daniel@0 12648 },
Daniel@0 12649
Daniel@0 12650 _normValueFromMouse: function( position ) {
Daniel@0 12651 var pixelTotal,
Daniel@0 12652 pixelMouse,
Daniel@0 12653 percentMouse,
Daniel@0 12654 valueTotal,
Daniel@0 12655 valueMouse;
Daniel@0 12656
Daniel@0 12657 if ( this.orientation === "horizontal" ) {
Daniel@0 12658 pixelTotal = this.elementSize.width;
Daniel@0 12659 pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
Daniel@0 12660 } else {
Daniel@0 12661 pixelTotal = this.elementSize.height;
Daniel@0 12662 pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
Daniel@0 12663 }
Daniel@0 12664
Daniel@0 12665 percentMouse = ( pixelMouse / pixelTotal );
Daniel@0 12666 if ( percentMouse > 1 ) {
Daniel@0 12667 percentMouse = 1;
Daniel@0 12668 }
Daniel@0 12669 if ( percentMouse < 0 ) {
Daniel@0 12670 percentMouse = 0;
Daniel@0 12671 }
Daniel@0 12672 if ( this.orientation === "vertical" ) {
Daniel@0 12673 percentMouse = 1 - percentMouse;
Daniel@0 12674 }
Daniel@0 12675
Daniel@0 12676 valueTotal = this._valueMax() - this._valueMin();
Daniel@0 12677 valueMouse = this._valueMin() + percentMouse * valueTotal;
Daniel@0 12678
Daniel@0 12679 return this._trimAlignValue( valueMouse );
Daniel@0 12680 },
Daniel@0 12681
Daniel@0 12682 _start: function( event, index ) {
Daniel@0 12683 var uiHash = {
Daniel@0 12684 handle: this.handles[ index ],
Daniel@0 12685 value: this.value()
Daniel@0 12686 };
Daniel@0 12687 if ( this.options.values && this.options.values.length ) {
Daniel@0 12688 uiHash.value = this.values( index );
Daniel@0 12689 uiHash.values = this.values();
Daniel@0 12690 }
Daniel@0 12691 return this._trigger( "start", event, uiHash );
Daniel@0 12692 },
Daniel@0 12693
Daniel@0 12694 _slide: function( event, index, newVal ) {
Daniel@0 12695 var otherVal,
Daniel@0 12696 newValues,
Daniel@0 12697 allowed;
Daniel@0 12698
Daniel@0 12699 if ( this.options.values && this.options.values.length ) {
Daniel@0 12700 otherVal = this.values( index ? 0 : 1 );
Daniel@0 12701
Daniel@0 12702 if ( ( this.options.values.length === 2 && this.options.range === true ) &&
Daniel@0 12703 ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
Daniel@0 12704 ) {
Daniel@0 12705 newVal = otherVal;
Daniel@0 12706 }
Daniel@0 12707
Daniel@0 12708 if ( newVal !== this.values( index ) ) {
Daniel@0 12709 newValues = this.values();
Daniel@0 12710 newValues[ index ] = newVal;
Daniel@0 12711 // A slide can be canceled by returning false from the slide callback
Daniel@0 12712 allowed = this._trigger( "slide", event, {
Daniel@0 12713 handle: this.handles[ index ],
Daniel@0 12714 value: newVal,
Daniel@0 12715 values: newValues
Daniel@0 12716 } );
Daniel@0 12717 otherVal = this.values( index ? 0 : 1 );
Daniel@0 12718 if ( allowed !== false ) {
Daniel@0 12719 this.values( index, newVal );
Daniel@0 12720 }
Daniel@0 12721 }
Daniel@0 12722 } else {
Daniel@0 12723 if ( newVal !== this.value() ) {
Daniel@0 12724 // A slide can be canceled by returning false from the slide callback
Daniel@0 12725 allowed = this._trigger( "slide", event, {
Daniel@0 12726 handle: this.handles[ index ],
Daniel@0 12727 value: newVal
Daniel@0 12728 } );
Daniel@0 12729 if ( allowed !== false ) {
Daniel@0 12730 this.value( newVal );
Daniel@0 12731 }
Daniel@0 12732 }
Daniel@0 12733 }
Daniel@0 12734 },
Daniel@0 12735
Daniel@0 12736 _stop: function( event, index ) {
Daniel@0 12737 var uiHash = {
Daniel@0 12738 handle: this.handles[ index ],
Daniel@0 12739 value: this.value()
Daniel@0 12740 };
Daniel@0 12741 if ( this.options.values && this.options.values.length ) {
Daniel@0 12742 uiHash.value = this.values( index );
Daniel@0 12743 uiHash.values = this.values();
Daniel@0 12744 }
Daniel@0 12745
Daniel@0 12746 this._trigger( "stop", event, uiHash );
Daniel@0 12747 },
Daniel@0 12748
Daniel@0 12749 _change: function( event, index ) {
Daniel@0 12750 if ( !this._keySliding && !this._mouseSliding ) {
Daniel@0 12751 var uiHash = {
Daniel@0 12752 handle: this.handles[ index ],
Daniel@0 12753 value: this.value()
Daniel@0 12754 };
Daniel@0 12755 if ( this.options.values && this.options.values.length ) {
Daniel@0 12756 uiHash.value = this.values( index );
Daniel@0 12757 uiHash.values = this.values();
Daniel@0 12758 }
Daniel@0 12759
Daniel@0 12760 //store the last changed value index for reference when handles overlap
Daniel@0 12761 this._lastChangedValue = index;
Daniel@0 12762
Daniel@0 12763 this._trigger( "change", event, uiHash );
Daniel@0 12764 }
Daniel@0 12765 },
Daniel@0 12766
Daniel@0 12767 value: function( newValue ) {
Daniel@0 12768 if ( arguments.length ) {
Daniel@0 12769 this.options.value = this._trimAlignValue( newValue );
Daniel@0 12770 this._refreshValue();
Daniel@0 12771 this._change( null, 0 );
Daniel@0 12772 return;
Daniel@0 12773 }
Daniel@0 12774
Daniel@0 12775 return this._value();
Daniel@0 12776 },
Daniel@0 12777
Daniel@0 12778 values: function( index, newValue ) {
Daniel@0 12779 var vals,
Daniel@0 12780 newValues,
Daniel@0 12781 i;
Daniel@0 12782
Daniel@0 12783 if ( arguments.length > 1 ) {
Daniel@0 12784 this.options.values[ index ] = this._trimAlignValue( newValue );
Daniel@0 12785 this._refreshValue();
Daniel@0 12786 this._change( null, index );
Daniel@0 12787 return;
Daniel@0 12788 }
Daniel@0 12789
Daniel@0 12790 if ( arguments.length ) {
Daniel@0 12791 if ( $.isArray( arguments[ 0 ] ) ) {
Daniel@0 12792 vals = this.options.values;
Daniel@0 12793 newValues = arguments[ 0 ];
Daniel@0 12794 for ( i = 0; i < vals.length; i += 1 ) {
Daniel@0 12795 vals[ i ] = this._trimAlignValue( newValues[ i ] );
Daniel@0 12796 this._change( null, i );
Daniel@0 12797 }
Daniel@0 12798 this._refreshValue();
Daniel@0 12799 } else {
Daniel@0 12800 if ( this.options.values && this.options.values.length ) {
Daniel@0 12801 return this._values( index );
Daniel@0 12802 } else {
Daniel@0 12803 return this.value();
Daniel@0 12804 }
Daniel@0 12805 }
Daniel@0 12806 } else {
Daniel@0 12807 return this._values();
Daniel@0 12808 }
Daniel@0 12809 },
Daniel@0 12810
Daniel@0 12811 _setOption: function( key, value ) {
Daniel@0 12812 var i,
Daniel@0 12813 valsLength = 0;
Daniel@0 12814
Daniel@0 12815 if ( key === "range" && this.options.range === true ) {
Daniel@0 12816 if ( value === "min" ) {
Daniel@0 12817 this.options.value = this._values( 0 );
Daniel@0 12818 this.options.values = null;
Daniel@0 12819 } else if ( value === "max" ) {
Daniel@0 12820 this.options.value = this._values( this.options.values.length - 1 );
Daniel@0 12821 this.options.values = null;
Daniel@0 12822 }
Daniel@0 12823 }
Daniel@0 12824
Daniel@0 12825 if ( $.isArray( this.options.values ) ) {
Daniel@0 12826 valsLength = this.options.values.length;
Daniel@0 12827 }
Daniel@0 12828
Daniel@0 12829 if ( key === "disabled" ) {
Daniel@0 12830 this.element.toggleClass( "ui-state-disabled", !!value );
Daniel@0 12831 }
Daniel@0 12832
Daniel@0 12833 this._super( key, value );
Daniel@0 12834
Daniel@0 12835 switch ( key ) {
Daniel@0 12836 case "orientation":
Daniel@0 12837 this._detectOrientation();
Daniel@0 12838 this.element
Daniel@0 12839 .removeClass( "ui-slider-horizontal ui-slider-vertical" )
Daniel@0 12840 .addClass( "ui-slider-" + this.orientation );
Daniel@0 12841 this._refreshValue();
Daniel@0 12842 break;
Daniel@0 12843 case "value":
Daniel@0 12844 this._animateOff = true;
Daniel@0 12845 this._refreshValue();
Daniel@0 12846 this._change( null, 0 );
Daniel@0 12847 this._animateOff = false;
Daniel@0 12848 break;
Daniel@0 12849 case "values":
Daniel@0 12850 this._animateOff = true;
Daniel@0 12851 this._refreshValue();
Daniel@0 12852 for ( i = 0; i < valsLength; i += 1 ) {
Daniel@0 12853 this._change( null, i );
Daniel@0 12854 }
Daniel@0 12855 this._animateOff = false;
Daniel@0 12856 break;
Daniel@0 12857 case "min":
Daniel@0 12858 case "max":
Daniel@0 12859 this._animateOff = true;
Daniel@0 12860 this._refreshValue();
Daniel@0 12861 this._animateOff = false;
Daniel@0 12862 break;
Daniel@0 12863 case "range":
Daniel@0 12864 this._animateOff = true;
Daniel@0 12865 this._refresh();
Daniel@0 12866 this._animateOff = false;
Daniel@0 12867 break;
Daniel@0 12868 }
Daniel@0 12869 },
Daniel@0 12870
Daniel@0 12871 //internal value getter
Daniel@0 12872 // _value() returns value trimmed by min and max, aligned by step
Daniel@0 12873 _value: function() {
Daniel@0 12874 var val = this.options.value;
Daniel@0 12875 val = this._trimAlignValue( val );
Daniel@0 12876
Daniel@0 12877 return val;
Daniel@0 12878 },
Daniel@0 12879
Daniel@0 12880 //internal values getter
Daniel@0 12881 // _values() returns array of values trimmed by min and max, aligned by step
Daniel@0 12882 // _values( index ) returns single value trimmed by min and max, aligned by step
Daniel@0 12883 _values: function( index ) {
Daniel@0 12884 var val,
Daniel@0 12885 vals,
Daniel@0 12886 i;
Daniel@0 12887
Daniel@0 12888 if ( arguments.length ) {
Daniel@0 12889 val = this.options.values[ index ];
Daniel@0 12890 val = this._trimAlignValue( val );
Daniel@0 12891
Daniel@0 12892 return val;
Daniel@0 12893 } else if ( this.options.values && this.options.values.length ) {
Daniel@0 12894 // .slice() creates a copy of the array
Daniel@0 12895 // this copy gets trimmed by min and max and then returned
Daniel@0 12896 vals = this.options.values.slice();
Daniel@0 12897 for ( i = 0; i < vals.length; i+= 1) {
Daniel@0 12898 vals[ i ] = this._trimAlignValue( vals[ i ] );
Daniel@0 12899 }
Daniel@0 12900
Daniel@0 12901 return vals;
Daniel@0 12902 } else {
Daniel@0 12903 return [];
Daniel@0 12904 }
Daniel@0 12905 },
Daniel@0 12906
Daniel@0 12907 // returns the step-aligned value that val is closest to, between (inclusive) min and max
Daniel@0 12908 _trimAlignValue: function( val ) {
Daniel@0 12909 if ( val <= this._valueMin() ) {
Daniel@0 12910 return this._valueMin();
Daniel@0 12911 }
Daniel@0 12912 if ( val >= this._valueMax() ) {
Daniel@0 12913 return this._valueMax();
Daniel@0 12914 }
Daniel@0 12915 var step = ( this.options.step > 0 ) ? this.options.step : 1,
Daniel@0 12916 valModStep = (val - this._valueMin()) % step,
Daniel@0 12917 alignValue = val - valModStep;
Daniel@0 12918
Daniel@0 12919 if ( Math.abs(valModStep) * 2 >= step ) {
Daniel@0 12920 alignValue += ( valModStep > 0 ) ? step : ( -step );
Daniel@0 12921 }
Daniel@0 12922
Daniel@0 12923 // Since JavaScript has problems with large floats, round
Daniel@0 12924 // the final value to 5 digits after the decimal point (see #4124)
Daniel@0 12925 return parseFloat( alignValue.toFixed(5) );
Daniel@0 12926 },
Daniel@0 12927
Daniel@0 12928 _valueMin: function() {
Daniel@0 12929 return this.options.min;
Daniel@0 12930 },
Daniel@0 12931
Daniel@0 12932 _valueMax: function() {
Daniel@0 12933 return this.options.max;
Daniel@0 12934 },
Daniel@0 12935
Daniel@0 12936 _refreshValue: function() {
Daniel@0 12937 var lastValPercent, valPercent, value, valueMin, valueMax,
Daniel@0 12938 oRange = this.options.range,
Daniel@0 12939 o = this.options,
Daniel@0 12940 that = this,
Daniel@0 12941 animate = ( !this._animateOff ) ? o.animate : false,
Daniel@0 12942 _set = {};
Daniel@0 12943
Daniel@0 12944 if ( this.options.values && this.options.values.length ) {
Daniel@0 12945 this.handles.each(function( i ) {
Daniel@0 12946 valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
Daniel@0 12947 _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
Daniel@0 12948 $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
Daniel@0 12949 if ( that.options.range === true ) {
Daniel@0 12950 if ( that.orientation === "horizontal" ) {
Daniel@0 12951 if ( i === 0 ) {
Daniel@0 12952 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
Daniel@0 12953 }
Daniel@0 12954 if ( i === 1 ) {
Daniel@0 12955 that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
Daniel@0 12956 }
Daniel@0 12957 } else {
Daniel@0 12958 if ( i === 0 ) {
Daniel@0 12959 that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
Daniel@0 12960 }
Daniel@0 12961 if ( i === 1 ) {
Daniel@0 12962 that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
Daniel@0 12963 }
Daniel@0 12964 }
Daniel@0 12965 }
Daniel@0 12966 lastValPercent = valPercent;
Daniel@0 12967 });
Daniel@0 12968 } else {
Daniel@0 12969 value = this.value();
Daniel@0 12970 valueMin = this._valueMin();
Daniel@0 12971 valueMax = this._valueMax();
Daniel@0 12972 valPercent = ( valueMax !== valueMin ) ?
Daniel@0 12973 ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
Daniel@0 12974 0;
Daniel@0 12975 _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
Daniel@0 12976 this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
Daniel@0 12977
Daniel@0 12978 if ( oRange === "min" && this.orientation === "horizontal" ) {
Daniel@0 12979 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
Daniel@0 12980 }
Daniel@0 12981 if ( oRange === "max" && this.orientation === "horizontal" ) {
Daniel@0 12982 this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
Daniel@0 12983 }
Daniel@0 12984 if ( oRange === "min" && this.orientation === "vertical" ) {
Daniel@0 12985 this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
Daniel@0 12986 }
Daniel@0 12987 if ( oRange === "max" && this.orientation === "vertical" ) {
Daniel@0 12988 this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
Daniel@0 12989 }
Daniel@0 12990 }
Daniel@0 12991 },
Daniel@0 12992
Daniel@0 12993 _handleEvents: {
Daniel@0 12994 keydown: function( event ) {
Daniel@0 12995 var allowed, curVal, newVal, step,
Daniel@0 12996 index = $( event.target ).data( "ui-slider-handle-index" );
Daniel@0 12997
Daniel@0 12998 switch ( event.keyCode ) {
Daniel@0 12999 case $.ui.keyCode.HOME:
Daniel@0 13000 case $.ui.keyCode.END:
Daniel@0 13001 case $.ui.keyCode.PAGE_UP:
Daniel@0 13002 case $.ui.keyCode.PAGE_DOWN:
Daniel@0 13003 case $.ui.keyCode.UP:
Daniel@0 13004 case $.ui.keyCode.RIGHT:
Daniel@0 13005 case $.ui.keyCode.DOWN:
Daniel@0 13006 case $.ui.keyCode.LEFT:
Daniel@0 13007 event.preventDefault();
Daniel@0 13008 if ( !this._keySliding ) {
Daniel@0 13009 this._keySliding = true;
Daniel@0 13010 $( event.target ).addClass( "ui-state-active" );
Daniel@0 13011 allowed = this._start( event, index );
Daniel@0 13012 if ( allowed === false ) {
Daniel@0 13013 return;
Daniel@0 13014 }
Daniel@0 13015 }
Daniel@0 13016 break;
Daniel@0 13017 }
Daniel@0 13018
Daniel@0 13019 step = this.options.step;
Daniel@0 13020 if ( this.options.values && this.options.values.length ) {
Daniel@0 13021 curVal = newVal = this.values( index );
Daniel@0 13022 } else {
Daniel@0 13023 curVal = newVal = this.value();
Daniel@0 13024 }
Daniel@0 13025
Daniel@0 13026 switch ( event.keyCode ) {
Daniel@0 13027 case $.ui.keyCode.HOME:
Daniel@0 13028 newVal = this._valueMin();
Daniel@0 13029 break;
Daniel@0 13030 case $.ui.keyCode.END:
Daniel@0 13031 newVal = this._valueMax();
Daniel@0 13032 break;
Daniel@0 13033 case $.ui.keyCode.PAGE_UP:
Daniel@0 13034 newVal = this._trimAlignValue(
Daniel@0 13035 curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
Daniel@0 13036 );
Daniel@0 13037 break;
Daniel@0 13038 case $.ui.keyCode.PAGE_DOWN:
Daniel@0 13039 newVal = this._trimAlignValue(
Daniel@0 13040 curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
Daniel@0 13041 break;
Daniel@0 13042 case $.ui.keyCode.UP:
Daniel@0 13043 case $.ui.keyCode.RIGHT:
Daniel@0 13044 if ( curVal === this._valueMax() ) {
Daniel@0 13045 return;
Daniel@0 13046 }
Daniel@0 13047 newVal = this._trimAlignValue( curVal + step );
Daniel@0 13048 break;
Daniel@0 13049 case $.ui.keyCode.DOWN:
Daniel@0 13050 case $.ui.keyCode.LEFT:
Daniel@0 13051 if ( curVal === this._valueMin() ) {
Daniel@0 13052 return;
Daniel@0 13053 }
Daniel@0 13054 newVal = this._trimAlignValue( curVal - step );
Daniel@0 13055 break;
Daniel@0 13056 }
Daniel@0 13057
Daniel@0 13058 this._slide( event, index, newVal );
Daniel@0 13059 },
Daniel@0 13060 keyup: function( event ) {
Daniel@0 13061 var index = $( event.target ).data( "ui-slider-handle-index" );
Daniel@0 13062
Daniel@0 13063 if ( this._keySliding ) {
Daniel@0 13064 this._keySliding = false;
Daniel@0 13065 this._stop( event, index );
Daniel@0 13066 this._change( event, index );
Daniel@0 13067 $( event.target ).removeClass( "ui-state-active" );
Daniel@0 13068 }
Daniel@0 13069 }
Daniel@0 13070 }
Daniel@0 13071 });
Daniel@0 13072
Daniel@0 13073
Daniel@0 13074 /*!
Daniel@0 13075 * jQuery UI Sortable 1.11.0
Daniel@0 13076 * http://jqueryui.com
Daniel@0 13077 *
Daniel@0 13078 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 13079 * Released under the MIT license.
Daniel@0 13080 * http://jquery.org/license
Daniel@0 13081 *
Daniel@0 13082 * http://api.jqueryui.com/sortable/
Daniel@0 13083 */
Daniel@0 13084
Daniel@0 13085
Daniel@0 13086 var sortable = $.widget("ui.sortable", $.ui.mouse, {
Daniel@0 13087 version: "1.11.0",
Daniel@0 13088 widgetEventPrefix: "sort",
Daniel@0 13089 ready: false,
Daniel@0 13090 options: {
Daniel@0 13091 appendTo: "parent",
Daniel@0 13092 axis: false,
Daniel@0 13093 connectWith: false,
Daniel@0 13094 containment: false,
Daniel@0 13095 cursor: "auto",
Daniel@0 13096 cursorAt: false,
Daniel@0 13097 dropOnEmpty: true,
Daniel@0 13098 forcePlaceholderSize: false,
Daniel@0 13099 forceHelperSize: false,
Daniel@0 13100 grid: false,
Daniel@0 13101 handle: false,
Daniel@0 13102 helper: "original",
Daniel@0 13103 items: "> *",
Daniel@0 13104 opacity: false,
Daniel@0 13105 placeholder: false,
Daniel@0 13106 revert: false,
Daniel@0 13107 scroll: true,
Daniel@0 13108 scrollSensitivity: 20,
Daniel@0 13109 scrollSpeed: 20,
Daniel@0 13110 scope: "default",
Daniel@0 13111 tolerance: "intersect",
Daniel@0 13112 zIndex: 1000,
Daniel@0 13113
Daniel@0 13114 // callbacks
Daniel@0 13115 activate: null,
Daniel@0 13116 beforeStop: null,
Daniel@0 13117 change: null,
Daniel@0 13118 deactivate: null,
Daniel@0 13119 out: null,
Daniel@0 13120 over: null,
Daniel@0 13121 receive: null,
Daniel@0 13122 remove: null,
Daniel@0 13123 sort: null,
Daniel@0 13124 start: null,
Daniel@0 13125 stop: null,
Daniel@0 13126 update: null
Daniel@0 13127 },
Daniel@0 13128
Daniel@0 13129 _isOverAxis: function( x, reference, size ) {
Daniel@0 13130 return ( x >= reference ) && ( x < ( reference + size ) );
Daniel@0 13131 },
Daniel@0 13132
Daniel@0 13133 _isFloating: function( item ) {
Daniel@0 13134 return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
Daniel@0 13135 },
Daniel@0 13136
Daniel@0 13137 _create: function() {
Daniel@0 13138
Daniel@0 13139 var o = this.options;
Daniel@0 13140 this.containerCache = {};
Daniel@0 13141 this.element.addClass("ui-sortable");
Daniel@0 13142
Daniel@0 13143 //Get the items
Daniel@0 13144 this.refresh();
Daniel@0 13145
Daniel@0 13146 //Let's determine if the items are being displayed horizontally
Daniel@0 13147 this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false;
Daniel@0 13148
Daniel@0 13149 //Let's determine the parent's offset
Daniel@0 13150 this.offset = this.element.offset();
Daniel@0 13151
Daniel@0 13152 //Initialize mouse events for interaction
Daniel@0 13153 this._mouseInit();
Daniel@0 13154
Daniel@0 13155 this._setHandleClassName();
Daniel@0 13156
Daniel@0 13157 //We're ready to go
Daniel@0 13158 this.ready = true;
Daniel@0 13159
Daniel@0 13160 },
Daniel@0 13161
Daniel@0 13162 _setOption: function( key, value ) {
Daniel@0 13163 this._super( key, value );
Daniel@0 13164
Daniel@0 13165 if ( key === "handle" ) {
Daniel@0 13166 this._setHandleClassName();
Daniel@0 13167 }
Daniel@0 13168 },
Daniel@0 13169
Daniel@0 13170 _setHandleClassName: function() {
Daniel@0 13171 this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
Daniel@0 13172 $.each( this.items, function() {
Daniel@0 13173 ( this.instance.options.handle ?
Daniel@0 13174 this.item.find( this.instance.options.handle ) : this.item )
Daniel@0 13175 .addClass( "ui-sortable-handle" );
Daniel@0 13176 });
Daniel@0 13177 },
Daniel@0 13178
Daniel@0 13179 _destroy: function() {
Daniel@0 13180 this.element
Daniel@0 13181 .removeClass( "ui-sortable ui-sortable-disabled" )
Daniel@0 13182 .find( ".ui-sortable-handle" )
Daniel@0 13183 .removeClass( "ui-sortable-handle" );
Daniel@0 13184 this._mouseDestroy();
Daniel@0 13185
Daniel@0 13186 for ( var i = this.items.length - 1; i >= 0; i-- ) {
Daniel@0 13187 this.items[i].item.removeData(this.widgetName + "-item");
Daniel@0 13188 }
Daniel@0 13189
Daniel@0 13190 return this;
Daniel@0 13191 },
Daniel@0 13192
Daniel@0 13193 _mouseCapture: function(event, overrideHandle) {
Daniel@0 13194 var currentItem = null,
Daniel@0 13195 validHandle = false,
Daniel@0 13196 that = this;
Daniel@0 13197
Daniel@0 13198 if (this.reverting) {
Daniel@0 13199 return false;
Daniel@0 13200 }
Daniel@0 13201
Daniel@0 13202 if(this.options.disabled || this.options.type === "static") {
Daniel@0 13203 return false;
Daniel@0 13204 }
Daniel@0 13205
Daniel@0 13206 //We have to refresh the items data once first
Daniel@0 13207 this._refreshItems(event);
Daniel@0 13208
Daniel@0 13209 //Find out if the clicked node (or one of its parents) is a actual item in this.items
Daniel@0 13210 $(event.target).parents().each(function() {
Daniel@0 13211 if($.data(this, that.widgetName + "-item") === that) {
Daniel@0 13212 currentItem = $(this);
Daniel@0 13213 return false;
Daniel@0 13214 }
Daniel@0 13215 });
Daniel@0 13216 if($.data(event.target, that.widgetName + "-item") === that) {
Daniel@0 13217 currentItem = $(event.target);
Daniel@0 13218 }
Daniel@0 13219
Daniel@0 13220 if(!currentItem) {
Daniel@0 13221 return false;
Daniel@0 13222 }
Daniel@0 13223 if(this.options.handle && !overrideHandle) {
Daniel@0 13224 $(this.options.handle, currentItem).find("*").addBack().each(function() {
Daniel@0 13225 if(this === event.target) {
Daniel@0 13226 validHandle = true;
Daniel@0 13227 }
Daniel@0 13228 });
Daniel@0 13229 if(!validHandle) {
Daniel@0 13230 return false;
Daniel@0 13231 }
Daniel@0 13232 }
Daniel@0 13233
Daniel@0 13234 this.currentItem = currentItem;
Daniel@0 13235 this._removeCurrentsFromItems();
Daniel@0 13236 return true;
Daniel@0 13237
Daniel@0 13238 },
Daniel@0 13239
Daniel@0 13240 _mouseStart: function(event, overrideHandle, noActivation) {
Daniel@0 13241
Daniel@0 13242 var i, body,
Daniel@0 13243 o = this.options;
Daniel@0 13244
Daniel@0 13245 this.currentContainer = this;
Daniel@0 13246
Daniel@0 13247 //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
Daniel@0 13248 this.refreshPositions();
Daniel@0 13249
Daniel@0 13250 //Create and append the visible helper
Daniel@0 13251 this.helper = this._createHelper(event);
Daniel@0 13252
Daniel@0 13253 //Cache the helper size
Daniel@0 13254 this._cacheHelperProportions();
Daniel@0 13255
Daniel@0 13256 /*
Daniel@0 13257 * - Position generation -
Daniel@0 13258 * This block generates everything position related - it's the core of draggables.
Daniel@0 13259 */
Daniel@0 13260
Daniel@0 13261 //Cache the margins of the original element
Daniel@0 13262 this._cacheMargins();
Daniel@0 13263
Daniel@0 13264 //Get the next scrolling parent
Daniel@0 13265 this.scrollParent = this.helper.scrollParent();
Daniel@0 13266
Daniel@0 13267 //The element's absolute position on the page minus margins
Daniel@0 13268 this.offset = this.currentItem.offset();
Daniel@0 13269 this.offset = {
Daniel@0 13270 top: this.offset.top - this.margins.top,
Daniel@0 13271 left: this.offset.left - this.margins.left
Daniel@0 13272 };
Daniel@0 13273
Daniel@0 13274 $.extend(this.offset, {
Daniel@0 13275 click: { //Where the click happened, relative to the element
Daniel@0 13276 left: event.pageX - this.offset.left,
Daniel@0 13277 top: event.pageY - this.offset.top
Daniel@0 13278 },
Daniel@0 13279 parent: this._getParentOffset(),
Daniel@0 13280 relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
Daniel@0 13281 });
Daniel@0 13282
Daniel@0 13283 // Only after we got the offset, we can change the helper's position to absolute
Daniel@0 13284 // TODO: Still need to figure out a way to make relative sorting possible
Daniel@0 13285 this.helper.css("position", "absolute");
Daniel@0 13286 this.cssPosition = this.helper.css("position");
Daniel@0 13287
Daniel@0 13288 //Generate the original position
Daniel@0 13289 this.originalPosition = this._generatePosition(event);
Daniel@0 13290 this.originalPageX = event.pageX;
Daniel@0 13291 this.originalPageY = event.pageY;
Daniel@0 13292
Daniel@0 13293 //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
Daniel@0 13294 (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
Daniel@0 13295
Daniel@0 13296 //Cache the former DOM position
Daniel@0 13297 this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
Daniel@0 13298
Daniel@0 13299 //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
Daniel@0 13300 if(this.helper[0] !== this.currentItem[0]) {
Daniel@0 13301 this.currentItem.hide();
Daniel@0 13302 }
Daniel@0 13303
Daniel@0 13304 //Create the placeholder
Daniel@0 13305 this._createPlaceholder();
Daniel@0 13306
Daniel@0 13307 //Set a containment if given in the options
Daniel@0 13308 if(o.containment) {
Daniel@0 13309 this._setContainment();
Daniel@0 13310 }
Daniel@0 13311
Daniel@0 13312 if( o.cursor && o.cursor !== "auto" ) { // cursor option
Daniel@0 13313 body = this.document.find( "body" );
Daniel@0 13314
Daniel@0 13315 // support: IE
Daniel@0 13316 this.storedCursor = body.css( "cursor" );
Daniel@0 13317 body.css( "cursor", o.cursor );
Daniel@0 13318
Daniel@0 13319 this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
Daniel@0 13320 }
Daniel@0 13321
Daniel@0 13322 if(o.opacity) { // opacity option
Daniel@0 13323 if (this.helper.css("opacity")) {
Daniel@0 13324 this._storedOpacity = this.helper.css("opacity");
Daniel@0 13325 }
Daniel@0 13326 this.helper.css("opacity", o.opacity);
Daniel@0 13327 }
Daniel@0 13328
Daniel@0 13329 if(o.zIndex) { // zIndex option
Daniel@0 13330 if (this.helper.css("zIndex")) {
Daniel@0 13331 this._storedZIndex = this.helper.css("zIndex");
Daniel@0 13332 }
Daniel@0 13333 this.helper.css("zIndex", o.zIndex);
Daniel@0 13334 }
Daniel@0 13335
Daniel@0 13336 //Prepare scrolling
Daniel@0 13337 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
Daniel@0 13338 this.overflowOffset = this.scrollParent.offset();
Daniel@0 13339 }
Daniel@0 13340
Daniel@0 13341 //Call callbacks
Daniel@0 13342 this._trigger("start", event, this._uiHash());
Daniel@0 13343
Daniel@0 13344 //Recache the helper size
Daniel@0 13345 if(!this._preserveHelperProportions) {
Daniel@0 13346 this._cacheHelperProportions();
Daniel@0 13347 }
Daniel@0 13348
Daniel@0 13349
Daniel@0 13350 //Post "activate" events to possible containers
Daniel@0 13351 if( !noActivation ) {
Daniel@0 13352 for ( i = this.containers.length - 1; i >= 0; i-- ) {
Daniel@0 13353 this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
Daniel@0 13354 }
Daniel@0 13355 }
Daniel@0 13356
Daniel@0 13357 //Prepare possible droppables
Daniel@0 13358 if($.ui.ddmanager) {
Daniel@0 13359 $.ui.ddmanager.current = this;
Daniel@0 13360 }
Daniel@0 13361
Daniel@0 13362 if ($.ui.ddmanager && !o.dropBehaviour) {
Daniel@0 13363 $.ui.ddmanager.prepareOffsets(this, event);
Daniel@0 13364 }
Daniel@0 13365
Daniel@0 13366 this.dragging = true;
Daniel@0 13367
Daniel@0 13368 this.helper.addClass("ui-sortable-helper");
Daniel@0 13369 this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
Daniel@0 13370 return true;
Daniel@0 13371
Daniel@0 13372 },
Daniel@0 13373
Daniel@0 13374 _mouseDrag: function(event) {
Daniel@0 13375 var i, item, itemElement, intersection,
Daniel@0 13376 o = this.options,
Daniel@0 13377 scrolled = false;
Daniel@0 13378
Daniel@0 13379 //Compute the helpers position
Daniel@0 13380 this.position = this._generatePosition(event);
Daniel@0 13381 this.positionAbs = this._convertPositionTo("absolute");
Daniel@0 13382
Daniel@0 13383 if (!this.lastPositionAbs) {
Daniel@0 13384 this.lastPositionAbs = this.positionAbs;
Daniel@0 13385 }
Daniel@0 13386
Daniel@0 13387 //Do scrolling
Daniel@0 13388 if(this.options.scroll) {
Daniel@0 13389 if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
Daniel@0 13390
Daniel@0 13391 if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
Daniel@0 13392 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
Daniel@0 13393 } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
Daniel@0 13394 this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
Daniel@0 13395 }
Daniel@0 13396
Daniel@0 13397 if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
Daniel@0 13398 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
Daniel@0 13399 } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
Daniel@0 13400 this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
Daniel@0 13401 }
Daniel@0 13402
Daniel@0 13403 } else {
Daniel@0 13404
Daniel@0 13405 if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
Daniel@0 13406 scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
Daniel@0 13407 } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
Daniel@0 13408 scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
Daniel@0 13409 }
Daniel@0 13410
Daniel@0 13411 if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
Daniel@0 13412 scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
Daniel@0 13413 } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
Daniel@0 13414 scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
Daniel@0 13415 }
Daniel@0 13416
Daniel@0 13417 }
Daniel@0 13418
Daniel@0 13419 if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
Daniel@0 13420 $.ui.ddmanager.prepareOffsets(this, event);
Daniel@0 13421 }
Daniel@0 13422 }
Daniel@0 13423
Daniel@0 13424 //Regenerate the absolute position used for position checks
Daniel@0 13425 this.positionAbs = this._convertPositionTo("absolute");
Daniel@0 13426
Daniel@0 13427 //Set the helper position
Daniel@0 13428 if(!this.options.axis || this.options.axis !== "y") {
Daniel@0 13429 this.helper[0].style.left = this.position.left+"px";
Daniel@0 13430 }
Daniel@0 13431 if(!this.options.axis || this.options.axis !== "x") {
Daniel@0 13432 this.helper[0].style.top = this.position.top+"px";
Daniel@0 13433 }
Daniel@0 13434
Daniel@0 13435 //Rearrange
Daniel@0 13436 for (i = this.items.length - 1; i >= 0; i--) {
Daniel@0 13437
Daniel@0 13438 //Cache variables and intersection, continue if no intersection
Daniel@0 13439 item = this.items[i];
Daniel@0 13440 itemElement = item.item[0];
Daniel@0 13441 intersection = this._intersectsWithPointer(item);
Daniel@0 13442 if (!intersection) {
Daniel@0 13443 continue;
Daniel@0 13444 }
Daniel@0 13445
Daniel@0 13446 // Only put the placeholder inside the current Container, skip all
Daniel@0 13447 // items from other containers. This works because when moving
Daniel@0 13448 // an item from one container to another the
Daniel@0 13449 // currentContainer is switched before the placeholder is moved.
Daniel@0 13450 //
Daniel@0 13451 // Without this, moving items in "sub-sortables" can cause
Daniel@0 13452 // the placeholder to jitter between the outer and inner container.
Daniel@0 13453 if (item.instance !== this.currentContainer) {
Daniel@0 13454 continue;
Daniel@0 13455 }
Daniel@0 13456
Daniel@0 13457 // cannot intersect with itself
Daniel@0 13458 // no useless actions that have been done before
Daniel@0 13459 // no action if the item moved is the parent of the item checked
Daniel@0 13460 if (itemElement !== this.currentItem[0] &&
Daniel@0 13461 this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
Daniel@0 13462 !$.contains(this.placeholder[0], itemElement) &&
Daniel@0 13463 (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
Daniel@0 13464 ) {
Daniel@0 13465
Daniel@0 13466 this.direction = intersection === 1 ? "down" : "up";
Daniel@0 13467
Daniel@0 13468 if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
Daniel@0 13469 this._rearrange(event, item);
Daniel@0 13470 } else {
Daniel@0 13471 break;
Daniel@0 13472 }
Daniel@0 13473
Daniel@0 13474 this._trigger("change", event, this._uiHash());
Daniel@0 13475 break;
Daniel@0 13476 }
Daniel@0 13477 }
Daniel@0 13478
Daniel@0 13479 //Post events to containers
Daniel@0 13480 this._contactContainers(event);
Daniel@0 13481
Daniel@0 13482 //Interconnect with droppables
Daniel@0 13483 if($.ui.ddmanager) {
Daniel@0 13484 $.ui.ddmanager.drag(this, event);
Daniel@0 13485 }
Daniel@0 13486
Daniel@0 13487 //Call callbacks
Daniel@0 13488 this._trigger("sort", event, this._uiHash());
Daniel@0 13489
Daniel@0 13490 this.lastPositionAbs = this.positionAbs;
Daniel@0 13491 return false;
Daniel@0 13492
Daniel@0 13493 },
Daniel@0 13494
Daniel@0 13495 _mouseStop: function(event, noPropagation) {
Daniel@0 13496
Daniel@0 13497 if(!event) {
Daniel@0 13498 return;
Daniel@0 13499 }
Daniel@0 13500
Daniel@0 13501 //If we are using droppables, inform the manager about the drop
Daniel@0 13502 if ($.ui.ddmanager && !this.options.dropBehaviour) {
Daniel@0 13503 $.ui.ddmanager.drop(this, event);
Daniel@0 13504 }
Daniel@0 13505
Daniel@0 13506 if(this.options.revert) {
Daniel@0 13507 var that = this,
Daniel@0 13508 cur = this.placeholder.offset(),
Daniel@0 13509 axis = this.options.axis,
Daniel@0 13510 animation = {};
Daniel@0 13511
Daniel@0 13512 if ( !axis || axis === "x" ) {
Daniel@0 13513 animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
Daniel@0 13514 }
Daniel@0 13515 if ( !axis || axis === "y" ) {
Daniel@0 13516 animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
Daniel@0 13517 }
Daniel@0 13518 this.reverting = true;
Daniel@0 13519 $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
Daniel@0 13520 that._clear(event);
Daniel@0 13521 });
Daniel@0 13522 } else {
Daniel@0 13523 this._clear(event, noPropagation);
Daniel@0 13524 }
Daniel@0 13525
Daniel@0 13526 return false;
Daniel@0 13527
Daniel@0 13528 },
Daniel@0 13529
Daniel@0 13530 cancel: function() {
Daniel@0 13531
Daniel@0 13532 if(this.dragging) {
Daniel@0 13533
Daniel@0 13534 this._mouseUp({ target: null });
Daniel@0 13535
Daniel@0 13536 if(this.options.helper === "original") {
Daniel@0 13537 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
Daniel@0 13538 } else {
Daniel@0 13539 this.currentItem.show();
Daniel@0 13540 }
Daniel@0 13541
Daniel@0 13542 //Post deactivating events to containers
Daniel@0 13543 for (var i = this.containers.length - 1; i >= 0; i--){
Daniel@0 13544 this.containers[i]._trigger("deactivate", null, this._uiHash(this));
Daniel@0 13545 if(this.containers[i].containerCache.over) {
Daniel@0 13546 this.containers[i]._trigger("out", null, this._uiHash(this));
Daniel@0 13547 this.containers[i].containerCache.over = 0;
Daniel@0 13548 }
Daniel@0 13549 }
Daniel@0 13550
Daniel@0 13551 }
Daniel@0 13552
Daniel@0 13553 if (this.placeholder) {
Daniel@0 13554 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
Daniel@0 13555 if(this.placeholder[0].parentNode) {
Daniel@0 13556 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
Daniel@0 13557 }
Daniel@0 13558 if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
Daniel@0 13559 this.helper.remove();
Daniel@0 13560 }
Daniel@0 13561
Daniel@0 13562 $.extend(this, {
Daniel@0 13563 helper: null,
Daniel@0 13564 dragging: false,
Daniel@0 13565 reverting: false,
Daniel@0 13566 _noFinalSort: null
Daniel@0 13567 });
Daniel@0 13568
Daniel@0 13569 if(this.domPosition.prev) {
Daniel@0 13570 $(this.domPosition.prev).after(this.currentItem);
Daniel@0 13571 } else {
Daniel@0 13572 $(this.domPosition.parent).prepend(this.currentItem);
Daniel@0 13573 }
Daniel@0 13574 }
Daniel@0 13575
Daniel@0 13576 return this;
Daniel@0 13577
Daniel@0 13578 },
Daniel@0 13579
Daniel@0 13580 serialize: function(o) {
Daniel@0 13581
Daniel@0 13582 var items = this._getItemsAsjQuery(o && o.connected),
Daniel@0 13583 str = [];
Daniel@0 13584 o = o || {};
Daniel@0 13585
Daniel@0 13586 $(items).each(function() {
Daniel@0 13587 var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
Daniel@0 13588 if (res) {
Daniel@0 13589 str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
Daniel@0 13590 }
Daniel@0 13591 });
Daniel@0 13592
Daniel@0 13593 if(!str.length && o.key) {
Daniel@0 13594 str.push(o.key + "=");
Daniel@0 13595 }
Daniel@0 13596
Daniel@0 13597 return str.join("&");
Daniel@0 13598
Daniel@0 13599 },
Daniel@0 13600
Daniel@0 13601 toArray: function(o) {
Daniel@0 13602
Daniel@0 13603 var items = this._getItemsAsjQuery(o && o.connected),
Daniel@0 13604 ret = [];
Daniel@0 13605
Daniel@0 13606 o = o || {};
Daniel@0 13607
Daniel@0 13608 items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
Daniel@0 13609 return ret;
Daniel@0 13610
Daniel@0 13611 },
Daniel@0 13612
Daniel@0 13613 /* Be careful with the following core functions */
Daniel@0 13614 _intersectsWith: function(item) {
Daniel@0 13615
Daniel@0 13616 var x1 = this.positionAbs.left,
Daniel@0 13617 x2 = x1 + this.helperProportions.width,
Daniel@0 13618 y1 = this.positionAbs.top,
Daniel@0 13619 y2 = y1 + this.helperProportions.height,
Daniel@0 13620 l = item.left,
Daniel@0 13621 r = l + item.width,
Daniel@0 13622 t = item.top,
Daniel@0 13623 b = t + item.height,
Daniel@0 13624 dyClick = this.offset.click.top,
Daniel@0 13625 dxClick = this.offset.click.left,
Daniel@0 13626 isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
Daniel@0 13627 isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
Daniel@0 13628 isOverElement = isOverElementHeight && isOverElementWidth;
Daniel@0 13629
Daniel@0 13630 if ( this.options.tolerance === "pointer" ||
Daniel@0 13631 this.options.forcePointerForContainers ||
Daniel@0 13632 (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
Daniel@0 13633 ) {
Daniel@0 13634 return isOverElement;
Daniel@0 13635 } else {
Daniel@0 13636
Daniel@0 13637 return (l < x1 + (this.helperProportions.width / 2) && // Right Half
Daniel@0 13638 x2 - (this.helperProportions.width / 2) < r && // Left Half
Daniel@0 13639 t < y1 + (this.helperProportions.height / 2) && // Bottom Half
Daniel@0 13640 y2 - (this.helperProportions.height / 2) < b ); // Top Half
Daniel@0 13641
Daniel@0 13642 }
Daniel@0 13643 },
Daniel@0 13644
Daniel@0 13645 _intersectsWithPointer: function(item) {
Daniel@0 13646
Daniel@0 13647 var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
Daniel@0 13648 isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
Daniel@0 13649 isOverElement = isOverElementHeight && isOverElementWidth,
Daniel@0 13650 verticalDirection = this._getDragVerticalDirection(),
Daniel@0 13651 horizontalDirection = this._getDragHorizontalDirection();
Daniel@0 13652
Daniel@0 13653 if (!isOverElement) {
Daniel@0 13654 return false;
Daniel@0 13655 }
Daniel@0 13656
Daniel@0 13657 return this.floating ?
Daniel@0 13658 ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
Daniel@0 13659 : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
Daniel@0 13660
Daniel@0 13661 },
Daniel@0 13662
Daniel@0 13663 _intersectsWithSides: function(item) {
Daniel@0 13664
Daniel@0 13665 var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
Daniel@0 13666 isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
Daniel@0 13667 verticalDirection = this._getDragVerticalDirection(),
Daniel@0 13668 horizontalDirection = this._getDragHorizontalDirection();
Daniel@0 13669
Daniel@0 13670 if (this.floating && horizontalDirection) {
Daniel@0 13671 return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
Daniel@0 13672 } else {
Daniel@0 13673 return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
Daniel@0 13674 }
Daniel@0 13675
Daniel@0 13676 },
Daniel@0 13677
Daniel@0 13678 _getDragVerticalDirection: function() {
Daniel@0 13679 var delta = this.positionAbs.top - this.lastPositionAbs.top;
Daniel@0 13680 return delta !== 0 && (delta > 0 ? "down" : "up");
Daniel@0 13681 },
Daniel@0 13682
Daniel@0 13683 _getDragHorizontalDirection: function() {
Daniel@0 13684 var delta = this.positionAbs.left - this.lastPositionAbs.left;
Daniel@0 13685 return delta !== 0 && (delta > 0 ? "right" : "left");
Daniel@0 13686 },
Daniel@0 13687
Daniel@0 13688 refresh: function(event) {
Daniel@0 13689 this._refreshItems(event);
Daniel@0 13690 this._setHandleClassName();
Daniel@0 13691 this.refreshPositions();
Daniel@0 13692 return this;
Daniel@0 13693 },
Daniel@0 13694
Daniel@0 13695 _connectWith: function() {
Daniel@0 13696 var options = this.options;
Daniel@0 13697 return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
Daniel@0 13698 },
Daniel@0 13699
Daniel@0 13700 _getItemsAsjQuery: function(connected) {
Daniel@0 13701
Daniel@0 13702 var i, j, cur, inst,
Daniel@0 13703 items = [],
Daniel@0 13704 queries = [],
Daniel@0 13705 connectWith = this._connectWith();
Daniel@0 13706
Daniel@0 13707 if(connectWith && connected) {
Daniel@0 13708 for (i = connectWith.length - 1; i >= 0; i--){
Daniel@0 13709 cur = $(connectWith[i]);
Daniel@0 13710 for ( j = cur.length - 1; j >= 0; j--){
Daniel@0 13711 inst = $.data(cur[j], this.widgetFullName);
Daniel@0 13712 if(inst && inst !== this && !inst.options.disabled) {
Daniel@0 13713 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]);
Daniel@0 13714 }
Daniel@0 13715 }
Daniel@0 13716 }
Daniel@0 13717 }
Daniel@0 13718
Daniel@0 13719 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]);
Daniel@0 13720
Daniel@0 13721 function addItems() {
Daniel@0 13722 items.push( this );
Daniel@0 13723 }
Daniel@0 13724 for (i = queries.length - 1; i >= 0; i--){
Daniel@0 13725 queries[i][0].each( addItems );
Daniel@0 13726 }
Daniel@0 13727
Daniel@0 13728 return $(items);
Daniel@0 13729
Daniel@0 13730 },
Daniel@0 13731
Daniel@0 13732 _removeCurrentsFromItems: function() {
Daniel@0 13733
Daniel@0 13734 var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
Daniel@0 13735
Daniel@0 13736 this.items = $.grep(this.items, function (item) {
Daniel@0 13737 for (var j=0; j < list.length; j++) {
Daniel@0 13738 if(list[j] === item.item[0]) {
Daniel@0 13739 return false;
Daniel@0 13740 }
Daniel@0 13741 }
Daniel@0 13742 return true;
Daniel@0 13743 });
Daniel@0 13744
Daniel@0 13745 },
Daniel@0 13746
Daniel@0 13747 _refreshItems: function(event) {
Daniel@0 13748
Daniel@0 13749 this.items = [];
Daniel@0 13750 this.containers = [this];
Daniel@0 13751
Daniel@0 13752 var i, j, cur, inst, targetData, _queries, item, queriesLength,
Daniel@0 13753 items = this.items,
Daniel@0 13754 queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
Daniel@0 13755 connectWith = this._connectWith();
Daniel@0 13756
Daniel@0 13757 if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
Daniel@0 13758 for (i = connectWith.length - 1; i >= 0; i--){
Daniel@0 13759 cur = $(connectWith[i]);
Daniel@0 13760 for (j = cur.length - 1; j >= 0; j--){
Daniel@0 13761 inst = $.data(cur[j], this.widgetFullName);
Daniel@0 13762 if(inst && inst !== this && !inst.options.disabled) {
Daniel@0 13763 queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
Daniel@0 13764 this.containers.push(inst);
Daniel@0 13765 }
Daniel@0 13766 }
Daniel@0 13767 }
Daniel@0 13768 }
Daniel@0 13769
Daniel@0 13770 for (i = queries.length - 1; i >= 0; i--) {
Daniel@0 13771 targetData = queries[i][1];
Daniel@0 13772 _queries = queries[i][0];
Daniel@0 13773
Daniel@0 13774 for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
Daniel@0 13775 item = $(_queries[j]);
Daniel@0 13776
Daniel@0 13777 item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
Daniel@0 13778
Daniel@0 13779 items.push({
Daniel@0 13780 item: item,
Daniel@0 13781 instance: targetData,
Daniel@0 13782 width: 0, height: 0,
Daniel@0 13783 left: 0, top: 0
Daniel@0 13784 });
Daniel@0 13785 }
Daniel@0 13786 }
Daniel@0 13787
Daniel@0 13788 },
Daniel@0 13789
Daniel@0 13790 refreshPositions: function(fast) {
Daniel@0 13791
Daniel@0 13792 //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
Daniel@0 13793 if(this.offsetParent && this.helper) {
Daniel@0 13794 this.offset.parent = this._getParentOffset();
Daniel@0 13795 }
Daniel@0 13796
Daniel@0 13797 var i, item, t, p;
Daniel@0 13798
Daniel@0 13799 for (i = this.items.length - 1; i >= 0; i--){
Daniel@0 13800 item = this.items[i];
Daniel@0 13801
Daniel@0 13802 //We ignore calculating positions of all connected containers when we're not over them
Daniel@0 13803 if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
Daniel@0 13804 continue;
Daniel@0 13805 }
Daniel@0 13806
Daniel@0 13807 t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
Daniel@0 13808
Daniel@0 13809 if (!fast) {
Daniel@0 13810 item.width = t.outerWidth();
Daniel@0 13811 item.height = t.outerHeight();
Daniel@0 13812 }
Daniel@0 13813
Daniel@0 13814 p = t.offset();
Daniel@0 13815 item.left = p.left;
Daniel@0 13816 item.top = p.top;
Daniel@0 13817 }
Daniel@0 13818
Daniel@0 13819 if(this.options.custom && this.options.custom.refreshContainers) {
Daniel@0 13820 this.options.custom.refreshContainers.call(this);
Daniel@0 13821 } else {
Daniel@0 13822 for (i = this.containers.length - 1; i >= 0; i--){
Daniel@0 13823 p = this.containers[i].element.offset();
Daniel@0 13824 this.containers[i].containerCache.left = p.left;
Daniel@0 13825 this.containers[i].containerCache.top = p.top;
Daniel@0 13826 this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
Daniel@0 13827 this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
Daniel@0 13828 }
Daniel@0 13829 }
Daniel@0 13830
Daniel@0 13831 return this;
Daniel@0 13832 },
Daniel@0 13833
Daniel@0 13834 _createPlaceholder: function(that) {
Daniel@0 13835 that = that || this;
Daniel@0 13836 var className,
Daniel@0 13837 o = that.options;
Daniel@0 13838
Daniel@0 13839 if(!o.placeholder || o.placeholder.constructor === String) {
Daniel@0 13840 className = o.placeholder;
Daniel@0 13841 o.placeholder = {
Daniel@0 13842 element: function() {
Daniel@0 13843
Daniel@0 13844 var nodeName = that.currentItem[0].nodeName.toLowerCase(),
Daniel@0 13845 element = $( "<" + nodeName + ">", that.document[0] )
Daniel@0 13846 .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
Daniel@0 13847 .removeClass("ui-sortable-helper");
Daniel@0 13848
Daniel@0 13849 if ( nodeName === "tr" ) {
Daniel@0 13850 that.currentItem.children().each(function() {
Daniel@0 13851 $( "<td>&#160;</td>", that.document[0] )
Daniel@0 13852 .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
Daniel@0 13853 .appendTo( element );
Daniel@0 13854 });
Daniel@0 13855 } else if ( nodeName === "img" ) {
Daniel@0 13856 element.attr( "src", that.currentItem.attr( "src" ) );
Daniel@0 13857 }
Daniel@0 13858
Daniel@0 13859 if ( !className ) {
Daniel@0 13860 element.css( "visibility", "hidden" );
Daniel@0 13861 }
Daniel@0 13862
Daniel@0 13863 return element;
Daniel@0 13864 },
Daniel@0 13865 update: function(container, p) {
Daniel@0 13866
Daniel@0 13867 // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
Daniel@0 13868 // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
Daniel@0 13869 if(className && !o.forcePlaceholderSize) {
Daniel@0 13870 return;
Daniel@0 13871 }
Daniel@0 13872
Daniel@0 13873 //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
Daniel@0 13874 if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
Daniel@0 13875 if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
Daniel@0 13876 }
Daniel@0 13877 };
Daniel@0 13878 }
Daniel@0 13879
Daniel@0 13880 //Create the placeholder
Daniel@0 13881 that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
Daniel@0 13882
Daniel@0 13883 //Append it after the actual current item
Daniel@0 13884 that.currentItem.after(that.placeholder);
Daniel@0 13885
Daniel@0 13886 //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
Daniel@0 13887 o.placeholder.update(that, that.placeholder);
Daniel@0 13888
Daniel@0 13889 },
Daniel@0 13890
Daniel@0 13891 _contactContainers: function(event) {
Daniel@0 13892 var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
Daniel@0 13893 innermostContainer = null,
Daniel@0 13894 innermostIndex = null;
Daniel@0 13895
Daniel@0 13896 // get innermost container that intersects with item
Daniel@0 13897 for (i = this.containers.length - 1; i >= 0; i--) {
Daniel@0 13898
Daniel@0 13899 // never consider a container that's located within the item itself
Daniel@0 13900 if($.contains(this.currentItem[0], this.containers[i].element[0])) {
Daniel@0 13901 continue;
Daniel@0 13902 }
Daniel@0 13903
Daniel@0 13904 if(this._intersectsWith(this.containers[i].containerCache)) {
Daniel@0 13905
Daniel@0 13906 // if we've already found a container and it's more "inner" than this, then continue
Daniel@0 13907 if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
Daniel@0 13908 continue;
Daniel@0 13909 }
Daniel@0 13910
Daniel@0 13911 innermostContainer = this.containers[i];
Daniel@0 13912 innermostIndex = i;
Daniel@0 13913
Daniel@0 13914 } else {
Daniel@0 13915 // container doesn't intersect. trigger "out" event if necessary
Daniel@0 13916 if(this.containers[i].containerCache.over) {
Daniel@0 13917 this.containers[i]._trigger("out", event, this._uiHash(this));
Daniel@0 13918 this.containers[i].containerCache.over = 0;
Daniel@0 13919 }
Daniel@0 13920 }
Daniel@0 13921
Daniel@0 13922 }
Daniel@0 13923
Daniel@0 13924 // if no intersecting containers found, return
Daniel@0 13925 if(!innermostContainer) {
Daniel@0 13926 return;
Daniel@0 13927 }
Daniel@0 13928
Daniel@0 13929 // move the item into the container if it's not there already
Daniel@0 13930 if(this.containers.length === 1) {
Daniel@0 13931 if (!this.containers[innermostIndex].containerCache.over) {
Daniel@0 13932 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
Daniel@0 13933 this.containers[innermostIndex].containerCache.over = 1;
Daniel@0 13934 }
Daniel@0 13935 } else {
Daniel@0 13936
Daniel@0 13937 //When entering a new container, we will find the item with the least distance and append our item near it
Daniel@0 13938 dist = 10000;
Daniel@0 13939 itemWithLeastDistance = null;
Daniel@0 13940 floating = innermostContainer.floating || this._isFloating(this.currentItem);
Daniel@0 13941 posProperty = floating ? "left" : "top";
Daniel@0 13942 sizeProperty = floating ? "width" : "height";
Daniel@0 13943 axis = floating ? "clientX" : "clientY";
Daniel@0 13944
Daniel@0 13945 for (j = this.items.length - 1; j >= 0; j--) {
Daniel@0 13946 if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
Daniel@0 13947 continue;
Daniel@0 13948 }
Daniel@0 13949 if(this.items[j].item[0] === this.currentItem[0]) {
Daniel@0 13950 continue;
Daniel@0 13951 }
Daniel@0 13952
Daniel@0 13953 cur = this.items[j].item.offset()[posProperty];
Daniel@0 13954 nearBottom = false;
Daniel@0 13955 if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
Daniel@0 13956 nearBottom = true;
Daniel@0 13957 }
Daniel@0 13958
Daniel@0 13959 if ( Math.abs( event[ axis ] - cur ) < dist ) {
Daniel@0 13960 dist = Math.abs( event[ axis ] - cur );
Daniel@0 13961 itemWithLeastDistance = this.items[ j ];
Daniel@0 13962 this.direction = nearBottom ? "up": "down";
Daniel@0 13963 }
Daniel@0 13964 }
Daniel@0 13965
Daniel@0 13966 //Check if dropOnEmpty is enabled
Daniel@0 13967 if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
Daniel@0 13968 return;
Daniel@0 13969 }
Daniel@0 13970
Daniel@0 13971 if(this.currentContainer === this.containers[innermostIndex]) {
Daniel@0 13972 return;
Daniel@0 13973 }
Daniel@0 13974
Daniel@0 13975 itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
Daniel@0 13976 this._trigger("change", event, this._uiHash());
Daniel@0 13977 this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
Daniel@0 13978 this.currentContainer = this.containers[innermostIndex];
Daniel@0 13979
Daniel@0 13980 //Update the placeholder
Daniel@0 13981 this.options.placeholder.update(this.currentContainer, this.placeholder);
Daniel@0 13982
Daniel@0 13983 this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
Daniel@0 13984 this.containers[innermostIndex].containerCache.over = 1;
Daniel@0 13985 }
Daniel@0 13986
Daniel@0 13987
Daniel@0 13988 },
Daniel@0 13989
Daniel@0 13990 _createHelper: function(event) {
Daniel@0 13991
Daniel@0 13992 var o = this.options,
Daniel@0 13993 helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
Daniel@0 13994
Daniel@0 13995 //Add the helper to the DOM if that didn't happen already
Daniel@0 13996 if(!helper.parents("body").length) {
Daniel@0 13997 $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
Daniel@0 13998 }
Daniel@0 13999
Daniel@0 14000 if(helper[0] === this.currentItem[0]) {
Daniel@0 14001 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") };
Daniel@0 14002 }
Daniel@0 14003
Daniel@0 14004 if(!helper[0].style.width || o.forceHelperSize) {
Daniel@0 14005 helper.width(this.currentItem.width());
Daniel@0 14006 }
Daniel@0 14007 if(!helper[0].style.height || o.forceHelperSize) {
Daniel@0 14008 helper.height(this.currentItem.height());
Daniel@0 14009 }
Daniel@0 14010
Daniel@0 14011 return helper;
Daniel@0 14012
Daniel@0 14013 },
Daniel@0 14014
Daniel@0 14015 _adjustOffsetFromHelper: function(obj) {
Daniel@0 14016 if (typeof obj === "string") {
Daniel@0 14017 obj = obj.split(" ");
Daniel@0 14018 }
Daniel@0 14019 if ($.isArray(obj)) {
Daniel@0 14020 obj = {left: +obj[0], top: +obj[1] || 0};
Daniel@0 14021 }
Daniel@0 14022 if ("left" in obj) {
Daniel@0 14023 this.offset.click.left = obj.left + this.margins.left;
Daniel@0 14024 }
Daniel@0 14025 if ("right" in obj) {
Daniel@0 14026 this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
Daniel@0 14027 }
Daniel@0 14028 if ("top" in obj) {
Daniel@0 14029 this.offset.click.top = obj.top + this.margins.top;
Daniel@0 14030 }
Daniel@0 14031 if ("bottom" in obj) {
Daniel@0 14032 this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
Daniel@0 14033 }
Daniel@0 14034 },
Daniel@0 14035
Daniel@0 14036 _getParentOffset: function() {
Daniel@0 14037
Daniel@0 14038
Daniel@0 14039 //Get the offsetParent and cache its position
Daniel@0 14040 this.offsetParent = this.helper.offsetParent();
Daniel@0 14041 var po = this.offsetParent.offset();
Daniel@0 14042
Daniel@0 14043 // This is a special case where we need to modify a offset calculated on start, since the following happened:
Daniel@0 14044 // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
Daniel@0 14045 // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
Daniel@0 14046 // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
Daniel@0 14047 if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
Daniel@0 14048 po.left += this.scrollParent.scrollLeft();
Daniel@0 14049 po.top += this.scrollParent.scrollTop();
Daniel@0 14050 }
Daniel@0 14051
Daniel@0 14052 // This needs to be actually done for all browsers, since pageX/pageY includes this information
Daniel@0 14053 // with an ugly IE fix
Daniel@0 14054 if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
Daniel@0 14055 po = { top: 0, left: 0 };
Daniel@0 14056 }
Daniel@0 14057
Daniel@0 14058 return {
Daniel@0 14059 top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
Daniel@0 14060 left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
Daniel@0 14061 };
Daniel@0 14062
Daniel@0 14063 },
Daniel@0 14064
Daniel@0 14065 _getRelativeOffset: function() {
Daniel@0 14066
Daniel@0 14067 if(this.cssPosition === "relative") {
Daniel@0 14068 var p = this.currentItem.position();
Daniel@0 14069 return {
Daniel@0 14070 top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
Daniel@0 14071 left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
Daniel@0 14072 };
Daniel@0 14073 } else {
Daniel@0 14074 return { top: 0, left: 0 };
Daniel@0 14075 }
Daniel@0 14076
Daniel@0 14077 },
Daniel@0 14078
Daniel@0 14079 _cacheMargins: function() {
Daniel@0 14080 this.margins = {
Daniel@0 14081 left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
Daniel@0 14082 top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
Daniel@0 14083 };
Daniel@0 14084 },
Daniel@0 14085
Daniel@0 14086 _cacheHelperProportions: function() {
Daniel@0 14087 this.helperProportions = {
Daniel@0 14088 width: this.helper.outerWidth(),
Daniel@0 14089 height: this.helper.outerHeight()
Daniel@0 14090 };
Daniel@0 14091 },
Daniel@0 14092
Daniel@0 14093 _setContainment: function() {
Daniel@0 14094
Daniel@0 14095 var ce, co, over,
Daniel@0 14096 o = this.options;
Daniel@0 14097 if(o.containment === "parent") {
Daniel@0 14098 o.containment = this.helper[0].parentNode;
Daniel@0 14099 }
Daniel@0 14100 if(o.containment === "document" || o.containment === "window") {
Daniel@0 14101 this.containment = [
Daniel@0 14102 0 - this.offset.relative.left - this.offset.parent.left,
Daniel@0 14103 0 - this.offset.relative.top - this.offset.parent.top,
Daniel@0 14104 $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
Daniel@0 14105 ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
Daniel@0 14106 ];
Daniel@0 14107 }
Daniel@0 14108
Daniel@0 14109 if(!(/^(document|window|parent)$/).test(o.containment)) {
Daniel@0 14110 ce = $(o.containment)[0];
Daniel@0 14111 co = $(o.containment).offset();
Daniel@0 14112 over = ($(ce).css("overflow") !== "hidden");
Daniel@0 14113
Daniel@0 14114 this.containment = [
Daniel@0 14115 co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
Daniel@0 14116 co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
Daniel@0 14117 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,
Daniel@0 14118 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
Daniel@0 14119 ];
Daniel@0 14120 }
Daniel@0 14121
Daniel@0 14122 },
Daniel@0 14123
Daniel@0 14124 _convertPositionTo: function(d, pos) {
Daniel@0 14125
Daniel@0 14126 if(!pos) {
Daniel@0 14127 pos = this.position;
Daniel@0 14128 }
Daniel@0 14129 var mod = d === "absolute" ? 1 : -1,
Daniel@0 14130 scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
Daniel@0 14131 scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
Daniel@0 14132
Daniel@0 14133 return {
Daniel@0 14134 top: (
Daniel@0 14135 pos.top + // The absolute mouse position
Daniel@0 14136 this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 14137 this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border)
Daniel@0 14138 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
Daniel@0 14139 ),
Daniel@0 14140 left: (
Daniel@0 14141 pos.left + // The absolute mouse position
Daniel@0 14142 this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 14143 this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border)
Daniel@0 14144 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
Daniel@0 14145 )
Daniel@0 14146 };
Daniel@0 14147
Daniel@0 14148 },
Daniel@0 14149
Daniel@0 14150 _generatePosition: function(event) {
Daniel@0 14151
Daniel@0 14152 var top, left,
Daniel@0 14153 o = this.options,
Daniel@0 14154 pageX = event.pageX,
Daniel@0 14155 pageY = event.pageY,
Daniel@0 14156 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);
Daniel@0 14157
Daniel@0 14158 // This is another very weird special case that only happens for relative elements:
Daniel@0 14159 // 1. If the css position is relative
Daniel@0 14160 // 2. and the scroll parent is the document or similar to the offset parent
Daniel@0 14161 // we have to refresh the relative offset during the scroll so there are no jumps
Daniel@0 14162 if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
Daniel@0 14163 this.offset.relative = this._getRelativeOffset();
Daniel@0 14164 }
Daniel@0 14165
Daniel@0 14166 /*
Daniel@0 14167 * - Position constraining -
Daniel@0 14168 * Constrain the position to a mix of grid, containment.
Daniel@0 14169 */
Daniel@0 14170
Daniel@0 14171 if(this.originalPosition) { //If we are not dragging yet, we won't check for options
Daniel@0 14172
Daniel@0 14173 if(this.containment) {
Daniel@0 14174 if(event.pageX - this.offset.click.left < this.containment[0]) {
Daniel@0 14175 pageX = this.containment[0] + this.offset.click.left;
Daniel@0 14176 }
Daniel@0 14177 if(event.pageY - this.offset.click.top < this.containment[1]) {
Daniel@0 14178 pageY = this.containment[1] + this.offset.click.top;
Daniel@0 14179 }
Daniel@0 14180 if(event.pageX - this.offset.click.left > this.containment[2]) {
Daniel@0 14181 pageX = this.containment[2] + this.offset.click.left;
Daniel@0 14182 }
Daniel@0 14183 if(event.pageY - this.offset.click.top > this.containment[3]) {
Daniel@0 14184 pageY = this.containment[3] + this.offset.click.top;
Daniel@0 14185 }
Daniel@0 14186 }
Daniel@0 14187
Daniel@0 14188 if(o.grid) {
Daniel@0 14189 top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
Daniel@0 14190 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;
Daniel@0 14191
Daniel@0 14192 left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
Daniel@0 14193 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;
Daniel@0 14194 }
Daniel@0 14195
Daniel@0 14196 }
Daniel@0 14197
Daniel@0 14198 return {
Daniel@0 14199 top: (
Daniel@0 14200 pageY - // The absolute mouse position
Daniel@0 14201 this.offset.click.top - // Click offset (relative to the element)
Daniel@0 14202 this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 14203 this.offset.parent.top + // The offsetParent's offset without borders (offset + border)
Daniel@0 14204 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
Daniel@0 14205 ),
Daniel@0 14206 left: (
Daniel@0 14207 pageX - // The absolute mouse position
Daniel@0 14208 this.offset.click.left - // Click offset (relative to the element)
Daniel@0 14209 this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent
Daniel@0 14210 this.offset.parent.left + // The offsetParent's offset without borders (offset + border)
Daniel@0 14211 ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
Daniel@0 14212 )
Daniel@0 14213 };
Daniel@0 14214
Daniel@0 14215 },
Daniel@0 14216
Daniel@0 14217 _rearrange: function(event, i, a, hardRefresh) {
Daniel@0 14218
Daniel@0 14219 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));
Daniel@0 14220
Daniel@0 14221 //Various things done here to improve the performance:
Daniel@0 14222 // 1. we create a setTimeout, that calls refreshPositions
Daniel@0 14223 // 2. on the instance, we have a counter variable, that get's higher after every append
Daniel@0 14224 // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
Daniel@0 14225 // 4. this lets only the last addition to the timeout stack through
Daniel@0 14226 this.counter = this.counter ? ++this.counter : 1;
Daniel@0 14227 var counter = this.counter;
Daniel@0 14228
Daniel@0 14229 this._delay(function() {
Daniel@0 14230 if(counter === this.counter) {
Daniel@0 14231 this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
Daniel@0 14232 }
Daniel@0 14233 });
Daniel@0 14234
Daniel@0 14235 },
Daniel@0 14236
Daniel@0 14237 _clear: function(event, noPropagation) {
Daniel@0 14238
Daniel@0 14239 this.reverting = false;
Daniel@0 14240 // We delay all events that have to be triggered to after the point where the placeholder has been removed and
Daniel@0 14241 // everything else normalized again
Daniel@0 14242 var i,
Daniel@0 14243 delayedTriggers = [];
Daniel@0 14244
Daniel@0 14245 // We first have to update the dom position of the actual currentItem
Daniel@0 14246 // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
Daniel@0 14247 if(!this._noFinalSort && this.currentItem.parent().length) {
Daniel@0 14248 this.placeholder.before(this.currentItem);
Daniel@0 14249 }
Daniel@0 14250 this._noFinalSort = null;
Daniel@0 14251
Daniel@0 14252 if(this.helper[0] === this.currentItem[0]) {
Daniel@0 14253 for(i in this._storedCSS) {
Daniel@0 14254 if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
Daniel@0 14255 this._storedCSS[i] = "";
Daniel@0 14256 }
Daniel@0 14257 }
Daniel@0 14258 this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
Daniel@0 14259 } else {
Daniel@0 14260 this.currentItem.show();
Daniel@0 14261 }
Daniel@0 14262
Daniel@0 14263 if(this.fromOutside && !noPropagation) {
Daniel@0 14264 delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
Daniel@0 14265 }
Daniel@0 14266 if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
Daniel@0 14267 delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
Daniel@0 14268 }
Daniel@0 14269
Daniel@0 14270 // Check if the items Container has Changed and trigger appropriate
Daniel@0 14271 // events.
Daniel@0 14272 if (this !== this.currentContainer) {
Daniel@0 14273 if(!noPropagation) {
Daniel@0 14274 delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
Daniel@0 14275 delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
Daniel@0 14276 delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer));
Daniel@0 14277 }
Daniel@0 14278 }
Daniel@0 14279
Daniel@0 14280
Daniel@0 14281 //Post events to containers
Daniel@0 14282 function delayEvent( type, instance, container ) {
Daniel@0 14283 return function( event ) {
Daniel@0 14284 container._trigger( type, event, instance._uiHash( instance ) );
Daniel@0 14285 };
Daniel@0 14286 }
Daniel@0 14287 for (i = this.containers.length - 1; i >= 0; i--){
Daniel@0 14288 if (!noPropagation) {
Daniel@0 14289 delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
Daniel@0 14290 }
Daniel@0 14291 if(this.containers[i].containerCache.over) {
Daniel@0 14292 delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
Daniel@0 14293 this.containers[i].containerCache.over = 0;
Daniel@0 14294 }
Daniel@0 14295 }
Daniel@0 14296
Daniel@0 14297 //Do what was originally in plugins
Daniel@0 14298 if ( this.storedCursor ) {
Daniel@0 14299 this.document.find( "body" ).css( "cursor", this.storedCursor );
Daniel@0 14300 this.storedStylesheet.remove();
Daniel@0 14301 }
Daniel@0 14302 if(this._storedOpacity) {
Daniel@0 14303 this.helper.css("opacity", this._storedOpacity);
Daniel@0 14304 }
Daniel@0 14305 if(this._storedZIndex) {
Daniel@0 14306 this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
Daniel@0 14307 }
Daniel@0 14308
Daniel@0 14309 this.dragging = false;
Daniel@0 14310 if(this.cancelHelperRemoval) {
Daniel@0 14311 if(!noPropagation) {
Daniel@0 14312 this._trigger("beforeStop", event, this._uiHash());
Daniel@0 14313 for (i=0; i < delayedTriggers.length; i++) {
Daniel@0 14314 delayedTriggers[i].call(this, event);
Daniel@0 14315 } //Trigger all delayed events
Daniel@0 14316 this._trigger("stop", event, this._uiHash());
Daniel@0 14317 }
Daniel@0 14318
Daniel@0 14319 this.fromOutside = false;
Daniel@0 14320 return false;
Daniel@0 14321 }
Daniel@0 14322
Daniel@0 14323 if(!noPropagation) {
Daniel@0 14324 this._trigger("beforeStop", event, this._uiHash());
Daniel@0 14325 }
Daniel@0 14326
Daniel@0 14327 //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
Daniel@0 14328 this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
Daniel@0 14329
Daniel@0 14330 if(this.helper[0] !== this.currentItem[0]) {
Daniel@0 14331 this.helper.remove();
Daniel@0 14332 }
Daniel@0 14333 this.helper = null;
Daniel@0 14334
Daniel@0 14335 if(!noPropagation) {
Daniel@0 14336 for (i=0; i < delayedTriggers.length; i++) {
Daniel@0 14337 delayedTriggers[i].call(this, event);
Daniel@0 14338 } //Trigger all delayed events
Daniel@0 14339 this._trigger("stop", event, this._uiHash());
Daniel@0 14340 }
Daniel@0 14341
Daniel@0 14342 this.fromOutside = false;
Daniel@0 14343 return true;
Daniel@0 14344
Daniel@0 14345 },
Daniel@0 14346
Daniel@0 14347 _trigger: function() {
Daniel@0 14348 if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
Daniel@0 14349 this.cancel();
Daniel@0 14350 }
Daniel@0 14351 },
Daniel@0 14352
Daniel@0 14353 _uiHash: function(_inst) {
Daniel@0 14354 var inst = _inst || this;
Daniel@0 14355 return {
Daniel@0 14356 helper: inst.helper,
Daniel@0 14357 placeholder: inst.placeholder || $([]),
Daniel@0 14358 position: inst.position,
Daniel@0 14359 originalPosition: inst.originalPosition,
Daniel@0 14360 offset: inst.positionAbs,
Daniel@0 14361 item: inst.currentItem,
Daniel@0 14362 sender: _inst ? _inst.element : null
Daniel@0 14363 };
Daniel@0 14364 }
Daniel@0 14365
Daniel@0 14366 });
Daniel@0 14367
Daniel@0 14368
Daniel@0 14369 /*!
Daniel@0 14370 * jQuery UI Spinner 1.11.0
Daniel@0 14371 * http://jqueryui.com
Daniel@0 14372 *
Daniel@0 14373 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 14374 * Released under the MIT license.
Daniel@0 14375 * http://jquery.org/license
Daniel@0 14376 *
Daniel@0 14377 * http://api.jqueryui.com/spinner/
Daniel@0 14378 */
Daniel@0 14379
Daniel@0 14380
Daniel@0 14381 function spinner_modifier( fn ) {
Daniel@0 14382 return function() {
Daniel@0 14383 var previous = this.element.val();
Daniel@0 14384 fn.apply( this, arguments );
Daniel@0 14385 this._refresh();
Daniel@0 14386 if ( previous !== this.element.val() ) {
Daniel@0 14387 this._trigger( "change" );
Daniel@0 14388 }
Daniel@0 14389 };
Daniel@0 14390 }
Daniel@0 14391
Daniel@0 14392 var spinner = $.widget( "ui.spinner", {
Daniel@0 14393 version: "1.11.0",
Daniel@0 14394 defaultElement: "<input>",
Daniel@0 14395 widgetEventPrefix: "spin",
Daniel@0 14396 options: {
Daniel@0 14397 culture: null,
Daniel@0 14398 icons: {
Daniel@0 14399 down: "ui-icon-triangle-1-s",
Daniel@0 14400 up: "ui-icon-triangle-1-n"
Daniel@0 14401 },
Daniel@0 14402 incremental: true,
Daniel@0 14403 max: null,
Daniel@0 14404 min: null,
Daniel@0 14405 numberFormat: null,
Daniel@0 14406 page: 10,
Daniel@0 14407 step: 1,
Daniel@0 14408
Daniel@0 14409 change: null,
Daniel@0 14410 spin: null,
Daniel@0 14411 start: null,
Daniel@0 14412 stop: null
Daniel@0 14413 },
Daniel@0 14414
Daniel@0 14415 _create: function() {
Daniel@0 14416 // handle string values that need to be parsed
Daniel@0 14417 this._setOption( "max", this.options.max );
Daniel@0 14418 this._setOption( "min", this.options.min );
Daniel@0 14419 this._setOption( "step", this.options.step );
Daniel@0 14420
Daniel@0 14421 // Only format if there is a value, prevents the field from being marked
Daniel@0 14422 // as invalid in Firefox, see #9573.
Daniel@0 14423 if ( this.value() !== "" ) {
Daniel@0 14424 // Format the value, but don't constrain.
Daniel@0 14425 this._value( this.element.val(), true );
Daniel@0 14426 }
Daniel@0 14427
Daniel@0 14428 this._draw();
Daniel@0 14429 this._on( this._events );
Daniel@0 14430 this._refresh();
Daniel@0 14431
Daniel@0 14432 // turning off autocomplete prevents the browser from remembering the
Daniel@0 14433 // value when navigating through history, so we re-enable autocomplete
Daniel@0 14434 // if the page is unloaded before the widget is destroyed. #7790
Daniel@0 14435 this._on( this.window, {
Daniel@0 14436 beforeunload: function() {
Daniel@0 14437 this.element.removeAttr( "autocomplete" );
Daniel@0 14438 }
Daniel@0 14439 });
Daniel@0 14440 },
Daniel@0 14441
Daniel@0 14442 _getCreateOptions: function() {
Daniel@0 14443 var options = {},
Daniel@0 14444 element = this.element;
Daniel@0 14445
Daniel@0 14446 $.each( [ "min", "max", "step" ], function( i, option ) {
Daniel@0 14447 var value = element.attr( option );
Daniel@0 14448 if ( value !== undefined && value.length ) {
Daniel@0 14449 options[ option ] = value;
Daniel@0 14450 }
Daniel@0 14451 });
Daniel@0 14452
Daniel@0 14453 return options;
Daniel@0 14454 },
Daniel@0 14455
Daniel@0 14456 _events: {
Daniel@0 14457 keydown: function( event ) {
Daniel@0 14458 if ( this._start( event ) && this._keydown( event ) ) {
Daniel@0 14459 event.preventDefault();
Daniel@0 14460 }
Daniel@0 14461 },
Daniel@0 14462 keyup: "_stop",
Daniel@0 14463 focus: function() {
Daniel@0 14464 this.previous = this.element.val();
Daniel@0 14465 },
Daniel@0 14466 blur: function( event ) {
Daniel@0 14467 if ( this.cancelBlur ) {
Daniel@0 14468 delete this.cancelBlur;
Daniel@0 14469 return;
Daniel@0 14470 }
Daniel@0 14471
Daniel@0 14472 this._stop();
Daniel@0 14473 this._refresh();
Daniel@0 14474 if ( this.previous !== this.element.val() ) {
Daniel@0 14475 this._trigger( "change", event );
Daniel@0 14476 }
Daniel@0 14477 },
Daniel@0 14478 mousewheel: function( event, delta ) {
Daniel@0 14479 if ( !delta ) {
Daniel@0 14480 return;
Daniel@0 14481 }
Daniel@0 14482 if ( !this.spinning && !this._start( event ) ) {
Daniel@0 14483 return false;
Daniel@0 14484 }
Daniel@0 14485
Daniel@0 14486 this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
Daniel@0 14487 clearTimeout( this.mousewheelTimer );
Daniel@0 14488 this.mousewheelTimer = this._delay(function() {
Daniel@0 14489 if ( this.spinning ) {
Daniel@0 14490 this._stop( event );
Daniel@0 14491 }
Daniel@0 14492 }, 100 );
Daniel@0 14493 event.preventDefault();
Daniel@0 14494 },
Daniel@0 14495 "mousedown .ui-spinner-button": function( event ) {
Daniel@0 14496 var previous;
Daniel@0 14497
Daniel@0 14498 // We never want the buttons to have focus; whenever the user is
Daniel@0 14499 // interacting with the spinner, the focus should be on the input.
Daniel@0 14500 // If the input is focused then this.previous is properly set from
Daniel@0 14501 // when the input first received focus. If the input is not focused
Daniel@0 14502 // then we need to set this.previous based on the value before spinning.
Daniel@0 14503 previous = this.element[0] === this.document[0].activeElement ?
Daniel@0 14504 this.previous : this.element.val();
Daniel@0 14505 function checkFocus() {
Daniel@0 14506 var isActive = this.element[0] === this.document[0].activeElement;
Daniel@0 14507 if ( !isActive ) {
Daniel@0 14508 this.element.focus();
Daniel@0 14509 this.previous = previous;
Daniel@0 14510 // support: IE
Daniel@0 14511 // IE sets focus asynchronously, so we need to check if focus
Daniel@0 14512 // moved off of the input because the user clicked on the button.
Daniel@0 14513 this._delay(function() {
Daniel@0 14514 this.previous = previous;
Daniel@0 14515 });
Daniel@0 14516 }
Daniel@0 14517 }
Daniel@0 14518
Daniel@0 14519 // ensure focus is on (or stays on) the text field
Daniel@0 14520 event.preventDefault();
Daniel@0 14521 checkFocus.call( this );
Daniel@0 14522
Daniel@0 14523 // support: IE
Daniel@0 14524 // IE doesn't prevent moving focus even with event.preventDefault()
Daniel@0 14525 // so we set a flag to know when we should ignore the blur event
Daniel@0 14526 // and check (again) if focus moved off of the input.
Daniel@0 14527 this.cancelBlur = true;
Daniel@0 14528 this._delay(function() {
Daniel@0 14529 delete this.cancelBlur;
Daniel@0 14530 checkFocus.call( this );
Daniel@0 14531 });
Daniel@0 14532
Daniel@0 14533 if ( this._start( event ) === false ) {
Daniel@0 14534 return;
Daniel@0 14535 }
Daniel@0 14536
Daniel@0 14537 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
Daniel@0 14538 },
Daniel@0 14539 "mouseup .ui-spinner-button": "_stop",
Daniel@0 14540 "mouseenter .ui-spinner-button": function( event ) {
Daniel@0 14541 // button will add ui-state-active if mouse was down while mouseleave and kept down
Daniel@0 14542 if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
Daniel@0 14543 return;
Daniel@0 14544 }
Daniel@0 14545
Daniel@0 14546 if ( this._start( event ) === false ) {
Daniel@0 14547 return false;
Daniel@0 14548 }
Daniel@0 14549 this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
Daniel@0 14550 },
Daniel@0 14551 // TODO: do we really want to consider this a stop?
Daniel@0 14552 // shouldn't we just stop the repeater and wait until mouseup before
Daniel@0 14553 // we trigger the stop event?
Daniel@0 14554 "mouseleave .ui-spinner-button": "_stop"
Daniel@0 14555 },
Daniel@0 14556
Daniel@0 14557 _draw: function() {
Daniel@0 14558 var uiSpinner = this.uiSpinner = this.element
Daniel@0 14559 .addClass( "ui-spinner-input" )
Daniel@0 14560 .attr( "autocomplete", "off" )
Daniel@0 14561 .wrap( this._uiSpinnerHtml() )
Daniel@0 14562 .parent()
Daniel@0 14563 // add buttons
Daniel@0 14564 .append( this._buttonHtml() );
Daniel@0 14565
Daniel@0 14566 this.element.attr( "role", "spinbutton" );
Daniel@0 14567
Daniel@0 14568 // button bindings
Daniel@0 14569 this.buttons = uiSpinner.find( ".ui-spinner-button" )
Daniel@0 14570 .attr( "tabIndex", -1 )
Daniel@0 14571 .button()
Daniel@0 14572 .removeClass( "ui-corner-all" );
Daniel@0 14573
Daniel@0 14574 // IE 6 doesn't understand height: 50% for the buttons
Daniel@0 14575 // unless the wrapper has an explicit height
Daniel@0 14576 if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
Daniel@0 14577 uiSpinner.height() > 0 ) {
Daniel@0 14578 uiSpinner.height( uiSpinner.height() );
Daniel@0 14579 }
Daniel@0 14580
Daniel@0 14581 // disable spinner if element was already disabled
Daniel@0 14582 if ( this.options.disabled ) {
Daniel@0 14583 this.disable();
Daniel@0 14584 }
Daniel@0 14585 },
Daniel@0 14586
Daniel@0 14587 _keydown: function( event ) {
Daniel@0 14588 var options = this.options,
Daniel@0 14589 keyCode = $.ui.keyCode;
Daniel@0 14590
Daniel@0 14591 switch ( event.keyCode ) {
Daniel@0 14592 case keyCode.UP:
Daniel@0 14593 this._repeat( null, 1, event );
Daniel@0 14594 return true;
Daniel@0 14595 case keyCode.DOWN:
Daniel@0 14596 this._repeat( null, -1, event );
Daniel@0 14597 return true;
Daniel@0 14598 case keyCode.PAGE_UP:
Daniel@0 14599 this._repeat( null, options.page, event );
Daniel@0 14600 return true;
Daniel@0 14601 case keyCode.PAGE_DOWN:
Daniel@0 14602 this._repeat( null, -options.page, event );
Daniel@0 14603 return true;
Daniel@0 14604 }
Daniel@0 14605
Daniel@0 14606 return false;
Daniel@0 14607 },
Daniel@0 14608
Daniel@0 14609 _uiSpinnerHtml: function() {
Daniel@0 14610 return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
Daniel@0 14611 },
Daniel@0 14612
Daniel@0 14613 _buttonHtml: function() {
Daniel@0 14614 return "" +
Daniel@0 14615 "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
Daniel@0 14616 "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
Daniel@0 14617 "</a>" +
Daniel@0 14618 "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
Daniel@0 14619 "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
Daniel@0 14620 "</a>";
Daniel@0 14621 },
Daniel@0 14622
Daniel@0 14623 _start: function( event ) {
Daniel@0 14624 if ( !this.spinning && this._trigger( "start", event ) === false ) {
Daniel@0 14625 return false;
Daniel@0 14626 }
Daniel@0 14627
Daniel@0 14628 if ( !this.counter ) {
Daniel@0 14629 this.counter = 1;
Daniel@0 14630 }
Daniel@0 14631 this.spinning = true;
Daniel@0 14632 return true;
Daniel@0 14633 },
Daniel@0 14634
Daniel@0 14635 _repeat: function( i, steps, event ) {
Daniel@0 14636 i = i || 500;
Daniel@0 14637
Daniel@0 14638 clearTimeout( this.timer );
Daniel@0 14639 this.timer = this._delay(function() {
Daniel@0 14640 this._repeat( 40, steps, event );
Daniel@0 14641 }, i );
Daniel@0 14642
Daniel@0 14643 this._spin( steps * this.options.step, event );
Daniel@0 14644 },
Daniel@0 14645
Daniel@0 14646 _spin: function( step, event ) {
Daniel@0 14647 var value = this.value() || 0;
Daniel@0 14648
Daniel@0 14649 if ( !this.counter ) {
Daniel@0 14650 this.counter = 1;
Daniel@0 14651 }
Daniel@0 14652
Daniel@0 14653 value = this._adjustValue( value + step * this._increment( this.counter ) );
Daniel@0 14654
Daniel@0 14655 if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
Daniel@0 14656 this._value( value );
Daniel@0 14657 this.counter++;
Daniel@0 14658 }
Daniel@0 14659 },
Daniel@0 14660
Daniel@0 14661 _increment: function( i ) {
Daniel@0 14662 var incremental = this.options.incremental;
Daniel@0 14663
Daniel@0 14664 if ( incremental ) {
Daniel@0 14665 return $.isFunction( incremental ) ?
Daniel@0 14666 incremental( i ) :
Daniel@0 14667 Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
Daniel@0 14668 }
Daniel@0 14669
Daniel@0 14670 return 1;
Daniel@0 14671 },
Daniel@0 14672
Daniel@0 14673 _precision: function() {
Daniel@0 14674 var precision = this._precisionOf( this.options.step );
Daniel@0 14675 if ( this.options.min !== null ) {
Daniel@0 14676 precision = Math.max( precision, this._precisionOf( this.options.min ) );
Daniel@0 14677 }
Daniel@0 14678 return precision;
Daniel@0 14679 },
Daniel@0 14680
Daniel@0 14681 _precisionOf: function( num ) {
Daniel@0 14682 var str = num.toString(),
Daniel@0 14683 decimal = str.indexOf( "." );
Daniel@0 14684 return decimal === -1 ? 0 : str.length - decimal - 1;
Daniel@0 14685 },
Daniel@0 14686
Daniel@0 14687 _adjustValue: function( value ) {
Daniel@0 14688 var base, aboveMin,
Daniel@0 14689 options = this.options;
Daniel@0 14690
Daniel@0 14691 // make sure we're at a valid step
Daniel@0 14692 // - find out where we are relative to the base (min or 0)
Daniel@0 14693 base = options.min !== null ? options.min : 0;
Daniel@0 14694 aboveMin = value - base;
Daniel@0 14695 // - round to the nearest step
Daniel@0 14696 aboveMin = Math.round(aboveMin / options.step) * options.step;
Daniel@0 14697 // - rounding is based on 0, so adjust back to our base
Daniel@0 14698 value = base + aboveMin;
Daniel@0 14699
Daniel@0 14700 // fix precision from bad JS floating point math
Daniel@0 14701 value = parseFloat( value.toFixed( this._precision() ) );
Daniel@0 14702
Daniel@0 14703 // clamp the value
Daniel@0 14704 if ( options.max !== null && value > options.max) {
Daniel@0 14705 return options.max;
Daniel@0 14706 }
Daniel@0 14707 if ( options.min !== null && value < options.min ) {
Daniel@0 14708 return options.min;
Daniel@0 14709 }
Daniel@0 14710
Daniel@0 14711 return value;
Daniel@0 14712 },
Daniel@0 14713
Daniel@0 14714 _stop: function( event ) {
Daniel@0 14715 if ( !this.spinning ) {
Daniel@0 14716 return;
Daniel@0 14717 }
Daniel@0 14718
Daniel@0 14719 clearTimeout( this.timer );
Daniel@0 14720 clearTimeout( this.mousewheelTimer );
Daniel@0 14721 this.counter = 0;
Daniel@0 14722 this.spinning = false;
Daniel@0 14723 this._trigger( "stop", event );
Daniel@0 14724 },
Daniel@0 14725
Daniel@0 14726 _setOption: function( key, value ) {
Daniel@0 14727 if ( key === "culture" || key === "numberFormat" ) {
Daniel@0 14728 var prevValue = this._parse( this.element.val() );
Daniel@0 14729 this.options[ key ] = value;
Daniel@0 14730 this.element.val( this._format( prevValue ) );
Daniel@0 14731 return;
Daniel@0 14732 }
Daniel@0 14733
Daniel@0 14734 if ( key === "max" || key === "min" || key === "step" ) {
Daniel@0 14735 if ( typeof value === "string" ) {
Daniel@0 14736 value = this._parse( value );
Daniel@0 14737 }
Daniel@0 14738 }
Daniel@0 14739 if ( key === "icons" ) {
Daniel@0 14740 this.buttons.first().find( ".ui-icon" )
Daniel@0 14741 .removeClass( this.options.icons.up )
Daniel@0 14742 .addClass( value.up );
Daniel@0 14743 this.buttons.last().find( ".ui-icon" )
Daniel@0 14744 .removeClass( this.options.icons.down )
Daniel@0 14745 .addClass( value.down );
Daniel@0 14746 }
Daniel@0 14747
Daniel@0 14748 this._super( key, value );
Daniel@0 14749
Daniel@0 14750 if ( key === "disabled" ) {
Daniel@0 14751 this.widget().toggleClass( "ui-state-disabled", !!value );
Daniel@0 14752 this.element.prop( "disabled", !!value );
Daniel@0 14753 this.buttons.button( value ? "disable" : "enable" );
Daniel@0 14754 }
Daniel@0 14755 },
Daniel@0 14756
Daniel@0 14757 _setOptions: spinner_modifier(function( options ) {
Daniel@0 14758 this._super( options );
Daniel@0 14759 }),
Daniel@0 14760
Daniel@0 14761 _parse: function( val ) {
Daniel@0 14762 if ( typeof val === "string" && val !== "" ) {
Daniel@0 14763 val = window.Globalize && this.options.numberFormat ?
Daniel@0 14764 Globalize.parseFloat( val, 10, this.options.culture ) : +val;
Daniel@0 14765 }
Daniel@0 14766 return val === "" || isNaN( val ) ? null : val;
Daniel@0 14767 },
Daniel@0 14768
Daniel@0 14769 _format: function( value ) {
Daniel@0 14770 if ( value === "" ) {
Daniel@0 14771 return "";
Daniel@0 14772 }
Daniel@0 14773 return window.Globalize && this.options.numberFormat ?
Daniel@0 14774 Globalize.format( value, this.options.numberFormat, this.options.culture ) :
Daniel@0 14775 value;
Daniel@0 14776 },
Daniel@0 14777
Daniel@0 14778 _refresh: function() {
Daniel@0 14779 this.element.attr({
Daniel@0 14780 "aria-valuemin": this.options.min,
Daniel@0 14781 "aria-valuemax": this.options.max,
Daniel@0 14782 // TODO: what should we do with values that can't be parsed?
Daniel@0 14783 "aria-valuenow": this._parse( this.element.val() )
Daniel@0 14784 });
Daniel@0 14785 },
Daniel@0 14786
Daniel@0 14787 isValid: function() {
Daniel@0 14788 var value = this.value();
Daniel@0 14789
Daniel@0 14790 // null is invalid
Daniel@0 14791 if ( value === null ) {
Daniel@0 14792 return false;
Daniel@0 14793 }
Daniel@0 14794
Daniel@0 14795 // if value gets adjusted, it's invalid
Daniel@0 14796 return value === this._adjustValue( value );
Daniel@0 14797 },
Daniel@0 14798
Daniel@0 14799 // update the value without triggering change
Daniel@0 14800 _value: function( value, allowAny ) {
Daniel@0 14801 var parsed;
Daniel@0 14802 if ( value !== "" ) {
Daniel@0 14803 parsed = this._parse( value );
Daniel@0 14804 if ( parsed !== null ) {
Daniel@0 14805 if ( !allowAny ) {
Daniel@0 14806 parsed = this._adjustValue( parsed );
Daniel@0 14807 }
Daniel@0 14808 value = this._format( parsed );
Daniel@0 14809 }
Daniel@0 14810 }
Daniel@0 14811 this.element.val( value );
Daniel@0 14812 this._refresh();
Daniel@0 14813 },
Daniel@0 14814
Daniel@0 14815 _destroy: function() {
Daniel@0 14816 this.element
Daniel@0 14817 .removeClass( "ui-spinner-input" )
Daniel@0 14818 .prop( "disabled", false )
Daniel@0 14819 .removeAttr( "autocomplete" )
Daniel@0 14820 .removeAttr( "role" )
Daniel@0 14821 .removeAttr( "aria-valuemin" )
Daniel@0 14822 .removeAttr( "aria-valuemax" )
Daniel@0 14823 .removeAttr( "aria-valuenow" );
Daniel@0 14824 this.uiSpinner.replaceWith( this.element );
Daniel@0 14825 },
Daniel@0 14826
Daniel@0 14827 stepUp: spinner_modifier(function( steps ) {
Daniel@0 14828 this._stepUp( steps );
Daniel@0 14829 }),
Daniel@0 14830 _stepUp: function( steps ) {
Daniel@0 14831 if ( this._start() ) {
Daniel@0 14832 this._spin( (steps || 1) * this.options.step );
Daniel@0 14833 this._stop();
Daniel@0 14834 }
Daniel@0 14835 },
Daniel@0 14836
Daniel@0 14837 stepDown: spinner_modifier(function( steps ) {
Daniel@0 14838 this._stepDown( steps );
Daniel@0 14839 }),
Daniel@0 14840 _stepDown: function( steps ) {
Daniel@0 14841 if ( this._start() ) {
Daniel@0 14842 this._spin( (steps || 1) * -this.options.step );
Daniel@0 14843 this._stop();
Daniel@0 14844 }
Daniel@0 14845 },
Daniel@0 14846
Daniel@0 14847 pageUp: spinner_modifier(function( pages ) {
Daniel@0 14848 this._stepUp( (pages || 1) * this.options.page );
Daniel@0 14849 }),
Daniel@0 14850
Daniel@0 14851 pageDown: spinner_modifier(function( pages ) {
Daniel@0 14852 this._stepDown( (pages || 1) * this.options.page );
Daniel@0 14853 }),
Daniel@0 14854
Daniel@0 14855 value: function( newVal ) {
Daniel@0 14856 if ( !arguments.length ) {
Daniel@0 14857 return this._parse( this.element.val() );
Daniel@0 14858 }
Daniel@0 14859 spinner_modifier( this._value ).call( this, newVal );
Daniel@0 14860 },
Daniel@0 14861
Daniel@0 14862 widget: function() {
Daniel@0 14863 return this.uiSpinner;
Daniel@0 14864 }
Daniel@0 14865 });
Daniel@0 14866
Daniel@0 14867
Daniel@0 14868 /*!
Daniel@0 14869 * jQuery UI Tabs 1.11.0
Daniel@0 14870 * http://jqueryui.com
Daniel@0 14871 *
Daniel@0 14872 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 14873 * Released under the MIT license.
Daniel@0 14874 * http://jquery.org/license
Daniel@0 14875 *
Daniel@0 14876 * http://api.jqueryui.com/tabs/
Daniel@0 14877 */
Daniel@0 14878
Daniel@0 14879
Daniel@0 14880 var tabs = $.widget( "ui.tabs", {
Daniel@0 14881 version: "1.11.0",
Daniel@0 14882 delay: 300,
Daniel@0 14883 options: {
Daniel@0 14884 active: null,
Daniel@0 14885 collapsible: false,
Daniel@0 14886 event: "click",
Daniel@0 14887 heightStyle: "content",
Daniel@0 14888 hide: null,
Daniel@0 14889 show: null,
Daniel@0 14890
Daniel@0 14891 // callbacks
Daniel@0 14892 activate: null,
Daniel@0 14893 beforeActivate: null,
Daniel@0 14894 beforeLoad: null,
Daniel@0 14895 load: null
Daniel@0 14896 },
Daniel@0 14897
Daniel@0 14898 _isLocal: (function() {
Daniel@0 14899 var rhash = /#.*$/;
Daniel@0 14900
Daniel@0 14901 return function( anchor ) {
Daniel@0 14902 var anchorUrl, locationUrl;
Daniel@0 14903
Daniel@0 14904 // support: IE7
Daniel@0 14905 // IE7 doesn't normalize the href property when set via script (#9317)
Daniel@0 14906 anchor = anchor.cloneNode( false );
Daniel@0 14907
Daniel@0 14908 anchorUrl = anchor.href.replace( rhash, "" );
Daniel@0 14909 locationUrl = location.href.replace( rhash, "" );
Daniel@0 14910
Daniel@0 14911 // decoding may throw an error if the URL isn't UTF-8 (#9518)
Daniel@0 14912 try {
Daniel@0 14913 anchorUrl = decodeURIComponent( anchorUrl );
Daniel@0 14914 } catch ( error ) {}
Daniel@0 14915 try {
Daniel@0 14916 locationUrl = decodeURIComponent( locationUrl );
Daniel@0 14917 } catch ( error ) {}
Daniel@0 14918
Daniel@0 14919 return anchor.hash.length > 1 && anchorUrl === locationUrl;
Daniel@0 14920 };
Daniel@0 14921 })(),
Daniel@0 14922
Daniel@0 14923 _create: function() {
Daniel@0 14924 var that = this,
Daniel@0 14925 options = this.options;
Daniel@0 14926
Daniel@0 14927 this.running = false;
Daniel@0 14928
Daniel@0 14929 this.element
Daniel@0 14930 .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
Daniel@0 14931 .toggleClass( "ui-tabs-collapsible", options.collapsible )
Daniel@0 14932 // Prevent users from focusing disabled tabs via click
Daniel@0 14933 .delegate( ".ui-tabs-nav > li", "mousedown" + this.eventNamespace, function( event ) {
Daniel@0 14934 if ( $( this ).is( ".ui-state-disabled" ) ) {
Daniel@0 14935 event.preventDefault();
Daniel@0 14936 }
Daniel@0 14937 })
Daniel@0 14938 // support: IE <9
Daniel@0 14939 // Preventing the default action in mousedown doesn't prevent IE
Daniel@0 14940 // from focusing the element, so if the anchor gets focused, blur.
Daniel@0 14941 // We don't have to worry about focusing the previously focused
Daniel@0 14942 // element since clicking on a non-focusable element should focus
Daniel@0 14943 // the body anyway.
Daniel@0 14944 .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
Daniel@0 14945 if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
Daniel@0 14946 this.blur();
Daniel@0 14947 }
Daniel@0 14948 });
Daniel@0 14949
Daniel@0 14950 this._processTabs();
Daniel@0 14951 options.active = this._initialActive();
Daniel@0 14952
Daniel@0 14953 // Take disabling tabs via class attribute from HTML
Daniel@0 14954 // into account and update option properly.
Daniel@0 14955 if ( $.isArray( options.disabled ) ) {
Daniel@0 14956 options.disabled = $.unique( options.disabled.concat(
Daniel@0 14957 $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
Daniel@0 14958 return that.tabs.index( li );
Daniel@0 14959 })
Daniel@0 14960 ) ).sort();
Daniel@0 14961 }
Daniel@0 14962
Daniel@0 14963 // check for length avoids error when initializing empty list
Daniel@0 14964 if ( this.options.active !== false && this.anchors.length ) {
Daniel@0 14965 this.active = this._findActive( options.active );
Daniel@0 14966 } else {
Daniel@0 14967 this.active = $();
Daniel@0 14968 }
Daniel@0 14969
Daniel@0 14970 this._refresh();
Daniel@0 14971
Daniel@0 14972 if ( this.active.length ) {
Daniel@0 14973 this.load( options.active );
Daniel@0 14974 }
Daniel@0 14975 },
Daniel@0 14976
Daniel@0 14977 _initialActive: function() {
Daniel@0 14978 var active = this.options.active,
Daniel@0 14979 collapsible = this.options.collapsible,
Daniel@0 14980 locationHash = location.hash.substring( 1 );
Daniel@0 14981
Daniel@0 14982 if ( active === null ) {
Daniel@0 14983 // check the fragment identifier in the URL
Daniel@0 14984 if ( locationHash ) {
Daniel@0 14985 this.tabs.each(function( i, tab ) {
Daniel@0 14986 if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
Daniel@0 14987 active = i;
Daniel@0 14988 return false;
Daniel@0 14989 }
Daniel@0 14990 });
Daniel@0 14991 }
Daniel@0 14992
Daniel@0 14993 // check for a tab marked active via a class
Daniel@0 14994 if ( active === null ) {
Daniel@0 14995 active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
Daniel@0 14996 }
Daniel@0 14997
Daniel@0 14998 // no active tab, set to false
Daniel@0 14999 if ( active === null || active === -1 ) {
Daniel@0 15000 active = this.tabs.length ? 0 : false;
Daniel@0 15001 }
Daniel@0 15002 }
Daniel@0 15003
Daniel@0 15004 // handle numbers: negative, out of range
Daniel@0 15005 if ( active !== false ) {
Daniel@0 15006 active = this.tabs.index( this.tabs.eq( active ) );
Daniel@0 15007 if ( active === -1 ) {
Daniel@0 15008 active = collapsible ? false : 0;
Daniel@0 15009 }
Daniel@0 15010 }
Daniel@0 15011
Daniel@0 15012 // don't allow collapsible: false and active: false
Daniel@0 15013 if ( !collapsible && active === false && this.anchors.length ) {
Daniel@0 15014 active = 0;
Daniel@0 15015 }
Daniel@0 15016
Daniel@0 15017 return active;
Daniel@0 15018 },
Daniel@0 15019
Daniel@0 15020 _getCreateEventData: function() {
Daniel@0 15021 return {
Daniel@0 15022 tab: this.active,
Daniel@0 15023 panel: !this.active.length ? $() : this._getPanelForTab( this.active )
Daniel@0 15024 };
Daniel@0 15025 },
Daniel@0 15026
Daniel@0 15027 _tabKeydown: function( event ) {
Daniel@0 15028 var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
Daniel@0 15029 selectedIndex = this.tabs.index( focusedTab ),
Daniel@0 15030 goingForward = true;
Daniel@0 15031
Daniel@0 15032 if ( this._handlePageNav( event ) ) {
Daniel@0 15033 return;
Daniel@0 15034 }
Daniel@0 15035
Daniel@0 15036 switch ( event.keyCode ) {
Daniel@0 15037 case $.ui.keyCode.RIGHT:
Daniel@0 15038 case $.ui.keyCode.DOWN:
Daniel@0 15039 selectedIndex++;
Daniel@0 15040 break;
Daniel@0 15041 case $.ui.keyCode.UP:
Daniel@0 15042 case $.ui.keyCode.LEFT:
Daniel@0 15043 goingForward = false;
Daniel@0 15044 selectedIndex--;
Daniel@0 15045 break;
Daniel@0 15046 case $.ui.keyCode.END:
Daniel@0 15047 selectedIndex = this.anchors.length - 1;
Daniel@0 15048 break;
Daniel@0 15049 case $.ui.keyCode.HOME:
Daniel@0 15050 selectedIndex = 0;
Daniel@0 15051 break;
Daniel@0 15052 case $.ui.keyCode.SPACE:
Daniel@0 15053 // Activate only, no collapsing
Daniel@0 15054 event.preventDefault();
Daniel@0 15055 clearTimeout( this.activating );
Daniel@0 15056 this._activate( selectedIndex );
Daniel@0 15057 return;
Daniel@0 15058 case $.ui.keyCode.ENTER:
Daniel@0 15059 // Toggle (cancel delayed activation, allow collapsing)
Daniel@0 15060 event.preventDefault();
Daniel@0 15061 clearTimeout( this.activating );
Daniel@0 15062 // Determine if we should collapse or activate
Daniel@0 15063 this._activate( selectedIndex === this.options.active ? false : selectedIndex );
Daniel@0 15064 return;
Daniel@0 15065 default:
Daniel@0 15066 return;
Daniel@0 15067 }
Daniel@0 15068
Daniel@0 15069 // Focus the appropriate tab, based on which key was pressed
Daniel@0 15070 event.preventDefault();
Daniel@0 15071 clearTimeout( this.activating );
Daniel@0 15072 selectedIndex = this._focusNextTab( selectedIndex, goingForward );
Daniel@0 15073
Daniel@0 15074 // Navigating with control key will prevent automatic activation
Daniel@0 15075 if ( !event.ctrlKey ) {
Daniel@0 15076 // Update aria-selected immediately so that AT think the tab is already selected.
Daniel@0 15077 // Otherwise AT may confuse the user by stating that they need to activate the tab,
Daniel@0 15078 // but the tab will already be activated by the time the announcement finishes.
Daniel@0 15079 focusedTab.attr( "aria-selected", "false" );
Daniel@0 15080 this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
Daniel@0 15081
Daniel@0 15082 this.activating = this._delay(function() {
Daniel@0 15083 this.option( "active", selectedIndex );
Daniel@0 15084 }, this.delay );
Daniel@0 15085 }
Daniel@0 15086 },
Daniel@0 15087
Daniel@0 15088 _panelKeydown: function( event ) {
Daniel@0 15089 if ( this._handlePageNav( event ) ) {
Daniel@0 15090 return;
Daniel@0 15091 }
Daniel@0 15092
Daniel@0 15093 // Ctrl+up moves focus to the current tab
Daniel@0 15094 if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
Daniel@0 15095 event.preventDefault();
Daniel@0 15096 this.active.focus();
Daniel@0 15097 }
Daniel@0 15098 },
Daniel@0 15099
Daniel@0 15100 // Alt+page up/down moves focus to the previous/next tab (and activates)
Daniel@0 15101 _handlePageNav: function( event ) {
Daniel@0 15102 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
Daniel@0 15103 this._activate( this._focusNextTab( this.options.active - 1, false ) );
Daniel@0 15104 return true;
Daniel@0 15105 }
Daniel@0 15106 if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
Daniel@0 15107 this._activate( this._focusNextTab( this.options.active + 1, true ) );
Daniel@0 15108 return true;
Daniel@0 15109 }
Daniel@0 15110 },
Daniel@0 15111
Daniel@0 15112 _findNextTab: function( index, goingForward ) {
Daniel@0 15113 var lastTabIndex = this.tabs.length - 1;
Daniel@0 15114
Daniel@0 15115 function constrain() {
Daniel@0 15116 if ( index > lastTabIndex ) {
Daniel@0 15117 index = 0;
Daniel@0 15118 }
Daniel@0 15119 if ( index < 0 ) {
Daniel@0 15120 index = lastTabIndex;
Daniel@0 15121 }
Daniel@0 15122 return index;
Daniel@0 15123 }
Daniel@0 15124
Daniel@0 15125 while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
Daniel@0 15126 index = goingForward ? index + 1 : index - 1;
Daniel@0 15127 }
Daniel@0 15128
Daniel@0 15129 return index;
Daniel@0 15130 },
Daniel@0 15131
Daniel@0 15132 _focusNextTab: function( index, goingForward ) {
Daniel@0 15133 index = this._findNextTab( index, goingForward );
Daniel@0 15134 this.tabs.eq( index ).focus();
Daniel@0 15135 return index;
Daniel@0 15136 },
Daniel@0 15137
Daniel@0 15138 _setOption: function( key, value ) {
Daniel@0 15139 if ( key === "active" ) {
Daniel@0 15140 // _activate() will handle invalid values and update this.options
Daniel@0 15141 this._activate( value );
Daniel@0 15142 return;
Daniel@0 15143 }
Daniel@0 15144
Daniel@0 15145 if ( key === "disabled" ) {
Daniel@0 15146 // don't use the widget factory's disabled handling
Daniel@0 15147 this._setupDisabled( value );
Daniel@0 15148 return;
Daniel@0 15149 }
Daniel@0 15150
Daniel@0 15151 this._super( key, value);
Daniel@0 15152
Daniel@0 15153 if ( key === "collapsible" ) {
Daniel@0 15154 this.element.toggleClass( "ui-tabs-collapsible", value );
Daniel@0 15155 // Setting collapsible: false while collapsed; open first panel
Daniel@0 15156 if ( !value && this.options.active === false ) {
Daniel@0 15157 this._activate( 0 );
Daniel@0 15158 }
Daniel@0 15159 }
Daniel@0 15160
Daniel@0 15161 if ( key === "event" ) {
Daniel@0 15162 this._setupEvents( value );
Daniel@0 15163 }
Daniel@0 15164
Daniel@0 15165 if ( key === "heightStyle" ) {
Daniel@0 15166 this._setupHeightStyle( value );
Daniel@0 15167 }
Daniel@0 15168 },
Daniel@0 15169
Daniel@0 15170 _sanitizeSelector: function( hash ) {
Daniel@0 15171 return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
Daniel@0 15172 },
Daniel@0 15173
Daniel@0 15174 refresh: function() {
Daniel@0 15175 var options = this.options,
Daniel@0 15176 lis = this.tablist.children( ":has(a[href])" );
Daniel@0 15177
Daniel@0 15178 // get disabled tabs from class attribute from HTML
Daniel@0 15179 // this will get converted to a boolean if needed in _refresh()
Daniel@0 15180 options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
Daniel@0 15181 return lis.index( tab );
Daniel@0 15182 });
Daniel@0 15183
Daniel@0 15184 this._processTabs();
Daniel@0 15185
Daniel@0 15186 // was collapsed or no tabs
Daniel@0 15187 if ( options.active === false || !this.anchors.length ) {
Daniel@0 15188 options.active = false;
Daniel@0 15189 this.active = $();
Daniel@0 15190 // was active, but active tab is gone
Daniel@0 15191 } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
Daniel@0 15192 // all remaining tabs are disabled
Daniel@0 15193 if ( this.tabs.length === options.disabled.length ) {
Daniel@0 15194 options.active = false;
Daniel@0 15195 this.active = $();
Daniel@0 15196 // activate previous tab
Daniel@0 15197 } else {
Daniel@0 15198 this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
Daniel@0 15199 }
Daniel@0 15200 // was active, active tab still exists
Daniel@0 15201 } else {
Daniel@0 15202 // make sure active index is correct
Daniel@0 15203 options.active = this.tabs.index( this.active );
Daniel@0 15204 }
Daniel@0 15205
Daniel@0 15206 this._refresh();
Daniel@0 15207 },
Daniel@0 15208
Daniel@0 15209 _refresh: function() {
Daniel@0 15210 this._setupDisabled( this.options.disabled );
Daniel@0 15211 this._setupEvents( this.options.event );
Daniel@0 15212 this._setupHeightStyle( this.options.heightStyle );
Daniel@0 15213
Daniel@0 15214 this.tabs.not( this.active ).attr({
Daniel@0 15215 "aria-selected": "false",
Daniel@0 15216 "aria-expanded": "false",
Daniel@0 15217 tabIndex: -1
Daniel@0 15218 });
Daniel@0 15219 this.panels.not( this._getPanelForTab( this.active ) )
Daniel@0 15220 .hide()
Daniel@0 15221 .attr({
Daniel@0 15222 "aria-hidden": "true"
Daniel@0 15223 });
Daniel@0 15224
Daniel@0 15225 // Make sure one tab is in the tab order
Daniel@0 15226 if ( !this.active.length ) {
Daniel@0 15227 this.tabs.eq( 0 ).attr( "tabIndex", 0 );
Daniel@0 15228 } else {
Daniel@0 15229 this.active
Daniel@0 15230 .addClass( "ui-tabs-active ui-state-active" )
Daniel@0 15231 .attr({
Daniel@0 15232 "aria-selected": "true",
Daniel@0 15233 "aria-expanded": "true",
Daniel@0 15234 tabIndex: 0
Daniel@0 15235 });
Daniel@0 15236 this._getPanelForTab( this.active )
Daniel@0 15237 .show()
Daniel@0 15238 .attr({
Daniel@0 15239 "aria-hidden": "false"
Daniel@0 15240 });
Daniel@0 15241 }
Daniel@0 15242 },
Daniel@0 15243
Daniel@0 15244 _processTabs: function() {
Daniel@0 15245 var that = this;
Daniel@0 15246
Daniel@0 15247 this.tablist = this._getList()
Daniel@0 15248 .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
Daniel@0 15249 .attr( "role", "tablist" );
Daniel@0 15250
Daniel@0 15251 this.tabs = this.tablist.find( "> li:has(a[href])" )
Daniel@0 15252 .addClass( "ui-state-default ui-corner-top" )
Daniel@0 15253 .attr({
Daniel@0 15254 role: "tab",
Daniel@0 15255 tabIndex: -1
Daniel@0 15256 });
Daniel@0 15257
Daniel@0 15258 this.anchors = this.tabs.map(function() {
Daniel@0 15259 return $( "a", this )[ 0 ];
Daniel@0 15260 })
Daniel@0 15261 .addClass( "ui-tabs-anchor" )
Daniel@0 15262 .attr({
Daniel@0 15263 role: "presentation",
Daniel@0 15264 tabIndex: -1
Daniel@0 15265 });
Daniel@0 15266
Daniel@0 15267 this.panels = $();
Daniel@0 15268
Daniel@0 15269 this.anchors.each(function( i, anchor ) {
Daniel@0 15270 var selector, panel, panelId,
Daniel@0 15271 anchorId = $( anchor ).uniqueId().attr( "id" ),
Daniel@0 15272 tab = $( anchor ).closest( "li" ),
Daniel@0 15273 originalAriaControls = tab.attr( "aria-controls" );
Daniel@0 15274
Daniel@0 15275 // inline tab
Daniel@0 15276 if ( that._isLocal( anchor ) ) {
Daniel@0 15277 selector = anchor.hash;
Daniel@0 15278 panelId = selector.substring( 1 );
Daniel@0 15279 panel = that.element.find( that._sanitizeSelector( selector ) );
Daniel@0 15280 // remote tab
Daniel@0 15281 } else {
Daniel@0 15282 // If the tab doesn't already have aria-controls,
Daniel@0 15283 // generate an id by using a throw-away element
Daniel@0 15284 panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
Daniel@0 15285 selector = "#" + panelId;
Daniel@0 15286 panel = that.element.find( selector );
Daniel@0 15287 if ( !panel.length ) {
Daniel@0 15288 panel = that._createPanel( panelId );
Daniel@0 15289 panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
Daniel@0 15290 }
Daniel@0 15291 panel.attr( "aria-live", "polite" );
Daniel@0 15292 }
Daniel@0 15293
Daniel@0 15294 if ( panel.length) {
Daniel@0 15295 that.panels = that.panels.add( panel );
Daniel@0 15296 }
Daniel@0 15297 if ( originalAriaControls ) {
Daniel@0 15298 tab.data( "ui-tabs-aria-controls", originalAriaControls );
Daniel@0 15299 }
Daniel@0 15300 tab.attr({
Daniel@0 15301 "aria-controls": panelId,
Daniel@0 15302 "aria-labelledby": anchorId
Daniel@0 15303 });
Daniel@0 15304 panel.attr( "aria-labelledby", anchorId );
Daniel@0 15305 });
Daniel@0 15306
Daniel@0 15307 this.panels
Daniel@0 15308 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
Daniel@0 15309 .attr( "role", "tabpanel" );
Daniel@0 15310 },
Daniel@0 15311
Daniel@0 15312 // allow overriding how to find the list for rare usage scenarios (#7715)
Daniel@0 15313 _getList: function() {
Daniel@0 15314 return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
Daniel@0 15315 },
Daniel@0 15316
Daniel@0 15317 _createPanel: function( id ) {
Daniel@0 15318 return $( "<div>" )
Daniel@0 15319 .attr( "id", id )
Daniel@0 15320 .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
Daniel@0 15321 .data( "ui-tabs-destroy", true );
Daniel@0 15322 },
Daniel@0 15323
Daniel@0 15324 _setupDisabled: function( disabled ) {
Daniel@0 15325 if ( $.isArray( disabled ) ) {
Daniel@0 15326 if ( !disabled.length ) {
Daniel@0 15327 disabled = false;
Daniel@0 15328 } else if ( disabled.length === this.anchors.length ) {
Daniel@0 15329 disabled = true;
Daniel@0 15330 }
Daniel@0 15331 }
Daniel@0 15332
Daniel@0 15333 // disable tabs
Daniel@0 15334 for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
Daniel@0 15335 if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
Daniel@0 15336 $( li )
Daniel@0 15337 .addClass( "ui-state-disabled" )
Daniel@0 15338 .attr( "aria-disabled", "true" );
Daniel@0 15339 } else {
Daniel@0 15340 $( li )
Daniel@0 15341 .removeClass( "ui-state-disabled" )
Daniel@0 15342 .removeAttr( "aria-disabled" );
Daniel@0 15343 }
Daniel@0 15344 }
Daniel@0 15345
Daniel@0 15346 this.options.disabled = disabled;
Daniel@0 15347 },
Daniel@0 15348
Daniel@0 15349 _setupEvents: function( event ) {
Daniel@0 15350 var events = {};
Daniel@0 15351 if ( event ) {
Daniel@0 15352 $.each( event.split(" "), function( index, eventName ) {
Daniel@0 15353 events[ eventName ] = "_eventHandler";
Daniel@0 15354 });
Daniel@0 15355 }
Daniel@0 15356
Daniel@0 15357 this._off( this.anchors.add( this.tabs ).add( this.panels ) );
Daniel@0 15358 // Always prevent the default action, even when disabled
Daniel@0 15359 this._on( true, this.anchors, {
Daniel@0 15360 click: function( event ) {
Daniel@0 15361 event.preventDefault();
Daniel@0 15362 }
Daniel@0 15363 });
Daniel@0 15364 this._on( this.anchors, events );
Daniel@0 15365 this._on( this.tabs, { keydown: "_tabKeydown" } );
Daniel@0 15366 this._on( this.panels, { keydown: "_panelKeydown" } );
Daniel@0 15367
Daniel@0 15368 this._focusable( this.tabs );
Daniel@0 15369 this._hoverable( this.tabs );
Daniel@0 15370 },
Daniel@0 15371
Daniel@0 15372 _setupHeightStyle: function( heightStyle ) {
Daniel@0 15373 var maxHeight,
Daniel@0 15374 parent = this.element.parent();
Daniel@0 15375
Daniel@0 15376 if ( heightStyle === "fill" ) {
Daniel@0 15377 maxHeight = parent.height();
Daniel@0 15378 maxHeight -= this.element.outerHeight() - this.element.height();
Daniel@0 15379
Daniel@0 15380 this.element.siblings( ":visible" ).each(function() {
Daniel@0 15381 var elem = $( this ),
Daniel@0 15382 position = elem.css( "position" );
Daniel@0 15383
Daniel@0 15384 if ( position === "absolute" || position === "fixed" ) {
Daniel@0 15385 return;
Daniel@0 15386 }
Daniel@0 15387 maxHeight -= elem.outerHeight( true );
Daniel@0 15388 });
Daniel@0 15389
Daniel@0 15390 this.element.children().not( this.panels ).each(function() {
Daniel@0 15391 maxHeight -= $( this ).outerHeight( true );
Daniel@0 15392 });
Daniel@0 15393
Daniel@0 15394 this.panels.each(function() {
Daniel@0 15395 $( this ).height( Math.max( 0, maxHeight -
Daniel@0 15396 $( this ).innerHeight() + $( this ).height() ) );
Daniel@0 15397 })
Daniel@0 15398 .css( "overflow", "auto" );
Daniel@0 15399 } else if ( heightStyle === "auto" ) {
Daniel@0 15400 maxHeight = 0;
Daniel@0 15401 this.panels.each(function() {
Daniel@0 15402 maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
Daniel@0 15403 }).height( maxHeight );
Daniel@0 15404 }
Daniel@0 15405 },
Daniel@0 15406
Daniel@0 15407 _eventHandler: function( event ) {
Daniel@0 15408 var options = this.options,
Daniel@0 15409 active = this.active,
Daniel@0 15410 anchor = $( event.currentTarget ),
Daniel@0 15411 tab = anchor.closest( "li" ),
Daniel@0 15412 clickedIsActive = tab[ 0 ] === active[ 0 ],
Daniel@0 15413 collapsing = clickedIsActive && options.collapsible,
Daniel@0 15414 toShow = collapsing ? $() : this._getPanelForTab( tab ),
Daniel@0 15415 toHide = !active.length ? $() : this._getPanelForTab( active ),
Daniel@0 15416 eventData = {
Daniel@0 15417 oldTab: active,
Daniel@0 15418 oldPanel: toHide,
Daniel@0 15419 newTab: collapsing ? $() : tab,
Daniel@0 15420 newPanel: toShow
Daniel@0 15421 };
Daniel@0 15422
Daniel@0 15423 event.preventDefault();
Daniel@0 15424
Daniel@0 15425 if ( tab.hasClass( "ui-state-disabled" ) ||
Daniel@0 15426 // tab is already loading
Daniel@0 15427 tab.hasClass( "ui-tabs-loading" ) ||
Daniel@0 15428 // can't switch durning an animation
Daniel@0 15429 this.running ||
Daniel@0 15430 // click on active header, but not collapsible
Daniel@0 15431 ( clickedIsActive && !options.collapsible ) ||
Daniel@0 15432 // allow canceling activation
Daniel@0 15433 ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
Daniel@0 15434 return;
Daniel@0 15435 }
Daniel@0 15436
Daniel@0 15437 options.active = collapsing ? false : this.tabs.index( tab );
Daniel@0 15438
Daniel@0 15439 this.active = clickedIsActive ? $() : tab;
Daniel@0 15440 if ( this.xhr ) {
Daniel@0 15441 this.xhr.abort();
Daniel@0 15442 }
Daniel@0 15443
Daniel@0 15444 if ( !toHide.length && !toShow.length ) {
Daniel@0 15445 $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
Daniel@0 15446 }
Daniel@0 15447
Daniel@0 15448 if ( toShow.length ) {
Daniel@0 15449 this.load( this.tabs.index( tab ), event );
Daniel@0 15450 }
Daniel@0 15451 this._toggle( event, eventData );
Daniel@0 15452 },
Daniel@0 15453
Daniel@0 15454 // handles show/hide for selecting tabs
Daniel@0 15455 _toggle: function( event, eventData ) {
Daniel@0 15456 var that = this,
Daniel@0 15457 toShow = eventData.newPanel,
Daniel@0 15458 toHide = eventData.oldPanel;
Daniel@0 15459
Daniel@0 15460 this.running = true;
Daniel@0 15461
Daniel@0 15462 function complete() {
Daniel@0 15463 that.running = false;
Daniel@0 15464 that._trigger( "activate", event, eventData );
Daniel@0 15465 }
Daniel@0 15466
Daniel@0 15467 function show() {
Daniel@0 15468 eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
Daniel@0 15469
Daniel@0 15470 if ( toShow.length && that.options.show ) {
Daniel@0 15471 that._show( toShow, that.options.show, complete );
Daniel@0 15472 } else {
Daniel@0 15473 toShow.show();
Daniel@0 15474 complete();
Daniel@0 15475 }
Daniel@0 15476 }
Daniel@0 15477
Daniel@0 15478 // start out by hiding, then showing, then completing
Daniel@0 15479 if ( toHide.length && this.options.hide ) {
Daniel@0 15480 this._hide( toHide, this.options.hide, function() {
Daniel@0 15481 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
Daniel@0 15482 show();
Daniel@0 15483 });
Daniel@0 15484 } else {
Daniel@0 15485 eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
Daniel@0 15486 toHide.hide();
Daniel@0 15487 show();
Daniel@0 15488 }
Daniel@0 15489
Daniel@0 15490 toHide.attr( "aria-hidden", "true" );
Daniel@0 15491 eventData.oldTab.attr({
Daniel@0 15492 "aria-selected": "false",
Daniel@0 15493 "aria-expanded": "false"
Daniel@0 15494 });
Daniel@0 15495 // If we're switching tabs, remove the old tab from the tab order.
Daniel@0 15496 // If we're opening from collapsed state, remove the previous tab from the tab order.
Daniel@0 15497 // If we're collapsing, then keep the collapsing tab in the tab order.
Daniel@0 15498 if ( toShow.length && toHide.length ) {
Daniel@0 15499 eventData.oldTab.attr( "tabIndex", -1 );
Daniel@0 15500 } else if ( toShow.length ) {
Daniel@0 15501 this.tabs.filter(function() {
Daniel@0 15502 return $( this ).attr( "tabIndex" ) === 0;
Daniel@0 15503 })
Daniel@0 15504 .attr( "tabIndex", -1 );
Daniel@0 15505 }
Daniel@0 15506
Daniel@0 15507 toShow.attr( "aria-hidden", "false" );
Daniel@0 15508 eventData.newTab.attr({
Daniel@0 15509 "aria-selected": "true",
Daniel@0 15510 "aria-expanded": "true",
Daniel@0 15511 tabIndex: 0
Daniel@0 15512 });
Daniel@0 15513 },
Daniel@0 15514
Daniel@0 15515 _activate: function( index ) {
Daniel@0 15516 var anchor,
Daniel@0 15517 active = this._findActive( index );
Daniel@0 15518
Daniel@0 15519 // trying to activate the already active panel
Daniel@0 15520 if ( active[ 0 ] === this.active[ 0 ] ) {
Daniel@0 15521 return;
Daniel@0 15522 }
Daniel@0 15523
Daniel@0 15524 // trying to collapse, simulate a click on the current active header
Daniel@0 15525 if ( !active.length ) {
Daniel@0 15526 active = this.active;
Daniel@0 15527 }
Daniel@0 15528
Daniel@0 15529 anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
Daniel@0 15530 this._eventHandler({
Daniel@0 15531 target: anchor,
Daniel@0 15532 currentTarget: anchor,
Daniel@0 15533 preventDefault: $.noop
Daniel@0 15534 });
Daniel@0 15535 },
Daniel@0 15536
Daniel@0 15537 _findActive: function( index ) {
Daniel@0 15538 return index === false ? $() : this.tabs.eq( index );
Daniel@0 15539 },
Daniel@0 15540
Daniel@0 15541 _getIndex: function( index ) {
Daniel@0 15542 // meta-function to give users option to provide a href string instead of a numerical index.
Daniel@0 15543 if ( typeof index === "string" ) {
Daniel@0 15544 index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
Daniel@0 15545 }
Daniel@0 15546
Daniel@0 15547 return index;
Daniel@0 15548 },
Daniel@0 15549
Daniel@0 15550 _destroy: function() {
Daniel@0 15551 if ( this.xhr ) {
Daniel@0 15552 this.xhr.abort();
Daniel@0 15553 }
Daniel@0 15554
Daniel@0 15555 this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
Daniel@0 15556
Daniel@0 15557 this.tablist
Daniel@0 15558 .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
Daniel@0 15559 .removeAttr( "role" );
Daniel@0 15560
Daniel@0 15561 this.anchors
Daniel@0 15562 .removeClass( "ui-tabs-anchor" )
Daniel@0 15563 .removeAttr( "role" )
Daniel@0 15564 .removeAttr( "tabIndex" )
Daniel@0 15565 .removeUniqueId();
Daniel@0 15566
Daniel@0 15567 this.tabs.add( this.panels ).each(function() {
Daniel@0 15568 if ( $.data( this, "ui-tabs-destroy" ) ) {
Daniel@0 15569 $( this ).remove();
Daniel@0 15570 } else {
Daniel@0 15571 $( this )
Daniel@0 15572 .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
Daniel@0 15573 "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
Daniel@0 15574 .removeAttr( "tabIndex" )
Daniel@0 15575 .removeAttr( "aria-live" )
Daniel@0 15576 .removeAttr( "aria-busy" )
Daniel@0 15577 .removeAttr( "aria-selected" )
Daniel@0 15578 .removeAttr( "aria-labelledby" )
Daniel@0 15579 .removeAttr( "aria-hidden" )
Daniel@0 15580 .removeAttr( "aria-expanded" )
Daniel@0 15581 .removeAttr( "role" );
Daniel@0 15582 }
Daniel@0 15583 });
Daniel@0 15584
Daniel@0 15585 this.tabs.each(function() {
Daniel@0 15586 var li = $( this ),
Daniel@0 15587 prev = li.data( "ui-tabs-aria-controls" );
Daniel@0 15588 if ( prev ) {
Daniel@0 15589 li
Daniel@0 15590 .attr( "aria-controls", prev )
Daniel@0 15591 .removeData( "ui-tabs-aria-controls" );
Daniel@0 15592 } else {
Daniel@0 15593 li.removeAttr( "aria-controls" );
Daniel@0 15594 }
Daniel@0 15595 });
Daniel@0 15596
Daniel@0 15597 this.panels.show();
Daniel@0 15598
Daniel@0 15599 if ( this.options.heightStyle !== "content" ) {
Daniel@0 15600 this.panels.css( "height", "" );
Daniel@0 15601 }
Daniel@0 15602 },
Daniel@0 15603
Daniel@0 15604 enable: function( index ) {
Daniel@0 15605 var disabled = this.options.disabled;
Daniel@0 15606 if ( disabled === false ) {
Daniel@0 15607 return;
Daniel@0 15608 }
Daniel@0 15609
Daniel@0 15610 if ( index === undefined ) {
Daniel@0 15611 disabled = false;
Daniel@0 15612 } else {
Daniel@0 15613 index = this._getIndex( index );
Daniel@0 15614 if ( $.isArray( disabled ) ) {
Daniel@0 15615 disabled = $.map( disabled, function( num ) {
Daniel@0 15616 return num !== index ? num : null;
Daniel@0 15617 });
Daniel@0 15618 } else {
Daniel@0 15619 disabled = $.map( this.tabs, function( li, num ) {
Daniel@0 15620 return num !== index ? num : null;
Daniel@0 15621 });
Daniel@0 15622 }
Daniel@0 15623 }
Daniel@0 15624 this._setupDisabled( disabled );
Daniel@0 15625 },
Daniel@0 15626
Daniel@0 15627 disable: function( index ) {
Daniel@0 15628 var disabled = this.options.disabled;
Daniel@0 15629 if ( disabled === true ) {
Daniel@0 15630 return;
Daniel@0 15631 }
Daniel@0 15632
Daniel@0 15633 if ( index === undefined ) {
Daniel@0 15634 disabled = true;
Daniel@0 15635 } else {
Daniel@0 15636 index = this._getIndex( index );
Daniel@0 15637 if ( $.inArray( index, disabled ) !== -1 ) {
Daniel@0 15638 return;
Daniel@0 15639 }
Daniel@0 15640 if ( $.isArray( disabled ) ) {
Daniel@0 15641 disabled = $.merge( [ index ], disabled ).sort();
Daniel@0 15642 } else {
Daniel@0 15643 disabled = [ index ];
Daniel@0 15644 }
Daniel@0 15645 }
Daniel@0 15646 this._setupDisabled( disabled );
Daniel@0 15647 },
Daniel@0 15648
Daniel@0 15649 load: function( index, event ) {
Daniel@0 15650 index = this._getIndex( index );
Daniel@0 15651 var that = this,
Daniel@0 15652 tab = this.tabs.eq( index ),
Daniel@0 15653 anchor = tab.find( ".ui-tabs-anchor" ),
Daniel@0 15654 panel = this._getPanelForTab( tab ),
Daniel@0 15655 eventData = {
Daniel@0 15656 tab: tab,
Daniel@0 15657 panel: panel
Daniel@0 15658 };
Daniel@0 15659
Daniel@0 15660 // not remote
Daniel@0 15661 if ( this._isLocal( anchor[ 0 ] ) ) {
Daniel@0 15662 return;
Daniel@0 15663 }
Daniel@0 15664
Daniel@0 15665 this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
Daniel@0 15666
Daniel@0 15667 // support: jQuery <1.8
Daniel@0 15668 // jQuery <1.8 returns false if the request is canceled in beforeSend,
Daniel@0 15669 // but as of 1.8, $.ajax() always returns a jqXHR object.
Daniel@0 15670 if ( this.xhr && this.xhr.statusText !== "canceled" ) {
Daniel@0 15671 tab.addClass( "ui-tabs-loading" );
Daniel@0 15672 panel.attr( "aria-busy", "true" );
Daniel@0 15673
Daniel@0 15674 this.xhr
Daniel@0 15675 .success(function( response ) {
Daniel@0 15676 // support: jQuery <1.8
Daniel@0 15677 // http://bugs.jquery.com/ticket/11778
Daniel@0 15678 setTimeout(function() {
Daniel@0 15679 panel.html( response );
Daniel@0 15680 that._trigger( "load", event, eventData );
Daniel@0 15681 }, 1 );
Daniel@0 15682 })
Daniel@0 15683 .complete(function( jqXHR, status ) {
Daniel@0 15684 // support: jQuery <1.8
Daniel@0 15685 // http://bugs.jquery.com/ticket/11778
Daniel@0 15686 setTimeout(function() {
Daniel@0 15687 if ( status === "abort" ) {
Daniel@0 15688 that.panels.stop( false, true );
Daniel@0 15689 }
Daniel@0 15690
Daniel@0 15691 tab.removeClass( "ui-tabs-loading" );
Daniel@0 15692 panel.removeAttr( "aria-busy" );
Daniel@0 15693
Daniel@0 15694 if ( jqXHR === that.xhr ) {
Daniel@0 15695 delete that.xhr;
Daniel@0 15696 }
Daniel@0 15697 }, 1 );
Daniel@0 15698 });
Daniel@0 15699 }
Daniel@0 15700 },
Daniel@0 15701
Daniel@0 15702 _ajaxSettings: function( anchor, event, eventData ) {
Daniel@0 15703 var that = this;
Daniel@0 15704 return {
Daniel@0 15705 url: anchor.attr( "href" ),
Daniel@0 15706 beforeSend: function( jqXHR, settings ) {
Daniel@0 15707 return that._trigger( "beforeLoad", event,
Daniel@0 15708 $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
Daniel@0 15709 }
Daniel@0 15710 };
Daniel@0 15711 },
Daniel@0 15712
Daniel@0 15713 _getPanelForTab: function( tab ) {
Daniel@0 15714 var id = $( tab ).attr( "aria-controls" );
Daniel@0 15715 return this.element.find( this._sanitizeSelector( "#" + id ) );
Daniel@0 15716 }
Daniel@0 15717 });
Daniel@0 15718
Daniel@0 15719
Daniel@0 15720 /*!
Daniel@0 15721 * jQuery UI Tooltip 1.11.0
Daniel@0 15722 * http://jqueryui.com
Daniel@0 15723 *
Daniel@0 15724 * Copyright 2014 jQuery Foundation and other contributors
Daniel@0 15725 * Released under the MIT license.
Daniel@0 15726 * http://jquery.org/license
Daniel@0 15727 *
Daniel@0 15728 * http://api.jqueryui.com/tooltip/
Daniel@0 15729 */
Daniel@0 15730
Daniel@0 15731
Daniel@0 15732 var tooltip = $.widget( "ui.tooltip", {
Daniel@0 15733 version: "1.11.0",
Daniel@0 15734 options: {
Daniel@0 15735 content: function() {
Daniel@0 15736 // support: IE<9, Opera in jQuery <1.7
Daniel@0 15737 // .text() can't accept undefined, so coerce to a string
Daniel@0 15738 var title = $( this ).attr( "title" ) || "";
Daniel@0 15739 // Escape title, since we're going from an attribute to raw HTML
Daniel@0 15740 return $( "<a>" ).text( title ).html();
Daniel@0 15741 },
Daniel@0 15742 hide: true,
Daniel@0 15743 // Disabled elements have inconsistent behavior across browsers (#8661)
Daniel@0 15744 items: "[title]:not([disabled])",
Daniel@0 15745 position: {
Daniel@0 15746 my: "left top+15",
Daniel@0 15747 at: "left bottom",
Daniel@0 15748 collision: "flipfit flip"
Daniel@0 15749 },
Daniel@0 15750 show: true,
Daniel@0 15751 tooltipClass: null,
Daniel@0 15752 track: false,
Daniel@0 15753
Daniel@0 15754 // callbacks
Daniel@0 15755 close: null,
Daniel@0 15756 open: null
Daniel@0 15757 },
Daniel@0 15758
Daniel@0 15759 _addDescribedBy: function( elem, id ) {
Daniel@0 15760 var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
Daniel@0 15761 describedby.push( id );
Daniel@0 15762 elem
Daniel@0 15763 .data( "ui-tooltip-id", id )
Daniel@0 15764 .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
Daniel@0 15765 },
Daniel@0 15766
Daniel@0 15767 _removeDescribedBy: function( elem ) {
Daniel@0 15768 var id = elem.data( "ui-tooltip-id" ),
Daniel@0 15769 describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
Daniel@0 15770 index = $.inArray( id, describedby );
Daniel@0 15771
Daniel@0 15772 if ( index !== -1 ) {
Daniel@0 15773 describedby.splice( index, 1 );
Daniel@0 15774 }
Daniel@0 15775
Daniel@0 15776 elem.removeData( "ui-tooltip-id" );
Daniel@0 15777 describedby = $.trim( describedby.join( " " ) );
Daniel@0 15778 if ( describedby ) {
Daniel@0 15779 elem.attr( "aria-describedby", describedby );
Daniel@0 15780 } else {
Daniel@0 15781 elem.removeAttr( "aria-describedby" );
Daniel@0 15782 }
Daniel@0 15783 },
Daniel@0 15784
Daniel@0 15785 _create: function() {
Daniel@0 15786 this._on({
Daniel@0 15787 mouseover: "open",
Daniel@0 15788 focusin: "open"
Daniel@0 15789 });
Daniel@0 15790
Daniel@0 15791 // IDs of generated tooltips, needed for destroy
Daniel@0 15792 this.tooltips = {};
Daniel@0 15793 // IDs of parent tooltips where we removed the title attribute
Daniel@0 15794 this.parents = {};
Daniel@0 15795
Daniel@0 15796 if ( this.options.disabled ) {
Daniel@0 15797 this._disable();
Daniel@0 15798 }
Daniel@0 15799
Daniel@0 15800 // Append the aria-live region so tooltips announce correctly
Daniel@0 15801 this.liveRegion = $( "<div>" )
Daniel@0 15802 .attr({
Daniel@0 15803 role: "log",
Daniel@0 15804 "aria-live": "assertive",
Daniel@0 15805 "aria-relevant": "additions"
Daniel@0 15806 })
Daniel@0 15807 .addClass( "ui-helper-hidden-accessible" )
Daniel@0 15808 .appendTo( this.document[ 0 ].body );
Daniel@0 15809 },
Daniel@0 15810
Daniel@0 15811 _setOption: function( key, value ) {
Daniel@0 15812 var that = this;
Daniel@0 15813
Daniel@0 15814 if ( key === "disabled" ) {
Daniel@0 15815 this[ value ? "_disable" : "_enable" ]();
Daniel@0 15816 this.options[ key ] = value;
Daniel@0 15817 // disable element style changes
Daniel@0 15818 return;
Daniel@0 15819 }
Daniel@0 15820
Daniel@0 15821 this._super( key, value );
Daniel@0 15822
Daniel@0 15823 if ( key === "content" ) {
Daniel@0 15824 $.each( this.tooltips, function( id, element ) {
Daniel@0 15825 that._updateContent( element );
Daniel@0 15826 });
Daniel@0 15827 }
Daniel@0 15828 },
Daniel@0 15829
Daniel@0 15830 _disable: function() {
Daniel@0 15831 var that = this;
Daniel@0 15832
Daniel@0 15833 // close open tooltips
Daniel@0 15834 $.each( this.tooltips, function( id, element ) {
Daniel@0 15835 var event = $.Event( "blur" );
Daniel@0 15836 event.target = event.currentTarget = element[0];
Daniel@0 15837 that.close( event, true );
Daniel@0 15838 });
Daniel@0 15839
Daniel@0 15840 // remove title attributes to prevent native tooltips
Daniel@0 15841 this.element.find( this.options.items ).addBack().each(function() {
Daniel@0 15842 var element = $( this );
Daniel@0 15843 if ( element.is( "[title]" ) ) {
Daniel@0 15844 element
Daniel@0 15845 .data( "ui-tooltip-title", element.attr( "title" ) )
Daniel@0 15846 .removeAttr( "title" );
Daniel@0 15847 }
Daniel@0 15848 });
Daniel@0 15849 },
Daniel@0 15850
Daniel@0 15851 _enable: function() {
Daniel@0 15852 // restore title attributes
Daniel@0 15853 this.element.find( this.options.items ).addBack().each(function() {
Daniel@0 15854 var element = $( this );
Daniel@0 15855 if ( element.data( "ui-tooltip-title" ) ) {
Daniel@0 15856 element.attr( "title", element.data( "ui-tooltip-title" ) );
Daniel@0 15857 }
Daniel@0 15858 });
Daniel@0 15859 },
Daniel@0 15860
Daniel@0 15861 open: function( event ) {
Daniel@0 15862 var that = this,
Daniel@0 15863 target = $( event ? event.target : this.element )
Daniel@0 15864 // we need closest here due to mouseover bubbling,
Daniel@0 15865 // but always pointing at the same event target
Daniel@0 15866 .closest( this.options.items );
Daniel@0 15867
Daniel@0 15868 // No element to show a tooltip for or the tooltip is already open
Daniel@0 15869 if ( !target.length || target.data( "ui-tooltip-id" ) ) {
Daniel@0 15870 return;
Daniel@0 15871 }
Daniel@0 15872
Daniel@0 15873 if ( target.attr( "title" ) ) {
Daniel@0 15874 target.data( "ui-tooltip-title", target.attr( "title" ) );
Daniel@0 15875 }
Daniel@0 15876
Daniel@0 15877 target.data( "ui-tooltip-open", true );
Daniel@0 15878
Daniel@0 15879 // kill parent tooltips, custom or native, for hover
Daniel@0 15880 if ( event && event.type === "mouseover" ) {
Daniel@0 15881 target.parents().each(function() {
Daniel@0 15882 var parent = $( this ),
Daniel@0 15883 blurEvent;
Daniel@0 15884 if ( parent.data( "ui-tooltip-open" ) ) {
Daniel@0 15885 blurEvent = $.Event( "blur" );
Daniel@0 15886 blurEvent.target = blurEvent.currentTarget = this;
Daniel@0 15887 that.close( blurEvent, true );
Daniel@0 15888 }
Daniel@0 15889 if ( parent.attr( "title" ) ) {
Daniel@0 15890 parent.uniqueId();
Daniel@0 15891 that.parents[ this.id ] = {
Daniel@0 15892 element: this,
Daniel@0 15893 title: parent.attr( "title" )
Daniel@0 15894 };
Daniel@0 15895 parent.attr( "title", "" );
Daniel@0 15896 }
Daniel@0 15897 });
Daniel@0 15898 }
Daniel@0 15899
Daniel@0 15900 this._updateContent( target, event );
Daniel@0 15901 },
Daniel@0 15902
Daniel@0 15903 _updateContent: function( target, event ) {
Daniel@0 15904 var content,
Daniel@0 15905 contentOption = this.options.content,
Daniel@0 15906 that = this,
Daniel@0 15907 eventType = event ? event.type : null;
Daniel@0 15908
Daniel@0 15909 if ( typeof contentOption === "string" ) {
Daniel@0 15910 return this._open( event, target, contentOption );
Daniel@0 15911 }
Daniel@0 15912
Daniel@0 15913 content = contentOption.call( target[0], function( response ) {
Daniel@0 15914 // ignore async response if tooltip was closed already
Daniel@0 15915 if ( !target.data( "ui-tooltip-open" ) ) {
Daniel@0 15916 return;
Daniel@0 15917 }
Daniel@0 15918 // IE may instantly serve a cached response for ajax requests
Daniel@0 15919 // delay this call to _open so the other call to _open runs first
Daniel@0 15920 that._delay(function() {
Daniel@0 15921 // jQuery creates a special event for focusin when it doesn't
Daniel@0 15922 // exist natively. To improve performance, the native event
Daniel@0 15923 // object is reused and the type is changed. Therefore, we can't
Daniel@0 15924 // rely on the type being correct after the event finished
Daniel@0 15925 // bubbling, so we set it back to the previous value. (#8740)
Daniel@0 15926 if ( event ) {
Daniel@0 15927 event.type = eventType;
Daniel@0 15928 }
Daniel@0 15929 this._open( event, target, response );
Daniel@0 15930 });
Daniel@0 15931 });
Daniel@0 15932 if ( content ) {
Daniel@0 15933 this._open( event, target, content );
Daniel@0 15934 }
Daniel@0 15935 },
Daniel@0 15936
Daniel@0 15937 _open: function( event, target, content ) {
Daniel@0 15938 var tooltip, events, delayedShow, a11yContent,
Daniel@0 15939 positionOption = $.extend( {}, this.options.position );
Daniel@0 15940
Daniel@0 15941 if ( !content ) {
Daniel@0 15942 return;
Daniel@0 15943 }
Daniel@0 15944
Daniel@0 15945 // Content can be updated multiple times. If the tooltip already
Daniel@0 15946 // exists, then just update the content and bail.
Daniel@0 15947 tooltip = this._find( target );
Daniel@0 15948 if ( tooltip.length ) {
Daniel@0 15949 tooltip.find( ".ui-tooltip-content" ).html( content );
Daniel@0 15950 return;
Daniel@0 15951 }
Daniel@0 15952
Daniel@0 15953 // if we have a title, clear it to prevent the native tooltip
Daniel@0 15954 // we have to check first to avoid defining a title if none exists
Daniel@0 15955 // (we don't want to cause an element to start matching [title])
Daniel@0 15956 //
Daniel@0 15957 // We use removeAttr only for key events, to allow IE to export the correct
Daniel@0 15958 // accessible attributes. For mouse events, set to empty string to avoid
Daniel@0 15959 // native tooltip showing up (happens only when removing inside mouseover).
Daniel@0 15960 if ( target.is( "[title]" ) ) {
Daniel@0 15961 if ( event && event.type === "mouseover" ) {
Daniel@0 15962 target.attr( "title", "" );
Daniel@0 15963 } else {
Daniel@0 15964 target.removeAttr( "title" );
Daniel@0 15965 }
Daniel@0 15966 }
Daniel@0 15967
Daniel@0 15968 tooltip = this._tooltip( target );
Daniel@0 15969 this._addDescribedBy( target, tooltip.attr( "id" ) );
Daniel@0 15970 tooltip.find( ".ui-tooltip-content" ).html( content );
Daniel@0 15971
Daniel@0 15972 // Support: Voiceover on OS X, JAWS on IE <= 9
Daniel@0 15973 // JAWS announces deletions even when aria-relevant="additions"
Daniel@0 15974 // Voiceover will sometimes re-read the entire log region's contents from the beginning
Daniel@0 15975 this.liveRegion.children().hide();
Daniel@0 15976 if ( content.clone ) {
Daniel@0 15977 a11yContent = content.clone();
Daniel@0 15978 a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
Daniel@0 15979 } else {
Daniel@0 15980 a11yContent = content;
Daniel@0 15981 }
Daniel@0 15982 $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
Daniel@0 15983
Daniel@0 15984 function position( event ) {
Daniel@0 15985 positionOption.of = event;
Daniel@0 15986 if ( tooltip.is( ":hidden" ) ) {
Daniel@0 15987 return;
Daniel@0 15988 }
Daniel@0 15989 tooltip.position( positionOption );
Daniel@0 15990 }
Daniel@0 15991 if ( this.options.track && event && /^mouse/.test( event.type ) ) {
Daniel@0 15992 this._on( this.document, {
Daniel@0 15993 mousemove: position
Daniel@0 15994 });
Daniel@0 15995 // trigger once to override element-relative positioning
Daniel@0 15996 position( event );
Daniel@0 15997 } else {
Daniel@0 15998 tooltip.position( $.extend({
Daniel@0 15999 of: target
Daniel@0 16000 }, this.options.position ) );
Daniel@0 16001 }
Daniel@0 16002
Daniel@0 16003 tooltip.hide();
Daniel@0 16004
Daniel@0 16005 this._show( tooltip, this.options.show );
Daniel@0 16006 // Handle tracking tooltips that are shown with a delay (#8644). As soon
Daniel@0 16007 // as the tooltip is visible, position the tooltip using the most recent
Daniel@0 16008 // event.
Daniel@0 16009 if ( this.options.show && this.options.show.delay ) {
Daniel@0 16010 delayedShow = this.delayedShow = setInterval(function() {
Daniel@0 16011 if ( tooltip.is( ":visible" ) ) {
Daniel@0 16012 position( positionOption.of );
Daniel@0 16013 clearInterval( delayedShow );
Daniel@0 16014 }
Daniel@0 16015 }, $.fx.interval );
Daniel@0 16016 }
Daniel@0 16017
Daniel@0 16018 this._trigger( "open", event, { tooltip: tooltip } );
Daniel@0 16019
Daniel@0 16020 events = {
Daniel@0 16021 keyup: function( event ) {
Daniel@0 16022 if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
Daniel@0 16023 var fakeEvent = $.Event(event);
Daniel@0 16024 fakeEvent.currentTarget = target[0];
Daniel@0 16025 this.close( fakeEvent, true );
Daniel@0 16026 }
Daniel@0 16027 }
Daniel@0 16028 };
Daniel@0 16029
Daniel@0 16030 // Only bind remove handler for delegated targets. Non-delegated
Daniel@0 16031 // tooltips will handle this in destroy.
Daniel@0 16032 if ( target[ 0 ] !== this.element[ 0 ] ) {
Daniel@0 16033 events.remove = function() {
Daniel@0 16034 this._removeTooltip( tooltip );
Daniel@0 16035 };
Daniel@0 16036 }
Daniel@0 16037
Daniel@0 16038 if ( !event || event.type === "mouseover" ) {
Daniel@0 16039 events.mouseleave = "close";
Daniel@0 16040 }
Daniel@0 16041 if ( !event || event.type === "focusin" ) {
Daniel@0 16042 events.focusout = "close";
Daniel@0 16043 }
Daniel@0 16044 this._on( true, target, events );
Daniel@0 16045 },
Daniel@0 16046
Daniel@0 16047 close: function( event ) {
Daniel@0 16048 var that = this,
Daniel@0 16049 target = $( event ? event.currentTarget : this.element ),
Daniel@0 16050 tooltip = this._find( target );
Daniel@0 16051
Daniel@0 16052 // disabling closes the tooltip, so we need to track when we're closing
Daniel@0 16053 // to avoid an infinite loop in case the tooltip becomes disabled on close
Daniel@0 16054 if ( this.closing ) {
Daniel@0 16055 return;
Daniel@0 16056 }
Daniel@0 16057
Daniel@0 16058 // Clear the interval for delayed tracking tooltips
Daniel@0 16059 clearInterval( this.delayedShow );
Daniel@0 16060
Daniel@0 16061 // only set title if we had one before (see comment in _open())
Daniel@0 16062 // If the title attribute has changed since open(), don't restore
Daniel@0 16063 if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
Daniel@0 16064 target.attr( "title", target.data( "ui-tooltip-title" ) );
Daniel@0 16065 }
Daniel@0 16066
Daniel@0 16067 this._removeDescribedBy( target );
Daniel@0 16068
Daniel@0 16069 tooltip.stop( true );
Daniel@0 16070 this._hide( tooltip, this.options.hide, function() {
Daniel@0 16071 that._removeTooltip( $( this ) );
Daniel@0 16072 });
Daniel@0 16073
Daniel@0 16074 target.removeData( "ui-tooltip-open" );
Daniel@0 16075 this._off( target, "mouseleave focusout keyup" );
Daniel@0 16076
Daniel@0 16077 // Remove 'remove' binding only on delegated targets
Daniel@0 16078 if ( target[ 0 ] !== this.element[ 0 ] ) {
Daniel@0 16079 this._off( target, "remove" );
Daniel@0 16080 }
Daniel@0 16081 this._off( this.document, "mousemove" );
Daniel@0 16082
Daniel@0 16083 if ( event && event.type === "mouseleave" ) {
Daniel@0 16084 $.each( this.parents, function( id, parent ) {
Daniel@0 16085 $( parent.element ).attr( "title", parent.title );
Daniel@0 16086 delete that.parents[ id ];
Daniel@0 16087 });
Daniel@0 16088 }
Daniel@0 16089
Daniel@0 16090 this.closing = true;
Daniel@0 16091 this._trigger( "close", event, { tooltip: tooltip } );
Daniel@0 16092 this.closing = false;
Daniel@0 16093 },
Daniel@0 16094
Daniel@0 16095 _tooltip: function( element ) {
Daniel@0 16096 var tooltip = $( "<div>" )
Daniel@0 16097 .attr( "role", "tooltip" )
Daniel@0 16098 .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
Daniel@0 16099 ( this.options.tooltipClass || "" ) ),
Daniel@0 16100 id = tooltip.uniqueId().attr( "id" );
Daniel@0 16101
Daniel@0 16102 $( "<div>" )
Daniel@0 16103 .addClass( "ui-tooltip-content" )
Daniel@0 16104 .appendTo( tooltip );
Daniel@0 16105
Daniel@0 16106 tooltip.appendTo( this.document[0].body );
Daniel@0 16107 this.tooltips[ id ] = element;
Daniel@0 16108 return tooltip;
Daniel@0 16109 },
Daniel@0 16110
Daniel@0 16111 _find: function( target ) {
Daniel@0 16112 var id = target.data( "ui-tooltip-id" );
Daniel@0 16113 return id ? $( "#" + id ) : $();
Daniel@0 16114 },
Daniel@0 16115
Daniel@0 16116 _removeTooltip: function( tooltip ) {
Daniel@0 16117 tooltip.remove();
Daniel@0 16118 delete this.tooltips[ tooltip.attr( "id" ) ];
Daniel@0 16119 },
Daniel@0 16120
Daniel@0 16121 _destroy: function() {
Daniel@0 16122 var that = this;
Daniel@0 16123
Daniel@0 16124 // close open tooltips
Daniel@0 16125 $.each( this.tooltips, function( id, element ) {
Daniel@0 16126 // Delegate to close method to handle common cleanup
Daniel@0 16127 var event = $.Event( "blur" );
Daniel@0 16128 event.target = event.currentTarget = element[0];
Daniel@0 16129 that.close( event, true );
Daniel@0 16130
Daniel@0 16131 // Remove immediately; destroying an open tooltip doesn't use the
Daniel@0 16132 // hide animation
Daniel@0 16133 $( "#" + id ).remove();
Daniel@0 16134
Daniel@0 16135 // Restore the title
Daniel@0 16136 if ( element.data( "ui-tooltip-title" ) ) {
Daniel@0 16137 // If the title attribute has changed since open(), don't restore
Daniel@0 16138 if ( !element.attr( "title" ) ) {
Daniel@0 16139 element.attr( "title", element.data( "ui-tooltip-title" ) );
Daniel@0 16140 }
Daniel@0 16141 element.removeData( "ui-tooltip-title" );
Daniel@0 16142 }
Daniel@0 16143 });
Daniel@0 16144 this.liveRegion.remove();
Daniel@0 16145 }
Daniel@0 16146 });
Daniel@0 16147
Daniel@0 16148
Daniel@0 16149
Daniel@0 16150 }));