You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4704 lines
151 KiB

7 years ago
  1. /*! jQuery UI - v1.12.1 - 2017-07-23
  2. * http://jqueryui.com
  3. * Includes: widget.js, data.js, keycode.js, scroll-parent.js, widgets/sortable.js, widgets/datepicker.js, widgets/mouse.js
  4. * Copyright jQuery Foundation and other contributors; Licensed MIT */
  5. (function( factory ) {
  6. if ( typeof define === "function" && define.amd ) {
  7. // AMD. Register as an anonymous module.
  8. define([ "jquery" ], factory );
  9. } else {
  10. // Browser globals
  11. factory( jQuery );
  12. }
  13. }(function( $ ) {
  14. $.ui = $.ui || {};
  15. var version = $.ui.version = "1.12.1";
  16. /*!
  17. * jQuery UI Widget 1.12.1
  18. * http://jqueryui.com
  19. *
  20. * Copyright jQuery Foundation and other contributors
  21. * Released under the MIT license.
  22. * http://jquery.org/license
  23. */
  24. //>>label: Widget
  25. //>>group: Core
  26. //>>description: Provides a factory for creating stateful widgets with a common API.
  27. //>>docs: http://api.jqueryui.com/jQuery.widget/
  28. //>>demos: http://jqueryui.com/widget/
  29. var widgetUuid = 0;
  30. var widgetSlice = Array.prototype.slice;
  31. $.cleanData = ( function( orig ) {
  32. return function( elems ) {
  33. var events, elem, i;
  34. for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
  35. try {
  36. // Only trigger remove when necessary to save time
  37. events = $._data( elem, "events" );
  38. if ( events && events.remove ) {
  39. $( elem ).triggerHandler( "remove" );
  40. }
  41. // Http://bugs.jquery.com/ticket/8235
  42. } catch ( e ) {}
  43. }
  44. orig( elems );
  45. };
  46. } )( $.cleanData );
  47. $.widget = function( name, base, prototype ) {
  48. var existingConstructor, constructor, basePrototype;
  49. // ProxiedPrototype allows the provided prototype to remain unmodified
  50. // so that it can be used as a mixin for multiple widgets (#8876)
  51. var proxiedPrototype = {};
  52. var namespace = name.split( "." )[ 0 ];
  53. name = name.split( "." )[ 1 ];
  54. var fullName = namespace + "-" + name;
  55. if ( !prototype ) {
  56. prototype = base;
  57. base = $.Widget;
  58. }
  59. if ( $.isArray( prototype ) ) {
  60. prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
  61. }
  62. // Create selector for plugin
  63. $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
  64. return !!$.data( elem, fullName );
  65. };
  66. $[ namespace ] = $[ namespace ] || {};
  67. existingConstructor = $[ namespace ][ name ];
  68. constructor = $[ namespace ][ name ] = function( options, element ) {
  69. // Allow instantiation without "new" keyword
  70. if ( !this._createWidget ) {
  71. return new constructor( options, element );
  72. }
  73. // Allow instantiation without initializing for simple inheritance
  74. // must use "new" keyword (the code above always passes args)
  75. if ( arguments.length ) {
  76. this._createWidget( options, element );
  77. }
  78. };
  79. // Extend with the existing constructor to carry over any static properties
  80. $.extend( constructor, existingConstructor, {
  81. version: prototype.version,
  82. // Copy the object used to create the prototype in case we need to
  83. // redefine the widget later
  84. _proto: $.extend( {}, prototype ),
  85. // Track widgets that inherit from this widget in case this widget is
  86. // redefined after a widget inherits from it
  87. _childConstructors: []
  88. } );
  89. basePrototype = new base();
  90. // We need to make the options hash a property directly on the new instance
  91. // otherwise we'll modify the options hash on the prototype that we're
  92. // inheriting from
  93. basePrototype.options = $.widget.extend( {}, basePrototype.options );
  94. $.each( prototype, function( prop, value ) {
  95. if ( !$.isFunction( value ) ) {
  96. proxiedPrototype[ prop ] = value;
  97. return;
  98. }
  99. proxiedPrototype[ prop ] = ( function() {
  100. function _super() {
  101. return base.prototype[ prop ].apply( this, arguments );
  102. }
  103. function _superApply( args ) {
  104. return base.prototype[ prop ].apply( this, args );
  105. }
  106. return function() {
  107. var __super = this._super;
  108. var __superApply = this._superApply;
  109. var returnValue;
  110. this._super = _super;
  111. this._superApply = _superApply;
  112. returnValue = value.apply( this, arguments );
  113. this._super = __super;
  114. this._superApply = __superApply;
  115. return returnValue;
  116. };
  117. } )();
  118. } );
  119. constructor.prototype = $.widget.extend( basePrototype, {
  120. // TODO: remove support for widgetEventPrefix
  121. // always use the name + a colon as the prefix, e.g., draggable:start
  122. // don't prefix for widgets that aren't DOM-based
  123. widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
  124. }, proxiedPrototype, {
  125. constructor: constructor,
  126. namespace: namespace,
  127. widgetName: name,
  128. widgetFullName: fullName
  129. } );
  130. // If this widget is being redefined then we need to find all widgets that
  131. // are inheriting from it and redefine all of them so that they inherit from
  132. // the new version of this widget. We're essentially trying to replace one
  133. // level in the prototype chain.
  134. if ( existingConstructor ) {
  135. $.each( existingConstructor._childConstructors, function( i, child ) {
  136. var childPrototype = child.prototype;
  137. // Redefine the child widget using the same prototype that was
  138. // originally used, but inherit from the new version of the base
  139. $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
  140. child._proto );
  141. } );
  142. // Remove the list of existing child constructors from the old constructor
  143. // so the old child constructors can be garbage collected
  144. delete existingConstructor._childConstructors;
  145. } else {
  146. base._childConstructors.push( constructor );
  147. }
  148. $.widget.bridge( name, constructor );
  149. return constructor;
  150. };
  151. $.widget.extend = function( target ) {
  152. var input = widgetSlice.call( arguments, 1 );
  153. var inputIndex = 0;
  154. var inputLength = input.length;
  155. var key;
  156. var value;
  157. for ( ; inputIndex < inputLength; inputIndex++ ) {
  158. for ( key in input[ inputIndex ] ) {
  159. value = input[ inputIndex ][ key ];
  160. if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
  161. // Clone objects
  162. if ( $.isPlainObject( value ) ) {
  163. target[ key ] = $.isPlainObject( target[ key ] ) ?
  164. $.widget.extend( {}, target[ key ], value ) :
  165. // Don't extend strings, arrays, etc. with objects
  166. $.widget.extend( {}, value );
  167. // Copy everything else by reference
  168. } else {
  169. target[ key ] = value;
  170. }
  171. }
  172. }
  173. }
  174. return target;
  175. };
  176. $.widget.bridge = function( name, object ) {
  177. var fullName = object.prototype.widgetFullName || name;
  178. $.fn[ name ] = function( options ) {
  179. var isMethodCall = typeof options === "string";
  180. var args = widgetSlice.call( arguments, 1 );
  181. var returnValue = this;
  182. if ( isMethodCall ) {
  183. // If this is an empty collection, we need to have the instance method
  184. // return undefined instead of the jQuery instance
  185. if ( !this.length && options === "instance" ) {
  186. returnValue = undefined;
  187. } else {
  188. this.each( function() {
  189. var methodValue;
  190. var instance = $.data( this, fullName );
  191. if ( options === "instance" ) {
  192. returnValue = instance;
  193. return false;
  194. }
  195. if ( !instance ) {
  196. return $.error( "cannot call methods on " + name +
  197. " prior to initialization; " +
  198. "attempted to call method '" + options + "'" );
  199. }
  200. if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
  201. return $.error( "no such method '" + options + "' for " + name +
  202. " widget instance" );
  203. }
  204. methodValue = instance[ options ].apply( instance, args );
  205. if ( methodValue !== instance && methodValue !== undefined ) {
  206. returnValue = methodValue && methodValue.jquery ?
  207. returnValue.pushStack( methodValue.get() ) :
  208. methodValue;
  209. return false;
  210. }
  211. } );
  212. }
  213. } else {
  214. // Allow multiple hashes to be passed on init
  215. if ( args.length ) {
  216. options = $.widget.extend.apply( null, [ options ].concat( args ) );
  217. }
  218. this.each( function() {
  219. var instance = $.data( this, fullName );
  220. if ( instance ) {
  221. instance.option( options || {} );
  222. if ( instance._init ) {
  223. instance._init();
  224. }
  225. } else {
  226. $.data( this, fullName, new object( options, this ) );
  227. }
  228. } );
  229. }
  230. return returnValue;
  231. };
  232. };
  233. $.Widget = function( /* options, element */ ) {};
  234. $.Widget._childConstructors = [];
  235. $.Widget.prototype = {
  236. widgetName: "widget",
  237. widgetEventPrefix: "",
  238. defaultElement: "<div>",
  239. options: {
  240. classes: {},
  241. disabled: false,
  242. // Callbacks
  243. create: null
  244. },
  245. _createWidget: function( options, element ) {
  246. element = $( element || this.defaultElement || this )[ 0 ];
  247. this.element = $( element );
  248. this.uuid = widgetUuid++;
  249. this.eventNamespace = "." + this.widgetName + this.uuid;
  250. this.bindings = $();
  251. this.hoverable = $();
  252. this.focusable = $();
  253. this.classesElementLookup = {};
  254. if ( element !== this ) {
  255. $.data( element, this.widgetFullName, this );
  256. this._on( true, this.element, {
  257. remove: function( event ) {
  258. if ( event.target === element ) {
  259. this.destroy();
  260. }
  261. }
  262. } );
  263. this.document = $( element.style ?
  264. // Element within the document
  265. element.ownerDocument :
  266. // Element is window or document
  267. element.document || element );
  268. this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
  269. }
  270. this.options = $.widget.extend( {},
  271. this.options,
  272. this._getCreateOptions(),
  273. options );
  274. this._create();
  275. if ( this.options.disabled ) {
  276. this._setOptionDisabled( this.options.disabled );
  277. }
  278. this._trigger( "create", null, this._getCreateEventData() );
  279. this._init();
  280. },
  281. _getCreateOptions: function() {
  282. return {};
  283. },
  284. _getCreateEventData: $.noop,
  285. _create: $.noop,
  286. _init: $.noop,
  287. destroy: function() {
  288. var that = this;
  289. this._destroy();
  290. $.each( this.classesElementLookup, function( key, value ) {
  291. that._removeClass( value, key );
  292. } );
  293. // We can probably remove the unbind calls in 2.0
  294. // all event bindings should go through this._on()
  295. this.element
  296. .off( this.eventNamespace )
  297. .removeData( this.widgetFullName );
  298. this.widget()
  299. .off( this.eventNamespace )
  300. .removeAttr( "aria-disabled" );
  301. // Clean up events and states
  302. this.bindings.off( this.eventNamespace );
  303. },
  304. _destroy: $.noop,
  305. widget: function() {
  306. return this.element;
  307. },
  308. option: function( key, value ) {
  309. var options = key;
  310. var parts;
  311. var curOption;
  312. var i;
  313. if ( arguments.length === 0 ) {
  314. // Don't return a reference to the internal hash
  315. return $.widget.extend( {}, this.options );
  316. }
  317. if ( typeof key === "string" ) {
  318. // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
  319. options = {};
  320. parts = key.split( "." );
  321. key = parts.shift();
  322. if ( parts.length ) {
  323. curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
  324. for ( i = 0; i < parts.length - 1; i++ ) {
  325. curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
  326. curOption = curOption[ parts[ i ] ];
  327. }
  328. key = parts.pop();
  329. if ( arguments.length === 1 ) {
  330. return curOption[ key ] === undefined ? null : curOption[ key ];
  331. }
  332. curOption[ key ] = value;
  333. } else {
  334. if ( arguments.length === 1 ) {
  335. return this.options[ key ] === undefined ? null : this.options[ key ];
  336. }
  337. options[ key ] = value;
  338. }
  339. }
  340. this._setOptions( options );
  341. return this;
  342. },
  343. _setOptions: function( options ) {
  344. var key;
  345. for ( key in options ) {
  346. this._setOption( key, options[ key ] );
  347. }
  348. return this;
  349. },
  350. _setOption: function( key, value ) {
  351. if ( key === "classes" ) {
  352. this._setOptionClasses( value );
  353. }
  354. this.options[ key ] = value;
  355. if ( key === "disabled" ) {
  356. this._setOptionDisabled( value );
  357. }
  358. return this;
  359. },
  360. _setOptionClasses: function( value ) {
  361. var classKey, elements, currentElements;
  362. for ( classKey in value ) {
  363. currentElements = this.classesElementLookup[ classKey ];
  364. if ( value[ classKey ] === this.options.classes[ classKey ] ||
  365. !currentElements ||
  366. !currentElements.length ) {
  367. continue;
  368. }
  369. // We are doing this to create a new jQuery object because the _removeClass() call
  370. // on the next line is going to destroy the reference to the current elements being
  371. // tracked. We need to save a copy of this collection so that we can add the new classes
  372. // below.
  373. elements = $( currentElements.get() );
  374. this._removeClass( currentElements, classKey );
  375. // We don't use _addClass() here, because that uses this.options.classes
  376. // for generating the string of classes. We want to use the value passed in from
  377. // _setOption(), this is the new value of the classes option which was passed to
  378. // _setOption(). We pass this value directly to _classes().
  379. elements.addClass( this._classes( {
  380. element: elements,
  381. keys: classKey,
  382. classes: value,
  383. add: true
  384. } ) );
  385. }
  386. },
  387. _setOptionDisabled: function( value ) {
  388. this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
  389. // If the widget is becoming disabled, then nothing is interactive
  390. if ( value ) {
  391. this._removeClass( this.hoverable, null, "ui-state-hover" );
  392. this._removeClass( this.focusable, null, "ui-state-focus" );
  393. }
  394. },
  395. enable: function() {
  396. return this._setOptions( { disabled: false } );
  397. },
  398. disable: function() {
  399. return this._setOptions( { disabled: true } );
  400. },
  401. _classes: function( options ) {
  402. var full = [];
  403. var that = this;
  404. options = $.extend( {
  405. element: this.element,
  406. classes: this.options.classes || {}
  407. }, options );
  408. function processClassString( classes, checkOption ) {
  409. var current, i;
  410. for ( i = 0; i < classes.length; i++ ) {
  411. current = that.classesElementLookup[ classes[ i ] ] || $();
  412. if ( options.add ) {
  413. current = $( $.unique( current.get().concat( options.element.get() ) ) );
  414. } else {
  415. current = $( current.not( options.element ).get() );
  416. }
  417. that.classesElementLookup[ classes[ i ] ] = current;
  418. full.push( classes[ i ] );
  419. if ( checkOption && options.classes[ classes[ i ] ] ) {
  420. full.push( options.classes[ classes[ i ] ] );
  421. }
  422. }
  423. }
  424. this._on( options.element, {
  425. "remove": "_untrackClassesElement"
  426. } );
  427. if ( options.keys ) {
  428. processClassString( options.keys.match( /\S+/g ) || [], true );
  429. }
  430. if ( options.extra ) {
  431. processClassString( options.extra.match( /\S+/g ) || [] );
  432. }
  433. return full.join( " " );
  434. },
  435. _untrackClassesElement: function( event ) {
  436. var that = this;
  437. $.each( that.classesElementLookup, function( key, value ) {
  438. if ( $.inArray( event.target, value ) !== -1 ) {
  439. that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
  440. }
  441. } );
  442. },
  443. _removeClass: function( element, keys, extra ) {
  444. return this._toggleClass( element, keys, extra, false );
  445. },
  446. _addClass: function( element, keys, extra ) {
  447. return this._toggleClass( element, keys, extra, true );
  448. },
  449. _toggleClass: function( element, keys, extra, add ) {
  450. add = ( typeof add === "boolean" ) ? add : extra;
  451. var shift = ( typeof element === "string" || element === null ),
  452. options = {
  453. extra: shift ? keys : extra,
  454. keys: shift ? element : keys,
  455. element: shift ? this.element : element,
  456. add: add
  457. };
  458. options.element.toggleClass( this._classes( options ), add );
  459. return this;
  460. },
  461. _on: function( suppressDisabledCheck, element, handlers ) {
  462. var delegateElement;
  463. var instance = this;
  464. // No suppressDisabledCheck flag, shuffle arguments
  465. if ( typeof suppressDisabledCheck !== "boolean" ) {
  466. handlers = element;
  467. element = suppressDisabledCheck;
  468. suppressDisabledCheck = false;
  469. }
  470. // No element argument, shuffle and use this.element
  471. if ( !handlers ) {
  472. handlers = element;
  473. element = this.element;
  474. delegateElement = this.widget();
  475. } else {
  476. element = delegateElement = $( element );
  477. this.bindings = this.bindings.add( element );
  478. }
  479. $.each( handlers, function( event, handler ) {
  480. function handlerProxy() {
  481. // Allow widgets to customize the disabled handling
  482. // - disabled as an array instead of boolean
  483. // - disabled class as method for disabling individual parts
  484. if ( !suppressDisabledCheck &&
  485. ( instance.options.disabled === true ||
  486. $( this ).hasClass( "ui-state-disabled" ) ) ) {
  487. return;
  488. }
  489. return ( typeof handler === "string" ? instance[ handler ] : handler )
  490. .apply( instance, arguments );
  491. }
  492. // Copy the guid so direct unbinding works
  493. if ( typeof handler !== "string" ) {
  494. handlerProxy.guid = handler.guid =
  495. handler.guid || handlerProxy.guid || $.guid++;
  496. }
  497. var match = event.match( /^([\w:-]*)\s*(.*)$/ );
  498. var eventName = match[ 1 ] + instance.eventNamespace;
  499. var selector = match[ 2 ];
  500. if ( selector ) {
  501. delegateElement.on( eventName, selector, handlerProxy );
  502. } else {
  503. element.on( eventName, handlerProxy );
  504. }
  505. } );
  506. },
  507. _off: function( element, eventName ) {
  508. eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
  509. this.eventNamespace;
  510. element.off( eventName ).off( eventName );
  511. // Clear the stack to avoid memory leaks (#10056)
  512. this.bindings = $( this.bindings.not( element ).get() );
  513. this.focusable = $( this.focusable.not( element ).get() );
  514. this.hoverable = $( this.hoverable.not( element ).get() );
  515. },
  516. _delay: function( handler, delay ) {
  517. function handlerProxy() {
  518. return ( typeof handler === "string" ? instance[ handler ] : handler )
  519. .apply( instance, arguments );
  520. }
  521. var instance = this;
  522. return setTimeout( handlerProxy, delay || 0 );
  523. },
  524. _hoverable: function( element ) {
  525. this.hoverable = this.hoverable.add( element );
  526. this._on( element, {
  527. mouseenter: function( event ) {
  528. this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
  529. },
  530. mouseleave: function( event ) {
  531. this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
  532. }
  533. } );
  534. },
  535. _focusable: function( element ) {
  536. this.focusable = this.focusable.add( element );
  537. this._on( element, {
  538. focusin: function( event ) {
  539. this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
  540. },
  541. focusout: function( event ) {
  542. this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
  543. }
  544. } );
  545. },
  546. _trigger: function( type, event, data ) {
  547. var prop, orig;
  548. var callback = this.options[ type ];
  549. data = data || {};
  550. event = $.Event( event );
  551. event.type = ( type === this.widgetEventPrefix ?
  552. type :
  553. this.widgetEventPrefix + type ).toLowerCase();
  554. // The original event may come from any element
  555. // so we need to reset the target on the new event
  556. event.target = this.element[ 0 ];
  557. // Copy original event properties over to the new event
  558. orig = event.originalEvent;
  559. if ( orig ) {
  560. for ( prop in orig ) {
  561. if ( !( prop in event ) ) {
  562. event[ prop ] = orig[ prop ];
  563. }
  564. }
  565. }
  566. this.element.trigger( event, data );
  567. return !( $.isFunction( callback ) &&
  568. callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
  569. event.isDefaultPrevented() );
  570. }
  571. };
  572. $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
  573. $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
  574. if ( typeof options === "string" ) {
  575. options = { effect: options };
  576. }
  577. var hasOptions;
  578. var effectName = !options ?
  579. method :
  580. options === true || typeof options === "number" ?
  581. defaultEffect :
  582. options.effect || defaultEffect;
  583. options = options || {};
  584. if ( typeof options === "number" ) {
  585. options = { duration: options };
  586. }
  587. hasOptions = !$.isEmptyObject( options );
  588. options.complete = callback;
  589. if ( options.delay ) {
  590. element.delay( options.delay );
  591. }
  592. if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
  593. element[ method ]( options );
  594. } else if ( effectName !== method && element[ effectName ] ) {
  595. element[ effectName ]( options.duration, options.easing, callback );
  596. } else {
  597. element.queue( function( next ) {
  598. $( this )[ method ]();
  599. if ( callback ) {
  600. callback.call( element[ 0 ] );
  601. }
  602. next();
  603. } );
  604. }
  605. };
  606. } );
  607. var widget = $.widget;
  608. /*!
  609. * jQuery UI :data 1.12.1
  610. * http://jqueryui.com
  611. *
  612. * Copyright jQuery Foundation and other contributors
  613. * Released under the MIT license.
  614. * http://jquery.org/license
  615. */
  616. //>>label: :data Selector
  617. //>>group: Core
  618. //>>description: Selects elements which have data stored under the specified key.
  619. //>>docs: http://api.jqueryui.com/data-selector/
  620. var data = $.extend( $.expr[ ":" ], {
  621. data: $.expr.createPseudo ?
  622. $.expr.createPseudo( function( dataName ) {
  623. return function( elem ) {
  624. return !!$.data( elem, dataName );
  625. };
  626. } ) :
  627. // Support: jQuery <1.8
  628. function( elem, i, match ) {
  629. return !!$.data( elem, match[ 3 ] );
  630. }
  631. } );
  632. /*!
  633. * jQuery UI Keycode 1.12.1
  634. * http://jqueryui.com
  635. *
  636. * Copyright jQuery Foundation and other contributors
  637. * Released under the MIT license.
  638. * http://jquery.org/license
  639. */
  640. //>>label: Keycode
  641. //>>group: Core
  642. //>>description: Provide keycodes as keynames
  643. //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
  644. var keycode = $.ui.keyCode = {
  645. BACKSPACE: 8,
  646. COMMA: 188,
  647. DELETE: 46,
  648. DOWN: 40,
  649. END: 35,
  650. ENTER: 13,
  651. ESCAPE: 27,
  652. HOME: 36,
  653. LEFT: 37,
  654. PAGE_DOWN: 34,
  655. PAGE_UP: 33,
  656. PERIOD: 190,
  657. RIGHT: 39,
  658. SPACE: 32,
  659. TAB: 9,
  660. UP: 38
  661. };
  662. /*!
  663. * jQuery UI Scroll Parent 1.12.1
  664. * http://jqueryui.com
  665. *
  666. * Copyright jQuery Foundation and other contributors
  667. * Released under the MIT license.
  668. * http://jquery.org/license
  669. */
  670. //>>label: scrollParent
  671. //>>group: Core
  672. //>>description: Get the closest ancestor element that is scrollable.
  673. //>>docs: http://api.jqueryui.com/scrollParent/
  674. var scrollParent = $.fn.scrollParent = function( includeHidden ) {
  675. var position = this.css( "position" ),
  676. excludeStaticParent = position === "absolute",
  677. overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
  678. scrollParent = this.parents().filter( function() {
  679. var parent = $( this );
  680. if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
  681. return false;
  682. }
  683. return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
  684. parent.css( "overflow-x" ) );
  685. } ).eq( 0 );
  686. return position === "fixed" || !scrollParent.length ?
  687. $( this[ 0 ].ownerDocument || document ) :
  688. scrollParent;
  689. };
  690. // This file is deprecated
  691. var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
  692. /*!
  693. * jQuery UI Mouse 1.12.1
  694. * http://jqueryui.com
  695. *
  696. * Copyright jQuery Foundation and other contributors
  697. * Released under the MIT license.
  698. * http://jquery.org/license
  699. */
  700. //>>label: Mouse
  701. //>>group: Widgets
  702. //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
  703. //>>docs: http://api.jqueryui.com/mouse/
  704. var mouseHandled = false;
  705. $( document ).on( "mouseup", function() {
  706. mouseHandled = false;
  707. } );
  708. var widgetsMouse = $.widget( "ui.mouse", {
  709. version: "1.12.1",
  710. options: {
  711. cancel: "input, textarea, button, select, option",
  712. distance: 1,
  713. delay: 0
  714. },
  715. _mouseInit: function() {
  716. var that = this;
  717. this.element
  718. .on( "mousedown." + this.widgetName, function( event ) {
  719. return that._mouseDown( event );
  720. } )
  721. .on( "click." + this.widgetName, function( event ) {
  722. if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
  723. $.removeData( event.target, that.widgetName + ".preventClickEvent" );
  724. event.stopImmediatePropagation();
  725. return false;
  726. }
  727. } );
  728. this.started = false;
  729. },
  730. // TODO: make sure destroying one instance of mouse doesn't mess with
  731. // other instances of mouse
  732. _mouseDestroy: function() {
  733. this.element.off( "." + this.widgetName );
  734. if ( this._mouseMoveDelegate ) {
  735. this.document
  736. .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  737. .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
  738. }
  739. },
  740. _mouseDown: function( event ) {
  741. // don't let more than one widget handle mouseStart
  742. if ( mouseHandled ) {
  743. return;
  744. }
  745. this._mouseMoved = false;
  746. // We may have missed mouseup (out of window)
  747. ( this._mouseStarted && this._mouseUp( event ) );
  748. this._mouseDownEvent = event;
  749. var that = this,
  750. btnIsLeft = ( event.which === 1 ),
  751. // event.target.nodeName works around a bug in IE 8 with
  752. // disabled inputs (#7620)
  753. elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
  754. $( event.target ).closest( this.options.cancel ).length : false );
  755. if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
  756. return true;
  757. }
  758. this.mouseDelayMet = !this.options.delay;
  759. if ( !this.mouseDelayMet ) {
  760. this._mouseDelayTimer = setTimeout( function() {
  761. that.mouseDelayMet = true;
  762. }, this.options.delay );
  763. }
  764. if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
  765. this._mouseStarted = ( this._mouseStart( event ) !== false );
  766. if ( !this._mouseStarted ) {
  767. event.preventDefault();
  768. return true;
  769. }
  770. }
  771. // Click event may never have fired (Gecko & Opera)
  772. if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
  773. $.removeData( event.target, this.widgetName + ".preventClickEvent" );
  774. }
  775. // These delegates are required to keep context
  776. this._mouseMoveDelegate = function( event ) {
  777. return that._mouseMove( event );
  778. };
  779. this._mouseUpDelegate = function( event ) {
  780. return that._mouseUp( event );
  781. };
  782. this.document
  783. .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  784. .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
  785. event.preventDefault();
  786. mouseHandled = true;
  787. return true;
  788. },
  789. _mouseMove: function( event ) {
  790. // Only check for mouseups outside the document if you've moved inside the document
  791. // at least once. This prevents the firing of mouseup in the case of IE<9, which will
  792. // fire a mousemove event if content is placed under the cursor. See #7778
  793. // Support: IE <9
  794. if ( this._mouseMoved ) {
  795. // IE mouseup check - mouseup happened when mouse was out of window
  796. if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
  797. !event.button ) {
  798. return this._mouseUp( event );
  799. // Iframe mouseup check - mouseup occurred in another document
  800. } else if ( !event.which ) {
  801. // Support: Safari <=8 - 9
  802. // Safari sets which to 0 if you press any of the following keys
  803. // during a drag (#14461)
  804. if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
  805. event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
  806. this.ignoreMissingWhich = true;
  807. } else if ( !this.ignoreMissingWhich ) {
  808. return this._mouseUp( event );
  809. }
  810. }
  811. }
  812. if ( event.which || event.button ) {
  813. this._mouseMoved = true;
  814. }
  815. if ( this._mouseStarted ) {
  816. this._mouseDrag( event );
  817. return event.preventDefault();
  818. }
  819. if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
  820. this._mouseStarted =
  821. ( this._mouseStart( this._mouseDownEvent, event ) !== false );
  822. ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
  823. }
  824. return !this._mouseStarted;
  825. },
  826. _mouseUp: function( event ) {
  827. this.document
  828. .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  829. .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
  830. if ( this._mouseStarted ) {
  831. this._mouseStarted = false;
  832. if ( event.target === this._mouseDownEvent.target ) {
  833. $.data( event.target, this.widgetName + ".preventClickEvent", true );
  834. }
  835. this._mouseStop( event );
  836. }
  837. if ( this._mouseDelayTimer ) {
  838. clearTimeout( this._mouseDelayTimer );
  839. delete this._mouseDelayTimer;
  840. }
  841. this.ignoreMissingWhich = false;
  842. mouseHandled = false;
  843. event.preventDefault();
  844. },
  845. _mouseDistanceMet: function( event ) {
  846. return ( Math.max(
  847. Math.abs( this._mouseDownEvent.pageX - event.pageX ),
  848. Math.abs( this._mouseDownEvent.pageY - event.pageY )
  849. ) >= this.options.distance
  850. );
  851. },
  852. _mouseDelayMet: function( /* event */ ) {
  853. return this.mouseDelayMet;
  854. },
  855. // These are placeholder methods, to be overriden by extending plugin
  856. _mouseStart: function( /* event */ ) {},
  857. _mouseDrag: function( /* event */ ) {},
  858. _mouseStop: function( /* event */ ) {},
  859. _mouseCapture: function( /* event */ ) { return true; }
  860. } );
  861. /*!
  862. * jQuery UI Sortable 1.12.1
  863. * http://jqueryui.com
  864. *
  865. * Copyright jQuery Foundation and other contributors
  866. * Released under the MIT license.
  867. * http://jquery.org/license
  868. */
  869. //>>label: Sortable
  870. //>>group: Interactions
  871. //>>description: Enables items in a list to be sorted using the mouse.
  872. //>>docs: http://api.jqueryui.com/sortable/
  873. //>>demos: http://jqueryui.com/sortable/
  874. //>>css.structure: ../../themes/base/sortable.css
  875. var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
  876. version: "1.12.1",
  877. widgetEventPrefix: "sort",
  878. ready: false,
  879. options: {
  880. appendTo: "parent",
  881. axis: false,
  882. connectWith: false,
  883. containment: false,
  884. cursor: "auto",
  885. cursorAt: false,
  886. dropOnEmpty: true,
  887. forcePlaceholderSize: false,
  888. forceHelperSize: false,
  889. grid: false,
  890. handle: false,
  891. helper: "original",
  892. items: "> *",
  893. opacity: false,
  894. placeholder: false,
  895. revert: false,
  896. scroll: true,
  897. scrollSensitivity: 20,
  898. scrollSpeed: 20,
  899. scope: "default",
  900. tolerance: "intersect",
  901. zIndex: 1000,
  902. // Callbacks
  903. activate: null,
  904. beforeStop: null,
  905. change: null,
  906. deactivate: null,
  907. out: null,
  908. over: null,
  909. receive: null,
  910. remove: null,
  911. sort: null,
  912. start: null,
  913. stop: null,
  914. update: null
  915. },
  916. _isOverAxis: function( x, reference, size ) {
  917. return ( x >= reference ) && ( x < ( reference + size ) );
  918. },
  919. _isFloating: function( item ) {
  920. return ( /left|right/ ).test( item.css( "float" ) ) ||
  921. ( /inline|table-cell/ ).test( item.css( "display" ) );
  922. },
  923. _create: function() {
  924. this.containerCache = {};
  925. this._addClass( "ui-sortable" );
  926. //Get the items
  927. this.refresh();
  928. //Let's determine the parent's offset
  929. this.offset = this.element.offset();
  930. //Initialize mouse events for interaction
  931. this._mouseInit();
  932. this._setHandleClassName();
  933. //We're ready to go
  934. this.ready = true;
  935. },
  936. _setOption: function( key, value ) {
  937. this._super( key, value );
  938. if ( key === "handle" ) {
  939. this._setHandleClassName();
  940. }
  941. },
  942. _setHandleClassName: function() {
  943. var that = this;
  944. this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
  945. $.each( this.items, function() {
  946. that._addClass(
  947. this.instance.options.handle ?
  948. this.item.find( this.instance.options.handle ) :
  949. this.item,
  950. "ui-sortable-handle"
  951. );
  952. } );
  953. },
  954. _destroy: function() {
  955. this._mouseDestroy();
  956. for ( var i = this.items.length - 1; i >= 0; i-- ) {
  957. this.items[ i ].item.removeData( this.widgetName + "-item" );
  958. }
  959. return this;
  960. },
  961. _mouseCapture: function( event, overrideHandle ) {
  962. var currentItem = null,
  963. validHandle = false,
  964. that = this;
  965. if ( this.reverting ) {
  966. return false;
  967. }
  968. if ( this.options.disabled || this.options.type === "static" ) {
  969. return false;
  970. }
  971. //We have to refresh the items data once first
  972. this._refreshItems( event );
  973. //Find out if the clicked node (or one of its parents) is a actual item in this.items
  974. $( event.target ).parents().each( function() {
  975. if ( $.data( this, that.widgetName + "-item" ) === that ) {
  976. currentItem = $( this );
  977. return false;
  978. }
  979. } );
  980. if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
  981. currentItem = $( event.target );
  982. }
  983. if ( !currentItem ) {
  984. return false;
  985. }
  986. if ( this.options.handle && !overrideHandle ) {
  987. $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
  988. if ( this === event.target ) {
  989. validHandle = true;
  990. }
  991. } );
  992. if ( !validHandle ) {
  993. return false;
  994. }
  995. }
  996. this.currentItem = currentItem;
  997. this._removeCurrentsFromItems();
  998. return true;
  999. },
  1000. _mouseStart: function( event, overrideHandle, noActivation ) {
  1001. var i, body,
  1002. o = this.options;
  1003. this.currentContainer = this;
  1004. //We only need to call refreshPositions, because the refreshItems call has been moved to
  1005. // mouseCapture
  1006. this.refreshPositions();
  1007. //Create and append the visible helper
  1008. this.helper = this._createHelper( event );
  1009. //Cache the helper size
  1010. this._cacheHelperProportions();
  1011. /*
  1012. * - Position generation -
  1013. * This block generates everything position related - it's the core of draggables.
  1014. */
  1015. //Cache the margins of the original element
  1016. this._cacheMargins();
  1017. //Get the next scrolling parent
  1018. this.scrollParent = this.helper.scrollParent();
  1019. //The element's absolute position on the page minus margins
  1020. this.offset = this.currentItem.offset();
  1021. this.offset = {
  1022. top: this.offset.top - this.margins.top,
  1023. left: this.offset.left - this.margins.left
  1024. };
  1025. $.extend( this.offset, {
  1026. click: { //Where the click happened, relative to the element
  1027. left: event.pageX - this.offset.left,
  1028. top: event.pageY - this.offset.top
  1029. },
  1030. parent: this._getParentOffset(),
  1031. // This is a relative to absolute position minus the actual position calculation -
  1032. // only used for relative positioned helper
  1033. relative: this._getRelativeOffset()
  1034. } );
  1035. // Only after we got the offset, we can change the helper's position to absolute
  1036. // TODO: Still need to figure out a way to make relative sorting possible
  1037. this.helper.css( "position", "absolute" );
  1038. this.cssPosition = this.helper.css( "position" );
  1039. //Generate the original position
  1040. this.originalPosition = this._generatePosition( event );
  1041. this.originalPageX = event.pageX;
  1042. this.originalPageY = event.pageY;
  1043. //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
  1044. ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
  1045. //Cache the former DOM position
  1046. this.domPosition = {
  1047. prev: this.currentItem.prev()[ 0 ],
  1048. parent: this.currentItem.parent()[ 0 ]
  1049. };
  1050. // If the helper is not the original, hide the original so it's not playing any role during
  1051. // the drag, won't cause anything bad this way
  1052. if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
  1053. this.currentItem.hide();
  1054. }
  1055. //Create the placeholder
  1056. this._createPlaceholder();
  1057. //Set a containment if given in the options
  1058. if ( o.containment ) {
  1059. this._setContainment();
  1060. }
  1061. if ( o.cursor && o.cursor !== "auto" ) { // cursor option
  1062. body = this.document.find( "body" );
  1063. // Support: IE
  1064. this.storedCursor = body.css( "cursor" );
  1065. body.css( "cursor", o.cursor );
  1066. this.storedStylesheet =
  1067. $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
  1068. }
  1069. if ( o.opacity ) { // opacity option
  1070. if ( this.helper.css( "opacity" ) ) {
  1071. this._storedOpacity = this.helper.css( "opacity" );
  1072. }
  1073. this.helper.css( "opacity", o.opacity );
  1074. }
  1075. if ( o.zIndex ) { // zIndex option
  1076. if ( this.helper.css( "zIndex" ) ) {
  1077. this._storedZIndex = this.helper.css( "zIndex" );
  1078. }
  1079. this.helper.css( "zIndex", o.zIndex );
  1080. }
  1081. //Prepare scrolling
  1082. if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1083. this.scrollParent[ 0 ].tagName !== "HTML" ) {
  1084. this.overflowOffset = this.scrollParent.offset();
  1085. }
  1086. //Call callbacks
  1087. this._trigger( "start", event, this._uiHash() );
  1088. //Recache the helper size
  1089. if ( !this._preserveHelperProportions ) {
  1090. this._cacheHelperProportions();
  1091. }
  1092. //Post "activate" events to possible containers
  1093. if ( !noActivation ) {
  1094. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  1095. this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
  1096. }
  1097. }
  1098. //Prepare possible droppables
  1099. if ( $.ui.ddmanager ) {
  1100. $.ui.ddmanager.current = this;
  1101. }
  1102. if ( $.ui.ddmanager && !o.dropBehaviour ) {
  1103. $.ui.ddmanager.prepareOffsets( this, event );
  1104. }
  1105. this.dragging = true;
  1106. this._addClass( this.helper, "ui-sortable-helper" );
  1107. // Execute the drag once - this causes the helper not to be visiblebefore getting its
  1108. // correct position
  1109. this._mouseDrag( event );
  1110. return true;
  1111. },
  1112. _mouseDrag: function( event ) {
  1113. var i, item, itemElement, intersection,
  1114. o = this.options,
  1115. scrolled = false;
  1116. //Compute the helpers position
  1117. this.position = this._generatePosition( event );
  1118. this.positionAbs = this._convertPositionTo( "absolute" );
  1119. if ( !this.lastPositionAbs ) {
  1120. this.lastPositionAbs = this.positionAbs;
  1121. }
  1122. //Do scrolling
  1123. if ( this.options.scroll ) {
  1124. if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1125. this.scrollParent[ 0 ].tagName !== "HTML" ) {
  1126. if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
  1127. event.pageY < o.scrollSensitivity ) {
  1128. this.scrollParent[ 0 ].scrollTop =
  1129. scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
  1130. } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
  1131. this.scrollParent[ 0 ].scrollTop =
  1132. scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
  1133. }
  1134. if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
  1135. event.pageX < o.scrollSensitivity ) {
  1136. this.scrollParent[ 0 ].scrollLeft = scrolled =
  1137. this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
  1138. } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
  1139. this.scrollParent[ 0 ].scrollLeft = scrolled =
  1140. this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
  1141. }
  1142. } else {
  1143. if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
  1144. scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
  1145. } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
  1146. o.scrollSensitivity ) {
  1147. scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
  1148. }
  1149. if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
  1150. scrolled = this.document.scrollLeft(
  1151. this.document.scrollLeft() - o.scrollSpeed
  1152. );
  1153. } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
  1154. o.scrollSensitivity ) {
  1155. scrolled = this.document.scrollLeft(
  1156. this.document.scrollLeft() + o.scrollSpeed
  1157. );
  1158. }
  1159. }
  1160. if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
  1161. $.ui.ddmanager.prepareOffsets( this, event );
  1162. }
  1163. }
  1164. //Regenerate the absolute position used for position checks
  1165. this.positionAbs = this._convertPositionTo( "absolute" );
  1166. //Set the helper position
  1167. if ( !this.options.axis || this.options.axis !== "y" ) {
  1168. this.helper[ 0 ].style.left = this.position.left + "px";
  1169. }
  1170. if ( !this.options.axis || this.options.axis !== "x" ) {
  1171. this.helper[ 0 ].style.top = this.position.top + "px";
  1172. }
  1173. //Rearrange
  1174. for ( i = this.items.length - 1; i >= 0; i-- ) {
  1175. //Cache variables and intersection, continue if no intersection
  1176. item = this.items[ i ];
  1177. itemElement = item.item[ 0 ];
  1178. intersection = this._intersectsWithPointer( item );
  1179. if ( !intersection ) {
  1180. continue;
  1181. }
  1182. // Only put the placeholder inside the current Container, skip all
  1183. // items from other containers. This works because when moving
  1184. // an item from one container to another the
  1185. // currentContainer is switched before the placeholder is moved.
  1186. //
  1187. // Without this, moving items in "sub-sortables" can cause
  1188. // the placeholder to jitter between the outer and inner container.
  1189. if ( item.instance !== this.currentContainer ) {
  1190. continue;
  1191. }
  1192. // Cannot intersect with itself
  1193. // no useless actions that have been done before
  1194. // no action if the item moved is the parent of the item checked
  1195. if ( itemElement !== this.currentItem[ 0 ] &&
  1196. this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
  1197. !$.contains( this.placeholder[ 0 ], itemElement ) &&
  1198. ( this.options.type === "semi-dynamic" ?
  1199. !$.contains( this.element[ 0 ], itemElement ) :
  1200. true
  1201. )
  1202. ) {
  1203. this.direction = intersection === 1 ? "down" : "up";
  1204. if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
  1205. this._rearrange( event, item );
  1206. } else {
  1207. break;
  1208. }
  1209. this._trigger( "change", event, this._uiHash() );
  1210. break;
  1211. }
  1212. }
  1213. //Post events to containers
  1214. this._contactContainers( event );
  1215. //Interconnect with droppables
  1216. if ( $.ui.ddmanager ) {
  1217. $.ui.ddmanager.drag( this, event );
  1218. }
  1219. //Call callbacks
  1220. this._trigger( "sort", event, this._uiHash() );
  1221. this.lastPositionAbs = this.positionAbs;
  1222. return false;
  1223. },
  1224. _mouseStop: function( event, noPropagation ) {
  1225. if ( !event ) {
  1226. return;
  1227. }
  1228. //If we are using droppables, inform the manager about the drop
  1229. if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
  1230. $.ui.ddmanager.drop( this, event );
  1231. }
  1232. if ( this.options.revert ) {
  1233. var that = this,
  1234. cur = this.placeholder.offset(),
  1235. axis = this.options.axis,
  1236. animation = {};
  1237. if ( !axis || axis === "x" ) {
  1238. animation.left = cur.left - this.offset.parent.left - this.margins.left +
  1239. ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
  1240. 0 :
  1241. this.offsetParent[ 0 ].scrollLeft
  1242. );
  1243. }
  1244. if ( !axis || axis === "y" ) {
  1245. animation.top = cur.top - this.offset.parent.top - this.margins.top +
  1246. ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
  1247. 0 :
  1248. this.offsetParent[ 0 ].scrollTop
  1249. );
  1250. }
  1251. this.reverting = true;
  1252. $( this.helper ).animate(
  1253. animation,
  1254. parseInt( this.options.revert, 10 ) || 500,
  1255. function() {
  1256. that._clear( event );
  1257. }
  1258. );
  1259. } else {
  1260. this._clear( event, noPropagation );
  1261. }
  1262. return false;
  1263. },
  1264. cancel: function() {
  1265. if ( this.dragging ) {
  1266. this._mouseUp( new $.Event( "mouseup", { target: null } ) );
  1267. if ( this.options.helper === "original" ) {
  1268. this.currentItem.css( this._storedCSS );
  1269. this._removeClass( this.currentItem, "ui-sortable-helper" );
  1270. } else {
  1271. this.currentItem.show();
  1272. }
  1273. //Post deactivating events to containers
  1274. for ( var i = this.containers.length - 1; i >= 0; i-- ) {
  1275. this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
  1276. if ( this.containers[ i ].containerCache.over ) {
  1277. this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
  1278. this.containers[ i ].containerCache.over = 0;
  1279. }
  1280. }
  1281. }
  1282. if ( this.placeholder ) {
  1283. //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
  1284. // it unbinds ALL events from the original node!
  1285. if ( this.placeholder[ 0 ].parentNode ) {
  1286. this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
  1287. }
  1288. if ( this.options.helper !== "original" && this.helper &&
  1289. this.helper[ 0 ].parentNode ) {
  1290. this.helper.remove();
  1291. }
  1292. $.extend( this, {
  1293. helper: null,
  1294. dragging: false,
  1295. reverting: false,
  1296. _noFinalSort: null
  1297. } );
  1298. if ( this.domPosition.prev ) {
  1299. $( this.domPosition.prev ).after( this.currentItem );
  1300. } else {
  1301. $( this.domPosition.parent ).prepend( this.currentItem );
  1302. }
  1303. }
  1304. return this;
  1305. },
  1306. serialize: function( o ) {
  1307. var items = this._getItemsAsjQuery( o && o.connected ),
  1308. str = [];
  1309. o = o || {};
  1310. $( items ).each( function() {
  1311. var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
  1312. .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
  1313. if ( res ) {
  1314. str.push(
  1315. ( o.key || res[ 1 ] + "[]" ) +
  1316. "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
  1317. }
  1318. } );
  1319. if ( !str.length && o.key ) {
  1320. str.push( o.key + "=" );
  1321. }
  1322. return str.join( "&" );
  1323. },
  1324. toArray: function( o ) {
  1325. var items = this._getItemsAsjQuery( o && o.connected ),
  1326. ret = [];
  1327. o = o || {};
  1328. items.each( function() {
  1329. ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
  1330. } );
  1331. return ret;
  1332. },
  1333. /* Be careful with the following core functions */
  1334. _intersectsWith: function( item ) {
  1335. var x1 = this.positionAbs.left,
  1336. x2 = x1 + this.helperProportions.width,
  1337. y1 = this.positionAbs.top,
  1338. y2 = y1 + this.helperProportions.height,
  1339. l = item.left,
  1340. r = l + item.width,
  1341. t = item.top,
  1342. b = t + item.height,
  1343. dyClick = this.offset.click.top,
  1344. dxClick = this.offset.click.left,
  1345. isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
  1346. ( y1 + dyClick ) < b ),
  1347. isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
  1348. ( x1 + dxClick ) < r ),
  1349. isOverElement = isOverElementHeight && isOverElementWidth;
  1350. if ( this.options.tolerance === "pointer" ||
  1351. this.options.forcePointerForContainers ||
  1352. ( this.options.tolerance !== "pointer" &&
  1353. this.helperProportions[ this.floating ? "width" : "height" ] >
  1354. item[ this.floating ? "width" : "height" ] )
  1355. ) {
  1356. return isOverElement;
  1357. } else {
  1358. return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
  1359. x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
  1360. t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
  1361. y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
  1362. }
  1363. },
  1364. _intersectsWithPointer: function( item ) {
  1365. var verticalDirection, horizontalDirection,
  1366. isOverElementHeight = ( this.options.axis === "x" ) ||
  1367. this._isOverAxis(
  1368. this.positionAbs.top + this.offset.click.top, item.top, item.height ),
  1369. isOverElementWidth = ( this.options.axis === "y" ) ||
  1370. this._isOverAxis(
  1371. this.positionAbs.left + this.offset.click.left, item.left, item.width ),
  1372. isOverElement = isOverElementHeight && isOverElementWidth;
  1373. if ( !isOverElement ) {
  1374. return false;
  1375. }
  1376. verticalDirection = this._getDragVerticalDirection();
  1377. horizontalDirection = this._getDragHorizontalDirection();
  1378. return this.floating ?
  1379. ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
  1380. : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
  1381. },
  1382. _intersectsWithSides: function( item ) {
  1383. var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
  1384. this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
  1385. isOverRightHalf = this._isOverAxis( this.positionAbs.left +
  1386. this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
  1387. verticalDirection = this._getDragVerticalDirection(),
  1388. horizontalDirection = this._getDragHorizontalDirection();
  1389. if ( this.floating && horizontalDirection ) {
  1390. return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
  1391. ( horizontalDirection === "left" && !isOverRightHalf ) );
  1392. } else {
  1393. return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
  1394. ( verticalDirection === "up" && !isOverBottomHalf ) );
  1395. }
  1396. },
  1397. _getDragVerticalDirection: function() {
  1398. var delta = this.positionAbs.top - this.lastPositionAbs.top;
  1399. return delta !== 0 && ( delta > 0 ? "down" : "up" );
  1400. },
  1401. _getDragHorizontalDirection: function() {
  1402. var delta = this.positionAbs.left - this.lastPositionAbs.left;
  1403. return delta !== 0 && ( delta > 0 ? "right" : "left" );
  1404. },
  1405. refresh: function( event ) {
  1406. this._refreshItems( event );
  1407. this._setHandleClassName();
  1408. this.refreshPositions();
  1409. return this;
  1410. },
  1411. _connectWith: function() {
  1412. var options = this.options;
  1413. return options.connectWith.constructor === String ?
  1414. [ options.connectWith ] :
  1415. options.connectWith;
  1416. },
  1417. _getItemsAsjQuery: function( connected ) {
  1418. var i, j, cur, inst,
  1419. items = [],
  1420. queries = [],
  1421. connectWith = this._connectWith();
  1422. if ( connectWith && connected ) {
  1423. for ( i = connectWith.length - 1; i >= 0; i-- ) {
  1424. cur = $( connectWith[ i ], this.document[ 0 ] );
  1425. for ( j = cur.length - 1; j >= 0; j-- ) {
  1426. inst = $.data( cur[ j ], this.widgetFullName );
  1427. if ( inst && inst !== this && !inst.options.disabled ) {
  1428. queries.push( [ $.isFunction( inst.options.items ) ?
  1429. inst.options.items.call( inst.element ) :
  1430. $( inst.options.items, inst.element )
  1431. .not( ".ui-sortable-helper" )
  1432. .not( ".ui-sortable-placeholder" ), inst ] );
  1433. }
  1434. }
  1435. }
  1436. }
  1437. queries.push( [ $.isFunction( this.options.items ) ?
  1438. this.options.items
  1439. .call( this.element, null, { options: this.options, item: this.currentItem } ) :
  1440. $( this.options.items, this.element )
  1441. .not( ".ui-sortable-helper" )
  1442. .not( ".ui-sortable-placeholder" ), this ] );
  1443. function addItems() {
  1444. items.push( this );
  1445. }
  1446. for ( i = queries.length - 1; i >= 0; i-- ) {
  1447. queries[ i ][ 0 ].each( addItems );
  1448. }
  1449. return $( items );
  1450. },
  1451. _removeCurrentsFromItems: function() {
  1452. var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
  1453. this.items = $.grep( this.items, function( item ) {
  1454. for ( var j = 0; j < list.length; j++ ) {
  1455. if ( list[ j ] === item.item[ 0 ] ) {
  1456. return false;
  1457. }
  1458. }
  1459. return true;
  1460. } );
  1461. },
  1462. _refreshItems: function( event ) {
  1463. this.items = [];
  1464. this.containers = [ this ];
  1465. var i, j, cur, inst, targetData, _queries, item, queriesLength,
  1466. items = this.items,
  1467. queries = [ [ $.isFunction( this.options.items ) ?
  1468. this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
  1469. $( this.options.items, this.element ), this ] ],
  1470. connectWith = this._connectWith();
  1471. //Shouldn't be run the first time through due to massive slow-down
  1472. if ( connectWith && this.ready ) {
  1473. for ( i = connectWith.length - 1; i >= 0; i-- ) {
  1474. cur = $( connectWith[ i ], this.document[ 0 ] );
  1475. for ( j = cur.length - 1; j >= 0; j-- ) {
  1476. inst = $.data( cur[ j ], this.widgetFullName );
  1477. if ( inst && inst !== this && !inst.options.disabled ) {
  1478. queries.push( [ $.isFunction( inst.options.items ) ?
  1479. inst.options.items
  1480. .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
  1481. $( inst.options.items, inst.element ), inst ] );
  1482. this.containers.push( inst );
  1483. }
  1484. }
  1485. }
  1486. }
  1487. for ( i = queries.length - 1; i >= 0; i-- ) {
  1488. targetData = queries[ i ][ 1 ];
  1489. _queries = queries[ i ][ 0 ];
  1490. for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
  1491. item = $( _queries[ j ] );
  1492. // Data for target checking (mouse manager)
  1493. item.data( this.widgetName + "-item", targetData );
  1494. items.push( {
  1495. item: item,
  1496. instance: targetData,
  1497. width: 0, height: 0,
  1498. left: 0, top: 0
  1499. } );
  1500. }
  1501. }
  1502. },
  1503. refreshPositions: function( fast ) {
  1504. // Determine whether items are being displayed horizontally
  1505. this.floating = this.items.length ?
  1506. this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
  1507. false;
  1508. //This has to be redone because due to the item being moved out/into the offsetParent,
  1509. // the offsetParent's position will change
  1510. if ( this.offsetParent && this.helper ) {
  1511. this.offset.parent = this._getParentOffset();
  1512. }
  1513. var i, item, t, p;
  1514. for ( i = this.items.length - 1; i >= 0; i-- ) {
  1515. item = this.items[ i ];
  1516. //We ignore calculating positions of all connected containers when we're not over them
  1517. if ( item.instance !== this.currentContainer && this.currentContainer &&
  1518. item.item[ 0 ] !== this.currentItem[ 0 ] ) {
  1519. continue;
  1520. }
  1521. t = this.options.toleranceElement ?
  1522. $( this.options.toleranceElement, item.item ) :
  1523. item.item;
  1524. if ( !fast ) {
  1525. item.width = t.outerWidth();
  1526. item.height = t.outerHeight();
  1527. }
  1528. p = t.offset();
  1529. item.left = p.left;
  1530. item.top = p.top;
  1531. }
  1532. if ( this.options.custom && this.options.custom.refreshContainers ) {
  1533. this.options.custom.refreshContainers.call( this );
  1534. } else {
  1535. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  1536. p = this.containers[ i ].element.offset();
  1537. this.containers[ i ].containerCache.left = p.left;
  1538. this.containers[ i ].containerCache.top = p.top;
  1539. this.containers[ i ].containerCache.width =
  1540. this.containers[ i ].element.outerWidth();
  1541. this.containers[ i ].containerCache.height =
  1542. this.containers[ i ].element.outerHeight();
  1543. }
  1544. }
  1545. return this;
  1546. },
  1547. _createPlaceholder: function( that ) {
  1548. that = that || this;
  1549. var className,
  1550. o = that.options;
  1551. if ( !o.placeholder || o.placeholder.constructor === String ) {
  1552. className = o.placeholder;
  1553. o.placeholder = {
  1554. element: function() {
  1555. var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
  1556. element = $( "<" + nodeName + ">", that.document[ 0 ] );
  1557. that._addClass( element, "ui-sortable-placeholder",
  1558. className || that.currentItem[ 0 ].className )
  1559. ._removeClass( element, "ui-sortable-helper" );
  1560. if ( nodeName === "tbody" ) {
  1561. that._createTrPlaceholder(
  1562. that.currentItem.find( "tr" ).eq( 0 ),
  1563. $( "<tr>", that.document[ 0 ] ).appendTo( element )
  1564. );
  1565. } else if ( nodeName === "tr" ) {
  1566. that._createTrPlaceholder( that.currentItem, element );
  1567. } else if ( nodeName === "img" ) {
  1568. element.attr( "src", that.currentItem.attr( "src" ) );
  1569. }
  1570. if ( !className ) {
  1571. element.css( "visibility", "hidden" );
  1572. }
  1573. return element;
  1574. },
  1575. update: function( container, p ) {
  1576. // 1. If a className is set as 'placeholder option, we don't force sizes -
  1577. // the class is responsible for that
  1578. // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
  1579. // class name is specified
  1580. if ( className && !o.forcePlaceholderSize ) {
  1581. return;
  1582. }
  1583. //If the element doesn't have a actual height by itself (without styles coming
  1584. // from a stylesheet), it receives the inline height from the dragged item
  1585. if ( !p.height() ) {
  1586. p.height(
  1587. that.currentItem.innerHeight() -
  1588. parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
  1589. parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
  1590. }
  1591. if ( !p.width() ) {
  1592. p.width(
  1593. that.currentItem.innerWidth() -
  1594. parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
  1595. parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
  1596. }
  1597. }
  1598. };
  1599. }
  1600. //Create the placeholder
  1601. that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
  1602. //Append it after the actual current item
  1603. that.currentItem.after( that.placeholder );
  1604. //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
  1605. o.placeholder.update( that, that.placeholder );
  1606. },
  1607. _createTrPlaceholder: function( sourceTr, targetTr ) {
  1608. var that = this;
  1609. sourceTr.children().each( function() {
  1610. $( "<td>&#160;</td>", that.document[ 0 ] )
  1611. .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
  1612. .appendTo( targetTr );
  1613. } );
  1614. },
  1615. _contactContainers: function( event ) {
  1616. var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
  1617. floating, axis,
  1618. innermostContainer = null,
  1619. innermostIndex = null;
  1620. // Get innermost container that intersects with item
  1621. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  1622. // Never consider a container that's located within the item itself
  1623. if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
  1624. continue;
  1625. }
  1626. if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
  1627. // If we've already found a container and it's more "inner" than this, then continue
  1628. if ( innermostContainer &&
  1629. $.contains(
  1630. this.containers[ i ].element[ 0 ],
  1631. innermostContainer.element[ 0 ] ) ) {
  1632. continue;
  1633. }
  1634. innermostContainer = this.containers[ i ];
  1635. innermostIndex = i;
  1636. } else {
  1637. // container doesn't intersect. trigger "out" event if necessary
  1638. if ( this.containers[ i ].containerCache.over ) {
  1639. this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
  1640. this.containers[ i ].containerCache.over = 0;
  1641. }
  1642. }
  1643. }
  1644. // If no intersecting containers found, return
  1645. if ( !innermostContainer ) {
  1646. return;
  1647. }
  1648. // Move the item into the container if it's not there already
  1649. if ( this.containers.length === 1 ) {
  1650. if ( !this.containers[ innermostIndex ].containerCache.over ) {
  1651. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
  1652. this.containers[ innermostIndex ].containerCache.over = 1;
  1653. }
  1654. } else {
  1655. // When entering a new container, we will find the item with the least distance and
  1656. // append our item near it
  1657. dist = 10000;
  1658. itemWithLeastDistance = null;
  1659. floating = innermostContainer.floating || this._isFloating( this.currentItem );
  1660. posProperty = floating ? "left" : "top";
  1661. sizeProperty = floating ? "width" : "height";
  1662. axis = floating ? "pageX" : "pageY";
  1663. for ( j = this.items.length - 1; j >= 0; j-- ) {
  1664. if ( !$.contains(
  1665. this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
  1666. ) {
  1667. continue;
  1668. }
  1669. if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
  1670. continue;
  1671. }
  1672. cur = this.items[ j ].item.offset()[ posProperty ];
  1673. nearBottom = false;
  1674. if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
  1675. nearBottom = true;
  1676. }
  1677. if ( Math.abs( event[ axis ] - cur ) < dist ) {
  1678. dist = Math.abs( event[ axis ] - cur );
  1679. itemWithLeastDistance = this.items[ j ];
  1680. this.direction = nearBottom ? "up" : "down";
  1681. }
  1682. }
  1683. //Check if dropOnEmpty is enabled
  1684. if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
  1685. return;
  1686. }
  1687. if ( this.currentContainer === this.containers[ innermostIndex ] ) {
  1688. if ( !this.currentContainer.containerCache.over ) {
  1689. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
  1690. this.currentContainer.containerCache.over = 1;
  1691. }
  1692. return;
  1693. }
  1694. itemWithLeastDistance ?
  1695. this._rearrange( event, itemWithLeastDistance, null, true ) :
  1696. this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
  1697. this._trigger( "change", event, this._uiHash() );
  1698. this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
  1699. this.currentContainer = this.containers[ innermostIndex ];
  1700. //Update the placeholder
  1701. this.options.placeholder.update( this.currentContainer, this.placeholder );
  1702. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
  1703. this.containers[ innermostIndex ].containerCache.over = 1;
  1704. }
  1705. },
  1706. _createHelper: function( event ) {
  1707. var o = this.options,
  1708. helper = $.isFunction( o.helper ) ?
  1709. $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
  1710. ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
  1711. //Add the helper to the DOM if that didn't happen already
  1712. if ( !helper.parents( "body" ).length ) {
  1713. $( o.appendTo !== "parent" ?
  1714. o.appendTo :
  1715. this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
  1716. }
  1717. if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
  1718. this._storedCSS = {
  1719. width: this.currentItem[ 0 ].style.width,
  1720. height: this.currentItem[ 0 ].style.height,
  1721. position: this.currentItem.css( "position" ),
  1722. top: this.currentItem.css( "top" ),
  1723. left: this.currentItem.css( "left" )
  1724. };
  1725. }
  1726. if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
  1727. helper.width( this.currentItem.width() );
  1728. }
  1729. if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
  1730. helper.height( this.currentItem.height() );
  1731. }
  1732. return helper;
  1733. },
  1734. _adjustOffsetFromHelper: function( obj ) {
  1735. if ( typeof obj === "string" ) {
  1736. obj = obj.split( " " );
  1737. }
  1738. if ( $.isArray( obj ) ) {
  1739. obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
  1740. }
  1741. if ( "left" in obj ) {
  1742. this.offset.click.left = obj.left + this.margins.left;
  1743. }
  1744. if ( "right" in obj ) {
  1745. this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
  1746. }
  1747. if ( "top" in obj ) {
  1748. this.offset.click.top = obj.top + this.margins.top;
  1749. }
  1750. if ( "bottom" in obj ) {
  1751. this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
  1752. }
  1753. },
  1754. _getParentOffset: function() {
  1755. //Get the offsetParent and cache its position
  1756. this.offsetParent = this.helper.offsetParent();
  1757. var po = this.offsetParent.offset();
  1758. // This is a special case where we need to modify a offset calculated on start, since the
  1759. // following happened:
  1760. // 1. The position of the helper is absolute, so it's position is calculated based on the
  1761. // next positioned parent
  1762. // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
  1763. // the document, which means that the scroll is included in the initial calculation of the
  1764. // offset of the parent, and never recalculated upon drag
  1765. if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1766. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
  1767. po.left += this.scrollParent.scrollLeft();
  1768. po.top += this.scrollParent.scrollTop();
  1769. }
  1770. // This needs to be actually done for all browsers, since pageX/pageY includes this
  1771. // information with an ugly IE fix
  1772. if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
  1773. ( this.offsetParent[ 0 ].tagName &&
  1774. this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
  1775. po = { top: 0, left: 0 };
  1776. }
  1777. return {
  1778. top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
  1779. left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
  1780. };
  1781. },
  1782. _getRelativeOffset: function() {
  1783. if ( this.cssPosition === "relative" ) {
  1784. var p = this.currentItem.position();
  1785. return {
  1786. top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
  1787. this.scrollParent.scrollTop(),
  1788. left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
  1789. this.scrollParent.scrollLeft()
  1790. };
  1791. } else {
  1792. return { top: 0, left: 0 };
  1793. }
  1794. },
  1795. _cacheMargins: function() {
  1796. this.margins = {
  1797. left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
  1798. top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
  1799. };
  1800. },
  1801. _cacheHelperProportions: function() {
  1802. this.helperProportions = {
  1803. width: this.helper.outerWidth(),
  1804. height: this.helper.outerHeight()
  1805. };
  1806. },
  1807. _setContainment: function() {
  1808. var ce, co, over,
  1809. o = this.options;
  1810. if ( o.containment === "parent" ) {
  1811. o.containment = this.helper[ 0 ].parentNode;
  1812. }
  1813. if ( o.containment === "document" || o.containment === "window" ) {
  1814. this.containment = [
  1815. 0 - this.offset.relative.left - this.offset.parent.left,
  1816. 0 - this.offset.relative.top - this.offset.parent.top,
  1817. o.containment === "document" ?
  1818. this.document.width() :
  1819. this.window.width() - this.helperProportions.width - this.margins.left,
  1820. ( o.containment === "document" ?
  1821. ( this.document.height() || document.body.parentNode.scrollHeight ) :
  1822. this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
  1823. ) - this.helperProportions.height - this.margins.top
  1824. ];
  1825. }
  1826. if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
  1827. ce = $( o.containment )[ 0 ];
  1828. co = $( o.containment ).offset();
  1829. over = ( $( ce ).css( "overflow" ) !== "hidden" );
  1830. this.containment = [
  1831. co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
  1832. ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
  1833. co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
  1834. ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
  1835. co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
  1836. ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
  1837. ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
  1838. this.helperProportions.width - this.margins.left,
  1839. co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
  1840. ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
  1841. ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
  1842. this.helperProportions.height - this.margins.top
  1843. ];
  1844. }
  1845. },
  1846. _convertPositionTo: function( d, pos ) {
  1847. if ( !pos ) {
  1848. pos = this.position;
  1849. }
  1850. var mod = d === "absolute" ? 1 : -1,
  1851. scroll = this.cssPosition === "absolute" &&
  1852. !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1853. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
  1854. this.offsetParent :
  1855. this.scrollParent,
  1856. scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
  1857. return {
  1858. top: (
  1859. // The absolute mouse position
  1860. pos.top +
  1861. // Only for relative positioned nodes: Relative offset from element to offset parent
  1862. this.offset.relative.top * mod +
  1863. // The offsetParent's offset without borders (offset + border)
  1864. this.offset.parent.top * mod -
  1865. ( ( this.cssPosition === "fixed" ?
  1866. -this.scrollParent.scrollTop() :
  1867. ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
  1868. ),
  1869. left: (
  1870. // The absolute mouse position
  1871. pos.left +
  1872. // Only for relative positioned nodes: Relative offset from element to offset parent
  1873. this.offset.relative.left * mod +
  1874. // The offsetParent's offset without borders (offset + border)
  1875. this.offset.parent.left * mod -
  1876. ( ( this.cssPosition === "fixed" ?
  1877. -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
  1878. scroll.scrollLeft() ) * mod )
  1879. )
  1880. };
  1881. },
  1882. _generatePosition: function( event ) {
  1883. var top, left,
  1884. o = this.options,
  1885. pageX = event.pageX,
  1886. pageY = event.pageY,
  1887. scroll = this.cssPosition === "absolute" &&
  1888. !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1889. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
  1890. this.offsetParent :
  1891. this.scrollParent,
  1892. scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
  1893. // This is another very weird special case that only happens for relative elements:
  1894. // 1. If the css position is relative
  1895. // 2. and the scroll parent is the document or similar to the offset parent
  1896. // we have to refresh the relative offset during the scroll so there are no jumps
  1897. if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1898. this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
  1899. this.offset.relative = this._getRelativeOffset();
  1900. }
  1901. /*
  1902. * - Position constraining -
  1903. * Constrain the position to a mix of grid, containment.
  1904. */
  1905. if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
  1906. if ( this.containment ) {
  1907. if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
  1908. pageX = this.containment[ 0 ] + this.offset.click.left;
  1909. }
  1910. if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
  1911. pageY = this.containment[ 1 ] + this.offset.click.top;
  1912. }
  1913. if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
  1914. pageX = this.containment[ 2 ] + this.offset.click.left;
  1915. }
  1916. if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
  1917. pageY = this.containment[ 3 ] + this.offset.click.top;
  1918. }
  1919. }
  1920. if ( o.grid ) {
  1921. top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
  1922. o.grid[ 1 ] ) * o.grid[ 1 ];
  1923. pageY = this.containment ?
  1924. ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
  1925. top - this.offset.click.top <= this.containment[ 3 ] ) ?
  1926. top :
  1927. ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
  1928. top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
  1929. top;
  1930. left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
  1931. o.grid[ 0 ] ) * o.grid[ 0 ];
  1932. pageX = this.containment ?
  1933. ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
  1934. left - this.offset.click.left <= this.containment[ 2 ] ) ?
  1935. left :
  1936. ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
  1937. left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
  1938. left;
  1939. }
  1940. }
  1941. return {
  1942. top: (
  1943. // The absolute mouse position
  1944. pageY -
  1945. // Click offset (relative to the element)
  1946. this.offset.click.top -
  1947. // Only for relative positioned nodes: Relative offset from element to offset parent
  1948. this.offset.relative.top -
  1949. // The offsetParent's offset without borders (offset + border)
  1950. this.offset.parent.top +
  1951. ( ( this.cssPosition === "fixed" ?
  1952. -this.scrollParent.scrollTop() :
  1953. ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
  1954. ),
  1955. left: (
  1956. // The absolute mouse position
  1957. pageX -
  1958. // Click offset (relative to the element)
  1959. this.offset.click.left -
  1960. // Only for relative positioned nodes: Relative offset from element to offset parent
  1961. this.offset.relative.left -
  1962. // The offsetParent's offset without borders (offset + border)
  1963. this.offset.parent.left +
  1964. ( ( this.cssPosition === "fixed" ?
  1965. -this.scrollParent.scrollLeft() :
  1966. scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
  1967. )
  1968. };
  1969. },
  1970. _rearrange: function( event, i, a, hardRefresh ) {
  1971. a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
  1972. i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
  1973. ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
  1974. //Various things done here to improve the performance:
  1975. // 1. we create a setTimeout, that calls refreshPositions
  1976. // 2. on the instance, we have a counter variable, that get's higher after every append
  1977. // 3. on the local scope, we copy the counter variable, and check in the timeout,
  1978. // if it's still the same
  1979. // 4. this lets only the last addition to the timeout stack through
  1980. this.counter = this.counter ? ++this.counter : 1;
  1981. var counter = this.counter;
  1982. this._delay( function() {
  1983. if ( counter === this.counter ) {
  1984. //Precompute after each DOM insertion, NOT on mousemove
  1985. this.refreshPositions( !hardRefresh );
  1986. }
  1987. } );
  1988. },
  1989. _clear: function( event, noPropagation ) {
  1990. this.reverting = false;
  1991. // We delay all events that have to be triggered to after the point where the placeholder
  1992. // has been removed and everything else normalized again
  1993. var i,
  1994. delayedTriggers = [];
  1995. // We first have to update the dom position of the actual currentItem
  1996. // Note: don't do it if the current item is already removed (by a user), or it gets
  1997. // reappended (see #4088)
  1998. if ( !this._noFinalSort && this.currentItem.parent().length ) {
  1999. this.placeholder.before( this.currentItem );
  2000. }
  2001. this._noFinalSort = null;
  2002. if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
  2003. for ( i in this._storedCSS ) {
  2004. if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
  2005. this._storedCSS[ i ] = "";
  2006. }
  2007. }
  2008. this.currentItem.css( this._storedCSS );
  2009. this._removeClass( this.currentItem, "ui-sortable-helper" );
  2010. } else {
  2011. this.currentItem.show();
  2012. }
  2013. if ( this.fromOutside && !noPropagation ) {
  2014. delayedTriggers.push( function( event ) {
  2015. this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
  2016. } );
  2017. }
  2018. if ( ( this.fromOutside ||
  2019. this.domPosition.prev !==
  2020. this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
  2021. this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
  2022. // Trigger update callback if the DOM position has changed
  2023. delayedTriggers.push( function( event ) {
  2024. this._trigger( "update", event, this._uiHash() );
  2025. } );
  2026. }
  2027. // Check if the items Container has Changed and trigger appropriate
  2028. // events.
  2029. if ( this !== this.currentContainer ) {
  2030. if ( !noPropagation ) {
  2031. delayedTriggers.push( function( event ) {
  2032. this._trigger( "remove", event, this._uiHash() );
  2033. } );
  2034. delayedTriggers.push( ( function( c ) {
  2035. return function( event ) {
  2036. c._trigger( "receive", event, this._uiHash( this ) );
  2037. };
  2038. } ).call( this, this.currentContainer ) );
  2039. delayedTriggers.push( ( function( c ) {
  2040. return function( event ) {
  2041. c._trigger( "update", event, this._uiHash( this ) );
  2042. };
  2043. } ).call( this, this.currentContainer ) );
  2044. }
  2045. }
  2046. //Post events to containers
  2047. function delayEvent( type, instance, container ) {
  2048. return function( event ) {
  2049. container._trigger( type, event, instance._uiHash( instance ) );
  2050. };
  2051. }
  2052. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  2053. if ( !noPropagation ) {
  2054. delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
  2055. }
  2056. if ( this.containers[ i ].containerCache.over ) {
  2057. delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
  2058. this.containers[ i ].containerCache.over = 0;
  2059. }
  2060. }
  2061. //Do what was originally in plugins
  2062. if ( this.storedCursor ) {
  2063. this.document.find( "body" ).css( "cursor", this.storedCursor );
  2064. this.storedStylesheet.remove();
  2065. }
  2066. if ( this._storedOpacity ) {
  2067. this.helper.css( "opacity", this._storedOpacity );
  2068. }
  2069. if ( this._storedZIndex ) {
  2070. this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
  2071. }
  2072. this.dragging = false;
  2073. if ( !noPropagation ) {
  2074. this._trigger( "beforeStop", event, this._uiHash() );
  2075. }
  2076. //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
  2077. // it unbinds ALL events from the original node!
  2078. this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
  2079. if ( !this.cancelHelperRemoval ) {
  2080. if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
  2081. this.helper.remove();
  2082. }
  2083. this.helper = null;
  2084. }
  2085. if ( !noPropagation ) {
  2086. for ( i = 0; i < delayedTriggers.length; i++ ) {
  2087. // Trigger all delayed events
  2088. delayedTriggers[ i ].call( this, event );
  2089. }
  2090. this._trigger( "stop", event, this._uiHash() );
  2091. }
  2092. this.fromOutside = false;
  2093. return !this.cancelHelperRemoval;
  2094. },
  2095. _trigger: function() {
  2096. if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
  2097. this.cancel();
  2098. }
  2099. },
  2100. _uiHash: function( _inst ) {
  2101. var inst = _inst || this;
  2102. return {
  2103. helper: inst.helper,
  2104. placeholder: inst.placeholder || $( [] ),
  2105. position: inst.position,
  2106. originalPosition: inst.originalPosition,
  2107. offset: inst.positionAbs,
  2108. item: inst.currentItem,
  2109. sender: _inst ? _inst.element : null
  2110. };
  2111. }
  2112. } );
  2113. // jscs:disable maximumLineLength
  2114. /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
  2115. /*!
  2116. * jQuery UI Datepicker 1.12.1
  2117. * http://jqueryui.com
  2118. *
  2119. * Copyright jQuery Foundation and other contributors
  2120. * Released under the MIT license.
  2121. * http://jquery.org/license
  2122. */
  2123. //>>label: Datepicker
  2124. //>>group: Widgets
  2125. //>>description: Displays a calendar from an input or inline for selecting dates.
  2126. //>>docs: http://api.jqueryui.com/datepicker/
  2127. //>>demos: http://jqueryui.com/datepicker/
  2128. //>>css.structure: ../../themes/base/core.css
  2129. //>>css.structure: ../../themes/base/datepicker.css
  2130. //>>css.theme: ../../themes/base/theme.css
  2131. $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
  2132. var datepicker_instActive;
  2133. function datepicker_getZindex( elem ) {
  2134. var position, value;
  2135. while ( elem.length && elem[ 0 ] !== document ) {
  2136. // Ignore z-index if position is set to a value where z-index is ignored by the browser
  2137. // This makes behavior of this function consistent across browsers
  2138. // WebKit always returns auto if the element is positioned
  2139. position = elem.css( "position" );
  2140. if ( position === "absolute" || position === "relative" || position === "fixed" ) {
  2141. // IE returns 0 when zIndex is not specified
  2142. // other browsers return a string
  2143. // we ignore the case of nested elements with an explicit value of 0
  2144. // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
  2145. value = parseInt( elem.css( "zIndex" ), 10 );
  2146. if ( !isNaN( value ) && value !== 0 ) {
  2147. return value;
  2148. }
  2149. }
  2150. elem = elem.parent();
  2151. }
  2152. return 0;
  2153. }
  2154. /* Date picker manager.
  2155. Use the singleton instance of this class, $.datepicker, to interact with the date picker.
  2156. Settings for (groups of) date pickers are maintained in an instance object,
  2157. allowing multiple different settings on the same page. */
  2158. function Datepicker() {
  2159. this._curInst = null; // The current instance in use
  2160. this._keyEvent = false; // If the last event was a key event
  2161. this._disabledInputs = []; // List of date picker inputs that have been disabled
  2162. this._datepickerShowing = false; // True if the popup picker is showing , false if not
  2163. this._inDialog = false; // True if showing within a "dialog", false if not
  2164. this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
  2165. this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
  2166. this._appendClass = "ui-datepicker-append"; // The name of the append marker class
  2167. this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
  2168. this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
  2169. this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
  2170. this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
  2171. this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
  2172. this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
  2173. this.regional = []; // Available regional settings, indexed by language code
  2174. this.regional[ "" ] = { // Default regional settings
  2175. closeText: "Done", // Display text for close link
  2176. prevText: "Prev", // Display text for previous month link
  2177. nextText: "Next", // Display text for next month link
  2178. currentText: "Today", // Display text for current month link
  2179. monthNames: [ "January","February","March","April","May","June",
  2180. "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
  2181. monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
  2182. dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
  2183. dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
  2184. dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
  2185. weekHeader: "Wk", // Column header for week of the year
  2186. dateFormat: "mm/dd/yy", // See format options on parseDate
  2187. firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
  2188. isRTL: false, // True if right-to-left language, false if left-to-right
  2189. showMonthAfterYear: false, // True if the year select precedes month, false for month then year
  2190. yearSuffix: "" // Additional text to append to the year in the month headers
  2191. };
  2192. this._defaults = { // Global defaults for all the date picker instances
  2193. showOn: "focus", // "focus" for popup on focus,
  2194. // "button" for trigger button, or "both" for either
  2195. showAnim: "fadeIn", // Name of jQuery animation for popup
  2196. showOptions: {}, // Options for enhanced animations
  2197. defaultDate: null, // Used when field is blank: actual date,
  2198. // +/-number for offset from today, null for today
  2199. appendText: "", // Display text following the input box, e.g. showing the format
  2200. buttonText: "...", // Text for trigger button
  2201. buttonImage: "", // URL for trigger button image
  2202. buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
  2203. hideIfNoPrevNext: false, // True to hide next/previous month links
  2204. // if not applicable, false to just disable them
  2205. navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
  2206. gotoCurrent: false, // True if today link goes back to current selection instead
  2207. changeMonth: false, // True if month can be selected directly, false if only prev/next
  2208. changeYear: false, // True if year can be selected directly, false if only prev/next
  2209. yearRange: "c-10:c+10", // Range of years to display in drop-down,
  2210. // either relative to today's year (-nn:+nn), relative to currently displayed year
  2211. // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
  2212. showOtherMonths: false, // True to show dates in other months, false to leave blank
  2213. selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
  2214. showWeek: false, // True to show week of the year, false to not show it
  2215. calculateWeek: this.iso8601Week, // How to calculate the week of the year,
  2216. // takes a Date and returns the number of the week for it
  2217. shortYearCutoff: "+10", // Short year values < this are in the current century,
  2218. // > this are in the previous century,
  2219. // string value starting with "+" for current year + value
  2220. minDate: null, // The earliest selectable date, or null for no limit
  2221. maxDate: null, // The latest selectable date, or null for no limit
  2222. duration: "fast", // Duration of display/closure
  2223. beforeShowDay: null, // Function that takes a date and returns an array with
  2224. // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
  2225. // [2] = cell title (optional), e.g. $.datepicker.noWeekends
  2226. beforeShow: null, // Function that takes an input field and
  2227. // returns a set of custom settings for the date picker
  2228. onSelect: null, // Define a callback function when a date is selected
  2229. onChangeMonthYear: null, // Define a callback function when the month or year is changed
  2230. onClose: null, // Define a callback function when the datepicker is closed
  2231. numberOfMonths: 1, // Number of months to show at a time
  2232. showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
  2233. stepMonths: 1, // Number of months to step back/forward
  2234. stepBigMonths: 12, // Number of months to step back/forward for the big links
  2235. altField: "", // Selector for an alternate field to store selected dates into
  2236. altFormat: "", // The date format to use for the alternate field
  2237. constrainInput: true, // The input is constrained by the current date format
  2238. showButtonPanel: false, // True to show button panel, false to not show it
  2239. autoSize: false, // True to size the input for the date format, false to leave as is
  2240. disabled: false // The initial disabled state
  2241. };
  2242. $.extend( this._defaults, this.regional[ "" ] );
  2243. this.regional.en = $.extend( true, {}, this.regional[ "" ] );
  2244. this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
  2245. this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
  2246. }
  2247. $.extend( Datepicker.prototype, {
  2248. /* Class name added to elements to indicate already configured with a date picker. */
  2249. markerClassName: "hasDatepicker",
  2250. //Keep track of the maximum number of rows displayed (see #7043)
  2251. maxRows: 4,
  2252. // TODO rename to "widget" when switching to widget factory
  2253. _widgetDatepicker: function() {
  2254. return this.dpDiv;
  2255. },
  2256. /* Override the default settings for all instances of the date picker.
  2257. * @param settings object - the new settings to use as defaults (anonymous object)
  2258. * @return the manager object
  2259. */
  2260. setDefaults: function( settings ) {
  2261. datepicker_extendRemove( this._defaults, settings || {} );
  2262. return this;
  2263. },
  2264. /* Attach the date picker to a jQuery selection.
  2265. * @param target element - the target input field or division or span
  2266. * @param settings object - the new settings to use for this date picker instance (anonymous)
  2267. */
  2268. _attachDatepicker: function( target, settings ) {
  2269. var nodeName, inline, inst;
  2270. nodeName = target.nodeName.toLowerCase();
  2271. inline = ( nodeName === "div" || nodeName === "span" );
  2272. if ( !target.id ) {
  2273. this.uuid += 1;
  2274. target.id = "dp" + this.uuid;
  2275. }
  2276. inst = this._newInst( $( target ), inline );
  2277. inst.settings = $.extend( {}, settings || {} );
  2278. if ( nodeName === "input" ) {
  2279. this._connectDatepicker( target, inst );
  2280. } else if ( inline ) {
  2281. this._inlineDatepicker( target, inst );
  2282. }
  2283. },
  2284. /* Create a new instance object. */
  2285. _newInst: function( target, inline ) {
  2286. var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
  2287. return { id: id, input: target, // associated target
  2288. selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
  2289. drawMonth: 0, drawYear: 0, // month being drawn
  2290. inline: inline, // is datepicker inline or not
  2291. dpDiv: ( !inline ? this.dpDiv : // presentation div
  2292. datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
  2293. },
  2294. /* Attach the date picker to an input field. */
  2295. _connectDatepicker: function( target, inst ) {
  2296. var input = $( target );
  2297. inst.append = $( [] );
  2298. inst.trigger = $( [] );
  2299. if ( input.hasClass( this.markerClassName ) ) {
  2300. return;
  2301. }
  2302. this._attachments( input, inst );
  2303. input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
  2304. on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
  2305. this._autoSize( inst );
  2306. $.data( target, "datepicker", inst );
  2307. //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
  2308. if ( inst.settings.disabled ) {
  2309. this._disableDatepicker( target );
  2310. }
  2311. },
  2312. /* Make attachments based on settings. */
  2313. _attachments: function( input, inst ) {
  2314. var showOn, buttonText, buttonImage,
  2315. appendText = this._get( inst, "appendText" ),
  2316. isRTL = this._get( inst, "isRTL" );
  2317. if ( inst.append ) {
  2318. inst.append.remove();
  2319. }
  2320. if ( appendText ) {
  2321. inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
  2322. input[ isRTL ? "before" : "after" ]( inst.append );
  2323. }
  2324. input.off( "focus", this._showDatepicker );
  2325. if ( inst.trigger ) {
  2326. inst.trigger.remove();
  2327. }
  2328. showOn = this._get( inst, "showOn" );
  2329. if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
  2330. input.on( "focus", this._showDatepicker );
  2331. }
  2332. if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
  2333. buttonText = this._get( inst, "buttonText" );
  2334. buttonImage = this._get( inst, "buttonImage" );
  2335. inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
  2336. $( "<img/>" ).addClass( this._triggerClass ).
  2337. attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
  2338. $( "<button type='button'></button>" ).addClass( this._triggerClass ).
  2339. html( !buttonImage ? buttonText : $( "<img/>" ).attr(
  2340. { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
  2341. input[ isRTL ? "before" : "after" ]( inst.trigger );
  2342. inst.trigger.on( "click", function() {
  2343. if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
  2344. $.datepicker._hideDatepicker();
  2345. } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
  2346. $.datepicker._hideDatepicker();
  2347. $.datepicker._showDatepicker( input[ 0 ] );
  2348. } else {
  2349. $.datepicker._showDatepicker( input[ 0 ] );
  2350. }
  2351. return false;
  2352. } );
  2353. }
  2354. },
  2355. /* Apply the maximum length for the date format. */
  2356. _autoSize: function( inst ) {
  2357. if ( this._get( inst, "autoSize" ) && !inst.inline ) {
  2358. var findMax, max, maxI, i,
  2359. date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
  2360. dateFormat = this._get( inst, "dateFormat" );
  2361. if ( dateFormat.match( /[DM]/ ) ) {
  2362. findMax = function( names ) {
  2363. max = 0;
  2364. maxI = 0;
  2365. for ( i = 0; i < names.length; i++ ) {
  2366. if ( names[ i ].length > max ) {
  2367. max = names[ i ].length;
  2368. maxI = i;
  2369. }
  2370. }
  2371. return maxI;
  2372. };
  2373. date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
  2374. "monthNames" : "monthNamesShort" ) ) ) );
  2375. date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
  2376. "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
  2377. }
  2378. inst.input.attr( "size", this._formatDate( inst, date ).length );
  2379. }
  2380. },
  2381. /* Attach an inline date picker to a div. */
  2382. _inlineDatepicker: function( target, inst ) {
  2383. var divSpan = $( target );
  2384. if ( divSpan.hasClass( this.markerClassName ) ) {
  2385. return;
  2386. }
  2387. divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
  2388. $.data( target, "datepicker", inst );
  2389. this._setDate( inst, this._getDefaultDate( inst ), true );
  2390. this._updateDatepicker( inst );
  2391. this._updateAlternate( inst );
  2392. //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
  2393. if ( inst.settings.disabled ) {
  2394. this._disableDatepicker( target );
  2395. }
  2396. // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
  2397. // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
  2398. inst.dpDiv.css( "display", "block" );
  2399. },
  2400. /* Pop-up the date picker in a "dialog" box.
  2401. * @param input element - ignored
  2402. * @param date string or Date - the initial date to display
  2403. * @param onSelect function - the function to call when a date is selected
  2404. * @param settings object - update the dialog date picker instance's settings (anonymous object)
  2405. * @param pos int[2] - coordinates for the dialog's position within the screen or
  2406. * event - with x/y coordinates or
  2407. * leave empty for default (screen centre)
  2408. * @return the manager object
  2409. */
  2410. _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
  2411. var id, browserWidth, browserHeight, scrollX, scrollY,
  2412. inst = this._dialogInst; // internal instance
  2413. if ( !inst ) {
  2414. this.uuid += 1;
  2415. id = "dp" + this.uuid;
  2416. this._dialogInput = $( "<input type='text' id='" + id +
  2417. "' style='position: absolute; top: -100px; width: 0px;'/>" );
  2418. this._dialogInput.on( "keydown", this._doKeyDown );
  2419. $( "body" ).append( this._dialogInput );
  2420. inst = this._dialogInst = this._newInst( this._dialogInput, false );
  2421. inst.settings = {};
  2422. $.data( this._dialogInput[ 0 ], "datepicker", inst );
  2423. }
  2424. datepicker_extendRemove( inst.settings, settings || {} );
  2425. date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
  2426. this._dialogInput.val( date );
  2427. this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
  2428. if ( !this._pos ) {
  2429. browserWidth = document.documentElement.clientWidth;
  2430. browserHeight = document.documentElement.clientHeight;
  2431. scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
  2432. scrollY = document.documentElement.scrollTop || document.body.scrollTop;
  2433. this._pos = // should use actual width/height below
  2434. [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
  2435. }
  2436. // Move input on screen for focus, but hidden behind dialog
  2437. this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
  2438. inst.settings.onSelect = onSelect;
  2439. this._inDialog = true;
  2440. this.dpDiv.addClass( this._dialogClass );
  2441. this._showDatepicker( this._dialogInput[ 0 ] );
  2442. if ( $.blockUI ) {
  2443. $.blockUI( this.dpDiv );
  2444. }
  2445. $.data( this._dialogInput[ 0 ], "datepicker", inst );
  2446. return this;
  2447. },
  2448. /* Detach a datepicker from its control.
  2449. * @param target element - the target input field or division or span
  2450. */
  2451. _destroyDatepicker: function( target ) {
  2452. var nodeName,
  2453. $target = $( target ),
  2454. inst = $.data( target, "datepicker" );
  2455. if ( !$target.hasClass( this.markerClassName ) ) {
  2456. return;
  2457. }
  2458. nodeName = target.nodeName.toLowerCase();
  2459. $.removeData( target, "datepicker" );
  2460. if ( nodeName === "input" ) {
  2461. inst.append.remove();
  2462. inst.trigger.remove();
  2463. $target.removeClass( this.markerClassName ).
  2464. off( "focus", this._showDatepicker ).
  2465. off( "keydown", this._doKeyDown ).
  2466. off( "keypress", this._doKeyPress ).
  2467. off( "keyup", this._doKeyUp );
  2468. } else if ( nodeName === "div" || nodeName === "span" ) {
  2469. $target.removeClass( this.markerClassName ).empty();
  2470. }
  2471. if ( datepicker_instActive === inst ) {
  2472. datepicker_instActive = null;
  2473. }
  2474. },
  2475. /* Enable the date picker to a jQuery selection.
  2476. * @param target element - the target input field or division or span
  2477. */
  2478. _enableDatepicker: function( target ) {
  2479. var nodeName, inline,
  2480. $target = $( target ),
  2481. inst = $.data( target, "datepicker" );
  2482. if ( !$target.hasClass( this.markerClassName ) ) {
  2483. return;
  2484. }
  2485. nodeName = target.nodeName.toLowerCase();
  2486. if ( nodeName === "input" ) {
  2487. target.disabled = false;
  2488. inst.trigger.filter( "button" ).
  2489. each( function() { this.disabled = false; } ).end().
  2490. filter( "img" ).css( { opacity: "1.0", cursor: "" } );
  2491. } else if ( nodeName === "div" || nodeName === "span" ) {
  2492. inline = $target.children( "." + this._inlineClass );
  2493. inline.children().removeClass( "ui-state-disabled" );
  2494. inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
  2495. prop( "disabled", false );
  2496. }
  2497. this._disabledInputs = $.map( this._disabledInputs,
  2498. function( value ) { return ( value === target ? null : value ); } ); // delete entry
  2499. },
  2500. /* Disable the date picker to a jQuery selection.
  2501. * @param target element - the target input field or division or span
  2502. */
  2503. _disableDatepicker: function( target ) {
  2504. var nodeName, inline,
  2505. $target = $( target ),
  2506. inst = $.data( target, "datepicker" );
  2507. if ( !$target.hasClass( this.markerClassName ) ) {
  2508. return;
  2509. }
  2510. nodeName = target.nodeName.toLowerCase();
  2511. if ( nodeName === "input" ) {
  2512. target.disabled = true;
  2513. inst.trigger.filter( "button" ).
  2514. each( function() { this.disabled = true; } ).end().
  2515. filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
  2516. } else if ( nodeName === "div" || nodeName === "span" ) {
  2517. inline = $target.children( "." + this._inlineClass );
  2518. inline.children().addClass( "ui-state-disabled" );
  2519. inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
  2520. prop( "disabled", true );
  2521. }
  2522. this._disabledInputs = $.map( this._disabledInputs,
  2523. function( value ) { return ( value === target ? null : value ); } ); // delete entry
  2524. this._disabledInputs[ this._disabledInputs.length ] = target;
  2525. },
  2526. /* Is the first field in a jQuery collection disabled as a datepicker?
  2527. * @param target element - the target input field or division or span
  2528. * @return boolean - true if disabled, false if enabled
  2529. */
  2530. _isDisabledDatepicker: function( target ) {
  2531. if ( !target ) {
  2532. return false;
  2533. }
  2534. for ( var i = 0; i < this._disabledInputs.length; i++ ) {
  2535. if ( this._disabledInputs[ i ] === target ) {
  2536. return true;
  2537. }
  2538. }
  2539. return false;
  2540. },
  2541. /* Retrieve the instance data for the target control.
  2542. * @param target element - the target input field or division or span
  2543. * @return object - the associated instance data
  2544. * @throws error if a jQuery problem getting data
  2545. */
  2546. _getInst: function( target ) {
  2547. try {
  2548. return $.data( target, "datepicker" );
  2549. }
  2550. catch ( err ) {
  2551. throw "Missing instance data for this datepicker";
  2552. }
  2553. },
  2554. /* Update or retrieve the settings for a date picker attached to an input field or division.
  2555. * @param target element - the target input field or division or span
  2556. * @param name object - the new settings to update or
  2557. * string - the name of the setting to change or retrieve,
  2558. * when retrieving also "all" for all instance settings or
  2559. * "defaults" for all global defaults
  2560. * @param value any - the new value for the setting
  2561. * (omit if above is an object or to retrieve a value)
  2562. */
  2563. _optionDatepicker: function( target, name, value ) {
  2564. var settings, date, minDate, maxDate,
  2565. inst = this._getInst( target );
  2566. if ( arguments.length === 2 && typeof name === "string" ) {
  2567. return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
  2568. ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
  2569. this._get( inst, name ) ) : null ) );
  2570. }
  2571. settings = name || {};
  2572. if ( typeof name === "string" ) {
  2573. settings = {};
  2574. settings[ name ] = value;
  2575. }
  2576. if ( inst ) {
  2577. if ( this._curInst === inst ) {
  2578. this._hideDatepicker();
  2579. }
  2580. date = this._getDateDatepicker( target, true );
  2581. minDate = this._getMinMaxDate( inst, "min" );
  2582. maxDate = this._getMinMaxDate( inst, "max" );
  2583. datepicker_extendRemove( inst.settings, settings );
  2584. // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
  2585. if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
  2586. inst.settings.minDate = this._formatDate( inst, minDate );
  2587. }
  2588. if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
  2589. inst.settings.maxDate = this._formatDate( inst, maxDate );
  2590. }
  2591. if ( "disabled" in settings ) {
  2592. if ( settings.disabled ) {
  2593. this._disableDatepicker( target );
  2594. } else {
  2595. this._enableDatepicker( target );
  2596. }
  2597. }
  2598. this._attachments( $( target ), inst );
  2599. this._autoSize( inst );
  2600. this._setDate( inst, date );
  2601. this._updateAlternate( inst );
  2602. this._updateDatepicker( inst );
  2603. }
  2604. },
  2605. // Change method deprecated
  2606. _changeDatepicker: function( target, name, value ) {
  2607. this._optionDatepicker( target, name, value );
  2608. },
  2609. /* Redraw the date picker attached to an input field or division.
  2610. * @param target element - the target input field or division or span
  2611. */
  2612. _refreshDatepicker: function( target ) {
  2613. var inst = this._getInst( target );
  2614. if ( inst ) {
  2615. this._updateDatepicker( inst );
  2616. }
  2617. },
  2618. /* Set the dates for a jQuery selection.
  2619. * @param target element - the target input field or division or span
  2620. * @param date Date - the new date
  2621. */
  2622. _setDateDatepicker: function( target, date ) {
  2623. var inst = this._getInst( target );
  2624. if ( inst ) {
  2625. this._setDate( inst, date );
  2626. this._updateDatepicker( inst );
  2627. this._updateAlternate( inst );
  2628. }
  2629. },
  2630. /* Get the date(s) for the first entry in a jQuery selection.
  2631. * @param target element - the target input field or division or span
  2632. * @param noDefault boolean - true if no default date is to be used
  2633. * @return Date - the current date
  2634. */
  2635. _getDateDatepicker: function( target, noDefault ) {
  2636. var inst = this._getInst( target );
  2637. if ( inst && !inst.inline ) {
  2638. this._setDateFromField( inst, noDefault );
  2639. }
  2640. return ( inst ? this._getDate( inst ) : null );
  2641. },
  2642. /* Handle keystrokes. */
  2643. _doKeyDown: function( event ) {
  2644. var onSelect, dateStr, sel,
  2645. inst = $.datepicker._getInst( event.target ),
  2646. handled = true,
  2647. isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
  2648. inst._keyEvent = true;
  2649. if ( $.datepicker._datepickerShowing ) {
  2650. switch ( event.keyCode ) {
  2651. case 9: $.datepicker._hideDatepicker();
  2652. handled = false;
  2653. break; // hide on tab out
  2654. case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
  2655. $.datepicker._currentClass + ")", inst.dpDiv );
  2656. if ( sel[ 0 ] ) {
  2657. $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
  2658. }
  2659. onSelect = $.datepicker._get( inst, "onSelect" );
  2660. if ( onSelect ) {
  2661. dateStr = $.datepicker._formatDate( inst );
  2662. // Trigger custom callback
  2663. onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
  2664. } else {
  2665. $.datepicker._hideDatepicker();
  2666. }
  2667. return false; // don't submit the form
  2668. case 27: $.datepicker._hideDatepicker();
  2669. break; // hide on escape
  2670. case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  2671. -$.datepicker._get( inst, "stepBigMonths" ) :
  2672. -$.datepicker._get( inst, "stepMonths" ) ), "M" );
  2673. break; // previous month/year on page up/+ ctrl
  2674. case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  2675. +$.datepicker._get( inst, "stepBigMonths" ) :
  2676. +$.datepicker._get( inst, "stepMonths" ) ), "M" );
  2677. break; // next month/year on page down/+ ctrl
  2678. case 35: if ( event.ctrlKey || event.metaKey ) {
  2679. $.datepicker._clearDate( event.target );
  2680. }
  2681. handled = event.ctrlKey || event.metaKey;
  2682. break; // clear on ctrl or command +end
  2683. case 36: if ( event.ctrlKey || event.metaKey ) {
  2684. $.datepicker._gotoToday( event.target );
  2685. }
  2686. handled = event.ctrlKey || event.metaKey;
  2687. break; // current on ctrl or command +home
  2688. case 37: if ( event.ctrlKey || event.metaKey ) {
  2689. $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
  2690. }
  2691. handled = event.ctrlKey || event.metaKey;
  2692. // -1 day on ctrl or command +left
  2693. if ( event.originalEvent.altKey ) {
  2694. $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  2695. -$.datepicker._get( inst, "stepBigMonths" ) :
  2696. -$.datepicker._get( inst, "stepMonths" ) ), "M" );
  2697. }
  2698. // next month/year on alt +left on Mac
  2699. break;
  2700. case 38: if ( event.ctrlKey || event.metaKey ) {
  2701. $.datepicker._adjustDate( event.target, -7, "D" );
  2702. }
  2703. handled = event.ctrlKey || event.metaKey;
  2704. break; // -1 week on ctrl or command +up
  2705. case 39: if ( event.ctrlKey || event.metaKey ) {
  2706. $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
  2707. }
  2708. handled = event.ctrlKey || event.metaKey;
  2709. // +1 day on ctrl or command +right
  2710. if ( event.originalEvent.altKey ) {
  2711. $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  2712. +$.datepicker._get( inst, "stepBigMonths" ) :
  2713. +$.datepicker._get( inst, "stepMonths" ) ), "M" );
  2714. }
  2715. // next month/year on alt +right
  2716. break;
  2717. case 40: if ( event.ctrlKey || event.metaKey ) {
  2718. $.datepicker._adjustDate( event.target, +7, "D" );
  2719. }
  2720. handled = event.ctrlKey || event.metaKey;
  2721. break; // +1 week on ctrl or command +down
  2722. default: handled = false;
  2723. }
  2724. } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
  2725. $.datepicker._showDatepicker( this );
  2726. } else {
  2727. handled = false;
  2728. }
  2729. if ( handled ) {
  2730. event.preventDefault();
  2731. event.stopPropagation();
  2732. }
  2733. },
  2734. /* Filter entered characters - based on date format. */
  2735. _doKeyPress: function( event ) {
  2736. var chars, chr,
  2737. inst = $.datepicker._getInst( event.target );
  2738. if ( $.datepicker._get( inst, "constrainInput" ) ) {
  2739. chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
  2740. chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
  2741. return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
  2742. }
  2743. },
  2744. /* Synchronise manual entry and field/alternate field. */
  2745. _doKeyUp: function( event ) {
  2746. var date,
  2747. inst = $.datepicker._getInst( event.target );
  2748. if ( inst.input.val() !== inst.lastVal ) {
  2749. try {
  2750. date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
  2751. ( inst.input ? inst.input.val() : null ),
  2752. $.datepicker._getFormatConfig( inst ) );
  2753. if ( date ) { // only if valid
  2754. $.datepicker._setDateFromField( inst );
  2755. $.datepicker._updateAlternate( inst );
  2756. $.datepicker._updateDatepicker( inst );
  2757. }
  2758. }
  2759. catch ( err ) {
  2760. }
  2761. }
  2762. return true;
  2763. },
  2764. /* Pop-up the date picker for a given input field.
  2765. * If false returned from beforeShow event handler do not show.
  2766. * @param input element - the input field attached to the date picker or
  2767. * event - if triggered by focus
  2768. */
  2769. _showDatepicker: function( input ) {
  2770. input = input.target || input;
  2771. if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
  2772. input = $( "input", input.parentNode )[ 0 ];
  2773. }
  2774. if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
  2775. return;
  2776. }
  2777. var inst, beforeShow, beforeShowSettings, isFixed,
  2778. offset, showAnim, duration;
  2779. inst = $.datepicker._getInst( input );
  2780. if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
  2781. $.datepicker._curInst.dpDiv.stop( true, true );
  2782. if ( inst && $.datepicker._datepickerShowing ) {
  2783. $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
  2784. }
  2785. }
  2786. beforeShow = $.datepicker._get( inst, "beforeShow" );
  2787. beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
  2788. if ( beforeShowSettings === false ) {
  2789. return;
  2790. }
  2791. datepicker_extendRemove( inst.settings, beforeShowSettings );
  2792. inst.lastVal = null;
  2793. $.datepicker._lastInput = input;
  2794. $.datepicker._setDateFromField( inst );
  2795. if ( $.datepicker._inDialog ) { // hide cursor
  2796. input.value = "";
  2797. }
  2798. if ( !$.datepicker._pos ) { // position below input
  2799. $.datepicker._pos = $.datepicker._findPos( input );
  2800. $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
  2801. }
  2802. isFixed = false;
  2803. $( input ).parents().each( function() {
  2804. isFixed |= $( this ).css( "position" ) === "fixed";
  2805. return !isFixed;
  2806. } );
  2807. offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
  2808. $.datepicker._pos = null;
  2809. //to avoid flashes on Firefox
  2810. inst.dpDiv.empty();
  2811. // determine sizing offscreen
  2812. inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
  2813. $.datepicker._updateDatepicker( inst );
  2814. // fix width for dynamic number of date pickers
  2815. // and adjust position before showing
  2816. offset = $.datepicker._checkOffset( inst, offset, isFixed );
  2817. inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
  2818. "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
  2819. left: offset.left + "px", top: offset.top + "px" } );
  2820. if ( !inst.inline ) {
  2821. showAnim = $.datepicker._get( inst, "showAnim" );
  2822. duration = $.datepicker._get( inst, "duration" );
  2823. inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
  2824. $.datepicker._datepickerShowing = true;
  2825. if ( $.effects && $.effects.effect[ showAnim ] ) {
  2826. inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
  2827. } else {
  2828. inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
  2829. }
  2830. if ( $.datepicker._shouldFocusInput( inst ) ) {
  2831. inst.input.trigger( "focus" );
  2832. }
  2833. $.datepicker._curInst = inst;
  2834. }
  2835. },
  2836. /* Generate the date picker content. */
  2837. _updateDatepicker: function( inst ) {
  2838. this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
  2839. datepicker_instActive = inst; // for delegate hover events
  2840. inst.dpDiv.empty().append( this._generateHTML( inst ) );
  2841. this._attachHandlers( inst );
  2842. var origyearshtml,
  2843. numMonths = this._getNumberOfMonths( inst ),
  2844. cols = numMonths[ 1 ],
  2845. width = 17,
  2846. activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
  2847. if ( activeCell.length > 0 ) {
  2848. datepicker_handleMouseover.apply( activeCell.get( 0 ) );
  2849. }
  2850. inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
  2851. if ( cols > 1 ) {
  2852. inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
  2853. }
  2854. inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
  2855. "Class" ]( "ui-datepicker-multi" );
  2856. inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
  2857. "Class" ]( "ui-datepicker-rtl" );
  2858. if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
  2859. inst.input.trigger( "focus" );
  2860. }
  2861. // Deffered render of the years select (to avoid flashes on Firefox)
  2862. if ( inst.yearshtml ) {
  2863. origyearshtml = inst.yearshtml;
  2864. setTimeout( function() {
  2865. //assure that inst.yearshtml didn't change.
  2866. if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
  2867. inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
  2868. }
  2869. origyearshtml = inst.yearshtml = null;
  2870. }, 0 );
  2871. }
  2872. },
  2873. // #6694 - don't focus the input if it's already focused
  2874. // this breaks the change event in IE
  2875. // Support: IE and jQuery <1.9
  2876. _shouldFocusInput: function( inst ) {
  2877. return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
  2878. },
  2879. /* Check positioning to remain on screen. */
  2880. _checkOffset: function( inst, offset, isFixed ) {
  2881. var dpWidth = inst.dpDiv.outerWidth(),
  2882. dpHeight = inst.dpDiv.outerHeight(),
  2883. inputWidth = inst.input ? inst.input.outerWidth() : 0,
  2884. inputHeight = inst.input ? inst.input.outerHeight() : 0,
  2885. viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
  2886. viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
  2887. offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
  2888. offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
  2889. offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
  2890. // Now check if datepicker is showing outside window viewport - move to a better place if so.
  2891. offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
  2892. Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
  2893. offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
  2894. Math.abs( dpHeight + inputHeight ) : 0 );
  2895. return offset;
  2896. },
  2897. /* Find an object's position on the screen. */
  2898. _findPos: function( obj ) {
  2899. var position,
  2900. inst = this._getInst( obj ),
  2901. isRTL = this._get( inst, "isRTL" );
  2902. while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
  2903. obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
  2904. }
  2905. position = $( obj ).offset();
  2906. return [ position.left, position.top ];
  2907. },
  2908. /* Hide the date picker from view.
  2909. * @param input element - the input field attached to the date picker
  2910. */
  2911. _hideDatepicker: function( input ) {
  2912. var showAnim, duration, postProcess, onClose,
  2913. inst = this._curInst;
  2914. if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
  2915. return;
  2916. }
  2917. if ( this._datepickerShowing ) {
  2918. showAnim = this._get( inst, "showAnim" );
  2919. duration = this._get( inst, "duration" );
  2920. postProcess = function() {
  2921. $.datepicker._tidyDialog( inst );
  2922. };
  2923. // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
  2924. if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
  2925. inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
  2926. } else {
  2927. inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
  2928. ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
  2929. }
  2930. if ( !showAnim ) {
  2931. postProcess();
  2932. }
  2933. this._datepickerShowing = false;
  2934. onClose = this._get( inst, "onClose" );
  2935. if ( onClose ) {
  2936. onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
  2937. }
  2938. this._lastInput = null;
  2939. if ( this._inDialog ) {
  2940. this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
  2941. if ( $.blockUI ) {
  2942. $.unblockUI();
  2943. $( "body" ).append( this.dpDiv );
  2944. }
  2945. }
  2946. this._inDialog = false;
  2947. }
  2948. },
  2949. /* Tidy up after a dialog display. */
  2950. _tidyDialog: function( inst ) {
  2951. inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
  2952. },
  2953. /* Close date picker if clicked elsewhere. */
  2954. _checkExternalClick: function( event ) {
  2955. if ( !$.datepicker._curInst ) {
  2956. return;
  2957. }
  2958. var $target = $( event.target ),
  2959. inst = $.datepicker._getInst( $target[ 0 ] );
  2960. if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
  2961. $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
  2962. !$target.hasClass( $.datepicker.markerClassName ) &&
  2963. !$target.closest( "." + $.datepicker._triggerClass ).length &&
  2964. $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
  2965. ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
  2966. $.datepicker._hideDatepicker();
  2967. }
  2968. },
  2969. /* Adjust one of the date sub-fields. */
  2970. _adjustDate: function( id, offset, period ) {
  2971. var target = $( id ),
  2972. inst = this._getInst( target[ 0 ] );
  2973. if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
  2974. return;
  2975. }
  2976. this._adjustInstDate( inst, offset +
  2977. ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
  2978. period );
  2979. this._updateDatepicker( inst );
  2980. },
  2981. /* Action for current link. */
  2982. _gotoToday: function( id ) {
  2983. var date,
  2984. target = $( id ),
  2985. inst = this._getInst( target[ 0 ] );
  2986. if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
  2987. inst.selectedDay = inst.currentDay;
  2988. inst.drawMonth = inst.selectedMonth = inst.currentMonth;
  2989. inst.drawYear = inst.selectedYear = inst.currentYear;
  2990. } else {
  2991. date = new Date();
  2992. inst.selectedDay = date.getDate();
  2993. inst.drawMonth = inst.selectedMonth = date.getMonth();
  2994. inst.drawYear = inst.selectedYear = date.getFullYear();
  2995. }
  2996. this._notifyChange( inst );
  2997. this._adjustDate( target );
  2998. },
  2999. /* Action for selecting a new month/year. */
  3000. _selectMonthYear: function( id, select, period ) {
  3001. var target = $( id ),
  3002. inst = this._getInst( target[ 0 ] );
  3003. inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
  3004. inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
  3005. parseInt( select.options[ select.selectedIndex ].value, 10 );
  3006. this._notifyChange( inst );
  3007. this._adjustDate( target );
  3008. },
  3009. /* Action for selecting a day. */
  3010. _selectDay: function( id, month, year, td ) {
  3011. var inst,
  3012. target = $( id );
  3013. if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
  3014. return;
  3015. }
  3016. inst = this._getInst( target[ 0 ] );
  3017. inst.selectedDay = inst.currentDay = $( "a", td ).html();
  3018. inst.selectedMonth = inst.currentMonth = month;
  3019. inst.selectedYear = inst.currentYear = year;
  3020. this._selectDate( id, this._formatDate( inst,
  3021. inst.currentDay, inst.currentMonth, inst.currentYear ) );
  3022. },
  3023. /* Erase the input field and hide the date picker. */
  3024. _clearDate: function( id ) {
  3025. var target = $( id );
  3026. this._selectDate( target, "" );
  3027. },
  3028. /* Update the input field with the selected date. */
  3029. _selectDate: function( id, dateStr ) {
  3030. var onSelect,
  3031. target = $( id ),
  3032. inst = this._getInst( target[ 0 ] );
  3033. dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
  3034. if ( inst.input ) {
  3035. inst.input.val( dateStr );
  3036. }
  3037. this._updateAlternate( inst );
  3038. onSelect = this._get( inst, "onSelect" );
  3039. if ( onSelect ) {
  3040. onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
  3041. } else if ( inst.input ) {
  3042. inst.input.trigger( "change" ); // fire the change event
  3043. }
  3044. if ( inst.inline ) {
  3045. this._updateDatepicker( inst );
  3046. } else {
  3047. this._hideDatepicker();
  3048. this._lastInput = inst.input[ 0 ];
  3049. if ( typeof( inst.input[ 0 ] ) !== "object" ) {
  3050. inst.input.trigger( "focus" ); // restore focus
  3051. }
  3052. this._lastInput = null;
  3053. }
  3054. },
  3055. /* Update any alternate field to synchronise with the main field. */
  3056. _updateAlternate: function( inst ) {
  3057. var altFormat, date, dateStr,
  3058. altField = this._get( inst, "altField" );
  3059. if ( altField ) { // update alternate field too
  3060. altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
  3061. date = this._getDate( inst );
  3062. dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
  3063. $( altField ).val( dateStr );
  3064. }
  3065. },
  3066. /* Set as beforeShowDay function to prevent selection of weekends.
  3067. * @param date Date - the date to customise
  3068. * @return [boolean, string] - is this date selectable?, what is its CSS class?
  3069. */
  3070. noWeekends: function( date ) {
  3071. var day = date.getDay();
  3072. return [ ( day > 0 && day < 6 ), "" ];
  3073. },
  3074. /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
  3075. * @param date Date - the date to get the week for
  3076. * @return number - the number of the week within the year that contains this date
  3077. */
  3078. iso8601Week: function( date ) {
  3079. var time,
  3080. checkDate = new Date( date.getTime() );
  3081. // Find Thursday of this week starting on Monday
  3082. checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
  3083. time = checkDate.getTime();
  3084. checkDate.setMonth( 0 ); // Compare with Jan 1
  3085. checkDate.setDate( 1 );
  3086. return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
  3087. },
  3088. /* Parse a string value into a date object.
  3089. * See formatDate below for the possible formats.
  3090. *
  3091. * @param format string - the expected format of the date
  3092. * @param value string - the date in the above format
  3093. * @param settings Object - attributes include:
  3094. * shortYearCutoff number - the cutoff year for determining the century (optional)
  3095. * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
  3096. * dayNames string[7] - names of the days from Sunday (optional)
  3097. * monthNamesShort string[12] - abbreviated names of the months (optional)
  3098. * monthNames string[12] - names of the months (optional)
  3099. * @return Date - the extracted date value or null if value is blank
  3100. */
  3101. parseDate: function( format, value, settings ) {
  3102. if ( format == null || value == null ) {
  3103. throw "Invalid arguments";
  3104. }
  3105. value = ( typeof value === "object" ? value.toString() : value + "" );
  3106. if ( value === "" ) {
  3107. return null;
  3108. }
  3109. var iFormat, dim, extra,
  3110. iValue = 0,
  3111. shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
  3112. shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
  3113. new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
  3114. dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
  3115. dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
  3116. monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
  3117. monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
  3118. year = -1,
  3119. month = -1,
  3120. day = -1,
  3121. doy = -1,
  3122. literal = false,
  3123. date,
  3124. // Check whether a format character is doubled
  3125. lookAhead = function( match ) {
  3126. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  3127. if ( matches ) {
  3128. iFormat++;
  3129. }
  3130. return matches;
  3131. },
  3132. // Extract a number from the string value
  3133. getNumber = function( match ) {
  3134. var isDoubled = lookAhead( match ),
  3135. size = ( match === "@" ? 14 : ( match === "!" ? 20 :
  3136. ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
  3137. minSize = ( match === "y" ? size : 1 ),
  3138. digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
  3139. num = value.substring( iValue ).match( digits );
  3140. if ( !num ) {
  3141. throw "Missing number at position " + iValue;
  3142. }
  3143. iValue += num[ 0 ].length;
  3144. return parseInt( num[ 0 ], 10 );
  3145. },
  3146. // Extract a name from the string value and convert to an index
  3147. getName = function( match, shortNames, longNames ) {
  3148. var index = -1,
  3149. names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
  3150. return [ [ k, v ] ];
  3151. } ).sort( function( a, b ) {
  3152. return -( a[ 1 ].length - b[ 1 ].length );
  3153. } );
  3154. $.each( names, function( i, pair ) {
  3155. var name = pair[ 1 ];
  3156. if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
  3157. index = pair[ 0 ];
  3158. iValue += name.length;
  3159. return false;
  3160. }
  3161. } );
  3162. if ( index !== -1 ) {
  3163. return index + 1;
  3164. } else {
  3165. throw "Unknown name at position " + iValue;
  3166. }
  3167. },
  3168. // Confirm that a literal character matches the string value
  3169. checkLiteral = function() {
  3170. if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
  3171. throw "Unexpected literal at position " + iValue;
  3172. }
  3173. iValue++;
  3174. };
  3175. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  3176. if ( literal ) {
  3177. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  3178. literal = false;
  3179. } else {
  3180. checkLiteral();
  3181. }
  3182. } else {
  3183. switch ( format.charAt( iFormat ) ) {
  3184. case "d":
  3185. day = getNumber( "d" );
  3186. break;
  3187. case "D":
  3188. getName( "D", dayNamesShort, dayNames );
  3189. break;
  3190. case "o":
  3191. doy = getNumber( "o" );
  3192. break;
  3193. case "m":
  3194. month = getNumber( "m" );
  3195. break;
  3196. case "M":
  3197. month = getName( "M", monthNamesShort, monthNames );
  3198. break;
  3199. case "y":
  3200. year = getNumber( "y" );
  3201. break;
  3202. case "@":
  3203. date = new Date( getNumber( "@" ) );
  3204. year = date.getFullYear();
  3205. month = date.getMonth() + 1;
  3206. day = date.getDate();
  3207. break;
  3208. case "!":
  3209. date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
  3210. year = date.getFullYear();
  3211. month = date.getMonth() + 1;
  3212. day = date.getDate();
  3213. break;
  3214. case "'":
  3215. if ( lookAhead( "'" ) ) {
  3216. checkLiteral();
  3217. } else {
  3218. literal = true;
  3219. }
  3220. break;
  3221. default:
  3222. checkLiteral();
  3223. }
  3224. }
  3225. }
  3226. if ( iValue < value.length ) {
  3227. extra = value.substr( iValue );
  3228. if ( !/^\s+/.test( extra ) ) {
  3229. throw "Extra/unparsed characters found in date: " + extra;
  3230. }
  3231. }
  3232. if ( year === -1 ) {
  3233. year = new Date().getFullYear();
  3234. } else if ( year < 100 ) {
  3235. year += new Date().getFullYear() - new Date().getFullYear() % 100 +
  3236. ( year <= shortYearCutoff ? 0 : -100 );
  3237. }
  3238. if ( doy > -1 ) {
  3239. month = 1;
  3240. day = doy;
  3241. do {
  3242. dim = this._getDaysInMonth( year, month - 1 );
  3243. if ( day <= dim ) {
  3244. break;
  3245. }
  3246. month++;
  3247. day -= dim;
  3248. } while ( true );
  3249. }
  3250. date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
  3251. if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
  3252. throw "Invalid date"; // E.g. 31/02/00
  3253. }
  3254. return date;
  3255. },
  3256. /* Standard date formats. */
  3257. ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
  3258. COOKIE: "D, dd M yy",
  3259. ISO_8601: "yy-mm-dd",
  3260. RFC_822: "D, d M y",
  3261. RFC_850: "DD, dd-M-y",
  3262. RFC_1036: "D, d M y",
  3263. RFC_1123: "D, d M yy",
  3264. RFC_2822: "D, d M yy",
  3265. RSS: "D, d M y", // RFC 822
  3266. TICKS: "!",
  3267. TIMESTAMP: "@",
  3268. W3C: "yy-mm-dd", // ISO 8601
  3269. _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
  3270. Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
  3271. /* Format a date object into a string value.
  3272. * The format can be combinations of the following:
  3273. * d - day of month (no leading zero)
  3274. * dd - day of month (two digit)
  3275. * o - day of year (no leading zeros)
  3276. * oo - day of year (three digit)
  3277. * D - day name short
  3278. * DD - day name long
  3279. * m - month of year (no leading zero)
  3280. * mm - month of year (two digit)
  3281. * M - month name short
  3282. * MM - month name long
  3283. * y - year (two digit)
  3284. * yy - year (four digit)
  3285. * @ - Unix timestamp (ms since 01/01/1970)
  3286. * ! - Windows ticks (100ns since 01/01/0001)
  3287. * "..." - literal text
  3288. * '' - single quote
  3289. *
  3290. * @param format string - the desired format of the date
  3291. * @param date Date - the date value to format
  3292. * @param settings Object - attributes include:
  3293. * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
  3294. * dayNames string[7] - names of the days from Sunday (optional)
  3295. * monthNamesShort string[12] - abbreviated names of the months (optional)
  3296. * monthNames string[12] - names of the months (optional)
  3297. * @return string - the date in the above format
  3298. */
  3299. formatDate: function( format, date, settings ) {
  3300. if ( !date ) {
  3301. return "";
  3302. }
  3303. var iFormat,
  3304. dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
  3305. dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
  3306. monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
  3307. monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
  3308. // Check whether a format character is doubled
  3309. lookAhead = function( match ) {
  3310. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  3311. if ( matches ) {
  3312. iFormat++;
  3313. }
  3314. return matches;
  3315. },
  3316. // Format a number, with leading zero if necessary
  3317. formatNumber = function( match, value, len ) {
  3318. var num = "" + value;
  3319. if ( lookAhead( match ) ) {
  3320. while ( num.length < len ) {
  3321. num = "0" + num;
  3322. }
  3323. }
  3324. return num;
  3325. },
  3326. // Format a name, short or long as requested
  3327. formatName = function( match, value, shortNames, longNames ) {
  3328. return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
  3329. },
  3330. output = "",
  3331. literal = false;
  3332. if ( date ) {
  3333. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  3334. if ( literal ) {
  3335. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  3336. literal = false;
  3337. } else {
  3338. output += format.charAt( iFormat );
  3339. }
  3340. } else {
  3341. switch ( format.charAt( iFormat ) ) {
  3342. case "d":
  3343. output += formatNumber( "d", date.getDate(), 2 );
  3344. break;
  3345. case "D":
  3346. output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
  3347. break;
  3348. case "o":
  3349. output += formatNumber( "o",
  3350. Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
  3351. break;
  3352. case "m":
  3353. output += formatNumber( "m", date.getMonth() + 1, 2 );
  3354. break;
  3355. case "M":
  3356. output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
  3357. break;
  3358. case "y":
  3359. output += ( lookAhead( "y" ) ? date.getFullYear() :
  3360. ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
  3361. break;
  3362. case "@":
  3363. output += date.getTime();
  3364. break;
  3365. case "!":
  3366. output += date.getTime() * 10000 + this._ticksTo1970;
  3367. break;
  3368. case "'":
  3369. if ( lookAhead( "'" ) ) {
  3370. output += "'";
  3371. } else {
  3372. literal = true;
  3373. }
  3374. break;
  3375. default:
  3376. output += format.charAt( iFormat );
  3377. }
  3378. }
  3379. }
  3380. }
  3381. return output;
  3382. },
  3383. /* Extract all possible characters from the date format. */
  3384. _possibleChars: function( format ) {
  3385. var iFormat,
  3386. chars = "",
  3387. literal = false,
  3388. // Check whether a format character is doubled
  3389. lookAhead = function( match ) {
  3390. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  3391. if ( matches ) {
  3392. iFormat++;
  3393. }
  3394. return matches;
  3395. };
  3396. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  3397. if ( literal ) {
  3398. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  3399. literal = false;
  3400. } else {
  3401. chars += format.charAt( iFormat );
  3402. }
  3403. } else {
  3404. switch ( format.charAt( iFormat ) ) {
  3405. case "d": case "m": case "y": case "@":
  3406. chars += "0123456789";
  3407. break;
  3408. case "D": case "M":
  3409. return null; // Accept anything
  3410. case "'":
  3411. if ( lookAhead( "'" ) ) {
  3412. chars += "'";
  3413. } else {
  3414. literal = true;
  3415. }
  3416. break;
  3417. default:
  3418. chars += format.charAt( iFormat );
  3419. }
  3420. }
  3421. }
  3422. return chars;
  3423. },
  3424. /* Get a setting value, defaulting if necessary. */
  3425. _get: function( inst, name ) {
  3426. return inst.settings[ name ] !== undefined ?
  3427. inst.settings[ name ] : this._defaults[ name ];
  3428. },
  3429. /* Parse existing date and initialise date picker. */
  3430. _setDateFromField: function( inst, noDefault ) {
  3431. if ( inst.input.val() === inst.lastVal ) {
  3432. return;
  3433. }
  3434. var dateFormat = this._get( inst, "dateFormat" ),
  3435. dates = inst.lastVal = inst.input ? inst.input.val() : null,
  3436. defaultDate = this._getDefaultDate( inst ),
  3437. date = defaultDate,
  3438. settings = this._getFormatConfig( inst );
  3439. try {
  3440. date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
  3441. } catch ( event ) {
  3442. dates = ( noDefault ? "" : dates );
  3443. }
  3444. inst.selectedDay = date.getDate();
  3445. inst.drawMonth = inst.selectedMonth = date.getMonth();
  3446. inst.drawYear = inst.selectedYear = date.getFullYear();
  3447. inst.currentDay = ( dates ? date.getDate() : 0 );
  3448. inst.currentMonth = ( dates ? date.getMonth() : 0 );
  3449. inst.currentYear = ( dates ? date.getFullYear() : 0 );
  3450. this._adjustInstDate( inst );
  3451. },
  3452. /* Retrieve the default date shown on opening. */
  3453. _getDefaultDate: function( inst ) {
  3454. return this._restrictMinMax( inst,
  3455. this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
  3456. },
  3457. /* A date may be specified as an exact value or a relative one. */
  3458. _determineDate: function( inst, date, defaultDate ) {
  3459. var offsetNumeric = function( offset ) {
  3460. var date = new Date();
  3461. date.setDate( date.getDate() + offset );
  3462. return date;
  3463. },
  3464. offsetString = function( offset ) {
  3465. try {
  3466. return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
  3467. offset, $.datepicker._getFormatConfig( inst ) );
  3468. }
  3469. catch ( e ) {
  3470. // Ignore
  3471. }
  3472. var date = ( offset.toLowerCase().match( /^c/ ) ?
  3473. $.datepicker._getDate( inst ) : null ) || new Date(),
  3474. year = date.getFullYear(),
  3475. month = date.getMonth(),
  3476. day = date.getDate(),
  3477. pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
  3478. matches = pattern.exec( offset );
  3479. while ( matches ) {
  3480. switch ( matches[ 2 ] || "d" ) {
  3481. case "d" : case "D" :
  3482. day += parseInt( matches[ 1 ], 10 ); break;
  3483. case "w" : case "W" :
  3484. day += parseInt( matches[ 1 ], 10 ) * 7; break;
  3485. case "m" : case "M" :
  3486. month += parseInt( matches[ 1 ], 10 );
  3487. day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
  3488. break;
  3489. case "y": case "Y" :
  3490. year += parseInt( matches[ 1 ], 10 );
  3491. day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
  3492. break;
  3493. }
  3494. matches = pattern.exec( offset );
  3495. }
  3496. return new Date( year, month, day );
  3497. },
  3498. newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
  3499. ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
  3500. newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
  3501. if ( newDate ) {
  3502. newDate.setHours( 0 );
  3503. newDate.setMinutes( 0 );
  3504. newDate.setSeconds( 0 );
  3505. newDate.setMilliseconds( 0 );
  3506. }
  3507. return this._daylightSavingAdjust( newDate );
  3508. },
  3509. /* Handle switch to/from daylight saving.
  3510. * Hours may be non-zero on daylight saving cut-over:
  3511. * > 12 when midnight changeover, but then cannot generate
  3512. * midnight datetime, so jump to 1AM, otherwise reset.
  3513. * @param date (Date) the date to check
  3514. * @return (Date) the corrected date
  3515. */
  3516. _daylightSavingAdjust: function( date ) {
  3517. if ( !date ) {
  3518. return null;
  3519. }
  3520. date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
  3521. return date;
  3522. },
  3523. /* Set the date(s) directly. */
  3524. _setDate: function( inst, date, noChange ) {
  3525. var clear = !date,
  3526. origMonth = inst.selectedMonth,
  3527. origYear = inst.selectedYear,
  3528. newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
  3529. inst.selectedDay = inst.currentDay = newDate.getDate();
  3530. inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
  3531. inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
  3532. if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
  3533. this._notifyChange( inst );
  3534. }
  3535. this._adjustInstDate( inst );
  3536. if ( inst.input ) {
  3537. inst.input.val( clear ? "" : this._formatDate( inst ) );
  3538. }
  3539. },
  3540. /* Retrieve the date(s) directly. */
  3541. _getDate: function( inst ) {
  3542. var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
  3543. this._daylightSavingAdjust( new Date(
  3544. inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
  3545. return startDate;
  3546. },
  3547. /* Attach the onxxx handlers. These are declared statically so
  3548. * they work with static code transformers like Caja.
  3549. */
  3550. _attachHandlers: function( inst ) {
  3551. var stepMonths = this._get( inst, "stepMonths" ),
  3552. id = "#" + inst.id.replace( /\\\\/g, "\\" );
  3553. inst.dpDiv.find( "[data-handler]" ).map( function() {
  3554. var handler = {
  3555. prev: function() {
  3556. $.datepicker._adjustDate( id, -stepMonths, "M" );
  3557. },
  3558. next: function() {
  3559. $.datepicker._adjustDate( id, +stepMonths, "M" );
  3560. },
  3561. hide: function() {
  3562. $.datepicker._hideDatepicker();
  3563. },
  3564. today: function() {
  3565. $.datepicker._gotoToday( id );
  3566. },
  3567. selectDay: function() {
  3568. $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
  3569. return false;
  3570. },
  3571. selectMonth: function() {
  3572. $.datepicker._selectMonthYear( id, this, "M" );
  3573. return false;
  3574. },
  3575. selectYear: function() {
  3576. $.datepicker._selectMonthYear( id, this, "Y" );
  3577. return false;
  3578. }
  3579. };
  3580. $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
  3581. } );
  3582. },
  3583. /* Generate the HTML for the current state of the date picker. */
  3584. _generateHTML: function( inst ) {
  3585. var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
  3586. controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
  3587. monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
  3588. selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
  3589. cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
  3590. printDate, dRow, tbody, daySettings, otherMonth, unselectable,
  3591. tempDate = new Date(),
  3592. today = this._daylightSavingAdjust(
  3593. new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
  3594. isRTL = this._get( inst, "isRTL" ),
  3595. showButtonPanel = this._get( inst, "showButtonPanel" ),
  3596. hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
  3597. navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
  3598. numMonths = this._getNumberOfMonths( inst ),
  3599. showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
  3600. stepMonths = this._get( inst, "stepMonths" ),
  3601. isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
  3602. currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
  3603. new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
  3604. minDate = this._getMinMaxDate( inst, "min" ),
  3605. maxDate = this._getMinMaxDate( inst, "max" ),
  3606. drawMonth = inst.drawMonth - showCurrentAtPos,
  3607. drawYear = inst.drawYear;
  3608. if ( drawMonth < 0 ) {
  3609. drawMonth += 12;
  3610. drawYear--;
  3611. }
  3612. if ( maxDate ) {
  3613. maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
  3614. maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
  3615. maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
  3616. while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
  3617. drawMonth--;
  3618. if ( drawMonth < 0 ) {
  3619. drawMonth = 11;
  3620. drawYear--;
  3621. }
  3622. }
  3623. }
  3624. inst.drawMonth = drawMonth;
  3625. inst.drawYear = drawYear;
  3626. prevText = this._get( inst, "prevText" );
  3627. prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
  3628. this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
  3629. this._getFormatConfig( inst ) ) );
  3630. prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
  3631. "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
  3632. " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
  3633. ( 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>" ) );
  3634. nextText = this._get( inst, "nextText" );
  3635. nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
  3636. this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
  3637. this._getFormatConfig( inst ) ) );
  3638. next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
  3639. "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
  3640. " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
  3641. ( 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>" ) );
  3642. currentText = this._get( inst, "currentText" );
  3643. gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
  3644. currentText = ( !navigationAsDateFormat ? currentText :
  3645. this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
  3646. 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'>" +
  3647. this._get( inst, "closeText" ) + "</button>" : "" );
  3648. buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
  3649. ( 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'" +
  3650. ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
  3651. firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
  3652. firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
  3653. showWeek = this._get( inst, "showWeek" );
  3654. dayNames = this._get( inst, "dayNames" );
  3655. dayNamesMin = this._get( inst, "dayNamesMin" );
  3656. monthNames = this._get( inst, "monthNames" );
  3657. monthNamesShort = this._get( inst, "monthNamesShort" );
  3658. beforeShowDay = this._get( inst, "beforeShowDay" );
  3659. showOtherMonths = this._get( inst, "showOtherMonths" );
  3660. selectOtherMonths = this._get( inst, "selectOtherMonths" );
  3661. defaultDate = this._getDefaultDate( inst );
  3662. html = "";
  3663. for ( row = 0; row < numMonths[ 0 ]; row++ ) {
  3664. group = "";
  3665. this.maxRows = 4;
  3666. for ( col = 0; col < numMonths[ 1 ]; col++ ) {
  3667. selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
  3668. cornerClass = " ui-corner-all";
  3669. calender = "";
  3670. if ( isMultiMonth ) {
  3671. calender += "<div class='ui-datepicker-group";
  3672. if ( numMonths[ 1 ] > 1 ) {
  3673. switch ( col ) {
  3674. case 0: calender += " ui-datepicker-group-first";
  3675. cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
  3676. case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
  3677. cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
  3678. default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
  3679. }
  3680. }
  3681. calender += "'>";
  3682. }
  3683. calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
  3684. ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
  3685. ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
  3686. this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
  3687. row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
  3688. "</div><table class='ui-datepicker-calendar'><thead>" +
  3689. "<tr>";
  3690. thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
  3691. for ( dow = 0; dow < 7; dow++ ) { // days of the week
  3692. day = ( dow + firstDay ) % 7;
  3693. thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
  3694. "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
  3695. }
  3696. calender += thead + "</tr></thead><tbody>";
  3697. daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
  3698. if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
  3699. inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
  3700. }
  3701. leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
  3702. curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
  3703. numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
  3704. this.maxRows = numRows;
  3705. printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
  3706. for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
  3707. calender += "<tr>";
  3708. tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
  3709. this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
  3710. for ( dow = 0; dow < 7; dow++ ) { // create date picker days
  3711. daySettings = ( beforeShowDay ?
  3712. beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
  3713. otherMonth = ( printDate.getMonth() !== drawMonth );
  3714. unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
  3715. ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
  3716. tbody += "<td class='" +
  3717. ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
  3718. ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
  3719. ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
  3720. ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
  3721. // or defaultDate is current printedDate and defaultDate is selectedDate
  3722. " " + this._dayOverClass : "" ) + // highlight selected day
  3723. ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
  3724. ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
  3725. ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
  3726. ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
  3727. ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
  3728. ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
  3729. ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
  3730. ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
  3731. ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
  3732. ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
  3733. ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
  3734. "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
  3735. printDate.setDate( printDate.getDate() + 1 );
  3736. printDate = this._daylightSavingAdjust( printDate );
  3737. }
  3738. calender += tbody + "</tr>";
  3739. }
  3740. drawMonth++;
  3741. if ( drawMonth > 11 ) {
  3742. drawMonth = 0;
  3743. drawYear++;
  3744. }
  3745. calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
  3746. ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
  3747. group += calender;
  3748. }
  3749. html += group;
  3750. }
  3751. html += buttonPanel;
  3752. inst._keyEvent = false;
  3753. return html;
  3754. },
  3755. /* Generate the month and year header. */
  3756. _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
  3757. secondary, monthNames, monthNamesShort ) {
  3758. var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
  3759. changeMonth = this._get( inst, "changeMonth" ),
  3760. changeYear = this._get( inst, "changeYear" ),
  3761. showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
  3762. html = "<div class='ui-datepicker-title'>",
  3763. monthHtml = "";
  3764. // Month selection
  3765. if ( secondary || !changeMonth ) {
  3766. monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
  3767. } else {
  3768. inMinYear = ( minDate && minDate.getFullYear() === drawYear );
  3769. inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
  3770. monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
  3771. for ( month = 0; month < 12; month++ ) {
  3772. if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
  3773. monthHtml += "<option value='" + month + "'" +
  3774. ( month === drawMonth ? " selected='selected'" : "" ) +
  3775. ">" + monthNamesShort[ month ] + "</option>";
  3776. }
  3777. }
  3778. monthHtml += "</select>";
  3779. }
  3780. if ( !showMonthAfterYear ) {
  3781. html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
  3782. }
  3783. // Year selection
  3784. if ( !inst.yearshtml ) {
  3785. inst.yearshtml = "";
  3786. if ( secondary || !changeYear ) {
  3787. html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
  3788. } else {
  3789. // determine range of years to display
  3790. years = this._get( inst, "yearRange" ).split( ":" );
  3791. thisYear = new Date().getFullYear();
  3792. determineYear = function( value ) {
  3793. var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
  3794. ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
  3795. parseInt( value, 10 ) ) );
  3796. return ( isNaN( year ) ? thisYear : year );
  3797. };
  3798. year = determineYear( years[ 0 ] );
  3799. endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
  3800. year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
  3801. endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
  3802. inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
  3803. for ( ; year <= endYear; year++ ) {
  3804. inst.yearshtml += "<option value='" + year + "'" +
  3805. ( year === drawYear ? " selected='selected'" : "" ) +
  3806. ">" + year + "</option>";
  3807. }
  3808. inst.yearshtml += "</select>";
  3809. html += inst.yearshtml;
  3810. inst.yearshtml = null;
  3811. }
  3812. }
  3813. html += this._get( inst, "yearSuffix" );
  3814. if ( showMonthAfterYear ) {
  3815. html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
  3816. }
  3817. html += "</div>"; // Close datepicker_header
  3818. return html;
  3819. },
  3820. /* Adjust one of the date sub-fields. */
  3821. _adjustInstDate: function( inst, offset, period ) {
  3822. var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
  3823. month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
  3824. day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
  3825. date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
  3826. inst.selectedDay = date.getDate();
  3827. inst.drawMonth = inst.selectedMonth = date.getMonth();
  3828. inst.drawYear = inst.selectedYear = date.getFullYear();
  3829. if ( period === "M" || period === "Y" ) {
  3830. this._notifyChange( inst );
  3831. }
  3832. },
  3833. /* Ensure a date is within any min/max bounds. */
  3834. _restrictMinMax: function( inst, date ) {
  3835. var minDate = this._getMinMaxDate( inst, "min" ),
  3836. maxDate = this._getMinMaxDate( inst, "max" ),
  3837. newDate = ( minDate && date < minDate ? minDate : date );
  3838. return ( maxDate && newDate > maxDate ? maxDate : newDate );
  3839. },
  3840. /* Notify change of month/year. */
  3841. _notifyChange: function( inst ) {
  3842. var onChange = this._get( inst, "onChangeMonthYear" );
  3843. if ( onChange ) {
  3844. onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
  3845. [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
  3846. }
  3847. },
  3848. /* Determine the number of months to show. */
  3849. _getNumberOfMonths: function( inst ) {
  3850. var numMonths = this._get( inst, "numberOfMonths" );
  3851. return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
  3852. },
  3853. /* Determine the current maximum date - ensure no time components are set. */
  3854. _getMinMaxDate: function( inst, minMax ) {
  3855. return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
  3856. },
  3857. /* Find the number of days in a given month. */
  3858. _getDaysInMonth: function( year, month ) {
  3859. return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
  3860. },
  3861. /* Find the day of the week of the first of a month. */
  3862. _getFirstDayOfMonth: function( year, month ) {
  3863. return new Date( year, month, 1 ).getDay();
  3864. },
  3865. /* Determines if we should allow a "next/prev" month display change. */
  3866. _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
  3867. var numMonths = this._getNumberOfMonths( inst ),
  3868. date = this._daylightSavingAdjust( new Date( curYear,
  3869. curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
  3870. if ( offset < 0 ) {
  3871. date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
  3872. }
  3873. return this._isInRange( inst, date );
  3874. },
  3875. /* Is the given date in the accepted range? */
  3876. _isInRange: function( inst, date ) {
  3877. var yearSplit, currentYear,
  3878. minDate = this._getMinMaxDate( inst, "min" ),
  3879. maxDate = this._getMinMaxDate( inst, "max" ),
  3880. minYear = null,
  3881. maxYear = null,
  3882. years = this._get( inst, "yearRange" );
  3883. if ( years ) {
  3884. yearSplit = years.split( ":" );
  3885. currentYear = new Date().getFullYear();
  3886. minYear = parseInt( yearSplit[ 0 ], 10 );
  3887. maxYear = parseInt( yearSplit[ 1 ], 10 );
  3888. if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
  3889. minYear += currentYear;
  3890. }
  3891. if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
  3892. maxYear += currentYear;
  3893. }
  3894. }
  3895. return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
  3896. ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
  3897. ( !minYear || date.getFullYear() >= minYear ) &&
  3898. ( !maxYear || date.getFullYear() <= maxYear ) );
  3899. },
  3900. /* Provide the configuration settings for formatting/parsing. */
  3901. _getFormatConfig: function( inst ) {
  3902. var shortYearCutoff = this._get( inst, "shortYearCutoff" );
  3903. shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
  3904. new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
  3905. return { shortYearCutoff: shortYearCutoff,
  3906. dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
  3907. monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
  3908. },
  3909. /* Format the given date for display. */
  3910. _formatDate: function( inst, day, month, year ) {
  3911. if ( !day ) {
  3912. inst.currentDay = inst.selectedDay;
  3913. inst.currentMonth = inst.selectedMonth;
  3914. inst.currentYear = inst.selectedYear;
  3915. }
  3916. var date = ( day ? ( typeof day === "object" ? day :
  3917. this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
  3918. this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
  3919. return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
  3920. }
  3921. } );
  3922. /*
  3923. * Bind hover events for datepicker elements.
  3924. * Done via delegate so the binding only occurs once in the lifetime of the parent div.
  3925. * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
  3926. */
  3927. function datepicker_bindHover( dpDiv ) {
  3928. var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
  3929. return dpDiv.on( "mouseout", selector, function() {
  3930. $( this ).removeClass( "ui-state-hover" );
  3931. if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
  3932. $( this ).removeClass( "ui-datepicker-prev-hover" );
  3933. }
  3934. if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
  3935. $( this ).removeClass( "ui-datepicker-next-hover" );
  3936. }
  3937. } )
  3938. .on( "mouseover", selector, datepicker_handleMouseover );
  3939. }
  3940. function datepicker_handleMouseover() {
  3941. if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
  3942. $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
  3943. $( this ).addClass( "ui-state-hover" );
  3944. if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
  3945. $( this ).addClass( "ui-datepicker-prev-hover" );
  3946. }
  3947. if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
  3948. $( this ).addClass( "ui-datepicker-next-hover" );
  3949. }
  3950. }
  3951. }
  3952. /* jQuery extend now ignores nulls! */
  3953. function datepicker_extendRemove( target, props ) {
  3954. $.extend( target, props );
  3955. for ( var name in props ) {
  3956. if ( props[ name ] == null ) {
  3957. target[ name ] = props[ name ];
  3958. }
  3959. }
  3960. return target;
  3961. }
  3962. /* Invoke the datepicker functionality.
  3963. @param options string - a command, optionally followed by additional parameters or
  3964. Object - settings for attaching new datepicker functionality
  3965. @return jQuery object */
  3966. $.fn.datepicker = function( options ) {
  3967. /* Verify an empty collection wasn't passed - Fixes #6976 */
  3968. if ( !this.length ) {
  3969. return this;
  3970. }
  3971. /* Initialise the date picker. */
  3972. if ( !$.datepicker.initialized ) {
  3973. $( document ).on( "mousedown", $.datepicker._checkExternalClick );
  3974. $.datepicker.initialized = true;
  3975. }
  3976. /* Append datepicker main container to body if not exist. */
  3977. if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
  3978. $( "body" ).append( $.datepicker.dpDiv );
  3979. }
  3980. var otherArgs = Array.prototype.slice.call( arguments, 1 );
  3981. if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
  3982. return $.datepicker[ "_" + options + "Datepicker" ].
  3983. apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
  3984. }
  3985. if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
  3986. return $.datepicker[ "_" + options + "Datepicker" ].
  3987. apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
  3988. }
  3989. return this.each( function() {
  3990. typeof options === "string" ?
  3991. $.datepicker[ "_" + options + "Datepicker" ].
  3992. apply( $.datepicker, [ this ].concat( otherArgs ) ) :
  3993. $.datepicker._attachDatepicker( this, options );
  3994. } );
  3995. };
  3996. $.datepicker = new Datepicker(); // singleton instance
  3997. $.datepicker.initialized = false;
  3998. $.datepicker.uuid = new Date().getTime();
  3999. $.datepicker.version = "1.12.1";
  4000. var widgetsDatepicker = $.datepicker;
  4001. }));