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.

6580 lines
201 KiB

  1. /*! jQuery UI - v1.12.1 - 2018-10-29
  2. * http://jqueryui.com
  3. * Includes: widget.js, position.js, data.js, keycode.js, scroll-parent.js, unique-id.js, widgets/sortable.js, widgets/autocomplete.js, widgets/datepicker.js, widgets/menu.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 Position 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. * http://api.jqueryui.com/position/
  617. */
  618. //>>label: Position
  619. //>>group: Core
  620. //>>description: Positions elements relative to other elements.
  621. //>>docs: http://api.jqueryui.com/position/
  622. //>>demos: http://jqueryui.com/position/
  623. ( function() {
  624. var cachedScrollbarWidth,
  625. max = Math.max,
  626. abs = Math.abs,
  627. rhorizontal = /left|center|right/,
  628. rvertical = /top|center|bottom/,
  629. roffset = /[\+\-]\d+(\.[\d]+)?%?/,
  630. rposition = /^\w+/,
  631. rpercent = /%$/,
  632. _position = $.fn.position;
  633. function getOffsets( offsets, width, height ) {
  634. return [
  635. parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
  636. parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
  637. ];
  638. }
  639. function parseCss( element, property ) {
  640. return parseInt( $.css( element, property ), 10 ) || 0;
  641. }
  642. function getDimensions( elem ) {
  643. var raw = elem[ 0 ];
  644. if ( raw.nodeType === 9 ) {
  645. return {
  646. width: elem.width(),
  647. height: elem.height(),
  648. offset: { top: 0, left: 0 }
  649. };
  650. }
  651. if ( $.isWindow( raw ) ) {
  652. return {
  653. width: elem.width(),
  654. height: elem.height(),
  655. offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
  656. };
  657. }
  658. if ( raw.preventDefault ) {
  659. return {
  660. width: 0,
  661. height: 0,
  662. offset: { top: raw.pageY, left: raw.pageX }
  663. };
  664. }
  665. return {
  666. width: elem.outerWidth(),
  667. height: elem.outerHeight(),
  668. offset: elem.offset()
  669. };
  670. }
  671. $.position = {
  672. scrollbarWidth: function() {
  673. if ( cachedScrollbarWidth !== undefined ) {
  674. return cachedScrollbarWidth;
  675. }
  676. var w1, w2,
  677. div = $( "<div " +
  678. "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
  679. "<div style='height:100px;width:auto;'></div></div>" ),
  680. innerDiv = div.children()[ 0 ];
  681. $( "body" ).append( div );
  682. w1 = innerDiv.offsetWidth;
  683. div.css( "overflow", "scroll" );
  684. w2 = innerDiv.offsetWidth;
  685. if ( w1 === w2 ) {
  686. w2 = div[ 0 ].clientWidth;
  687. }
  688. div.remove();
  689. return ( cachedScrollbarWidth = w1 - w2 );
  690. },
  691. getScrollInfo: function( within ) {
  692. var overflowX = within.isWindow || within.isDocument ? "" :
  693. within.element.css( "overflow-x" ),
  694. overflowY = within.isWindow || within.isDocument ? "" :
  695. within.element.css( "overflow-y" ),
  696. hasOverflowX = overflowX === "scroll" ||
  697. ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
  698. hasOverflowY = overflowY === "scroll" ||
  699. ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
  700. return {
  701. width: hasOverflowY ? $.position.scrollbarWidth() : 0,
  702. height: hasOverflowX ? $.position.scrollbarWidth() : 0
  703. };
  704. },
  705. getWithinInfo: function( element ) {
  706. var withinElement = $( element || window ),
  707. isWindow = $.isWindow( withinElement[ 0 ] ),
  708. isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
  709. hasOffset = !isWindow && !isDocument;
  710. return {
  711. element: withinElement,
  712. isWindow: isWindow,
  713. isDocument: isDocument,
  714. offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
  715. scrollLeft: withinElement.scrollLeft(),
  716. scrollTop: withinElement.scrollTop(),
  717. width: withinElement.outerWidth(),
  718. height: withinElement.outerHeight()
  719. };
  720. }
  721. };
  722. $.fn.position = function( options ) {
  723. if ( !options || !options.of ) {
  724. return _position.apply( this, arguments );
  725. }
  726. // Make a copy, we don't want to modify arguments
  727. options = $.extend( {}, options );
  728. var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
  729. target = $( options.of ),
  730. within = $.position.getWithinInfo( options.within ),
  731. scrollInfo = $.position.getScrollInfo( within ),
  732. collision = ( options.collision || "flip" ).split( " " ),
  733. offsets = {};
  734. dimensions = getDimensions( target );
  735. if ( target[ 0 ].preventDefault ) {
  736. // Force left top to allow flipping
  737. options.at = "left top";
  738. }
  739. targetWidth = dimensions.width;
  740. targetHeight = dimensions.height;
  741. targetOffset = dimensions.offset;
  742. // Clone to reuse original targetOffset later
  743. basePosition = $.extend( {}, targetOffset );
  744. // Force my and at to have valid horizontal and vertical positions
  745. // if a value is missing or invalid, it will be converted to center
  746. $.each( [ "my", "at" ], function() {
  747. var pos = ( options[ this ] || "" ).split( " " ),
  748. horizontalOffset,
  749. verticalOffset;
  750. if ( pos.length === 1 ) {
  751. pos = rhorizontal.test( pos[ 0 ] ) ?
  752. pos.concat( [ "center" ] ) :
  753. rvertical.test( pos[ 0 ] ) ?
  754. [ "center" ].concat( pos ) :
  755. [ "center", "center" ];
  756. }
  757. pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
  758. pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
  759. // Calculate offsets
  760. horizontalOffset = roffset.exec( pos[ 0 ] );
  761. verticalOffset = roffset.exec( pos[ 1 ] );
  762. offsets[ this ] = [
  763. horizontalOffset ? horizontalOffset[ 0 ] : 0,
  764. verticalOffset ? verticalOffset[ 0 ] : 0
  765. ];
  766. // Reduce to just the positions without the offsets
  767. options[ this ] = [
  768. rposition.exec( pos[ 0 ] )[ 0 ],
  769. rposition.exec( pos[ 1 ] )[ 0 ]
  770. ];
  771. } );
  772. // Normalize collision option
  773. if ( collision.length === 1 ) {
  774. collision[ 1 ] = collision[ 0 ];
  775. }
  776. if ( options.at[ 0 ] === "right" ) {
  777. basePosition.left += targetWidth;
  778. } else if ( options.at[ 0 ] === "center" ) {
  779. basePosition.left += targetWidth / 2;
  780. }
  781. if ( options.at[ 1 ] === "bottom" ) {
  782. basePosition.top += targetHeight;
  783. } else if ( options.at[ 1 ] === "center" ) {
  784. basePosition.top += targetHeight / 2;
  785. }
  786. atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
  787. basePosition.left += atOffset[ 0 ];
  788. basePosition.top += atOffset[ 1 ];
  789. return this.each( function() {
  790. var collisionPosition, using,
  791. elem = $( this ),
  792. elemWidth = elem.outerWidth(),
  793. elemHeight = elem.outerHeight(),
  794. marginLeft = parseCss( this, "marginLeft" ),
  795. marginTop = parseCss( this, "marginTop" ),
  796. collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
  797. scrollInfo.width,
  798. collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
  799. scrollInfo.height,
  800. position = $.extend( {}, basePosition ),
  801. myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
  802. if ( options.my[ 0 ] === "right" ) {
  803. position.left -= elemWidth;
  804. } else if ( options.my[ 0 ] === "center" ) {
  805. position.left -= elemWidth / 2;
  806. }
  807. if ( options.my[ 1 ] === "bottom" ) {
  808. position.top -= elemHeight;
  809. } else if ( options.my[ 1 ] === "center" ) {
  810. position.top -= elemHeight / 2;
  811. }
  812. position.left += myOffset[ 0 ];
  813. position.top += myOffset[ 1 ];
  814. collisionPosition = {
  815. marginLeft: marginLeft,
  816. marginTop: marginTop
  817. };
  818. $.each( [ "left", "top" ], function( i, dir ) {
  819. if ( $.ui.position[ collision[ i ] ] ) {
  820. $.ui.position[ collision[ i ] ][ dir ]( position, {
  821. targetWidth: targetWidth,
  822. targetHeight: targetHeight,
  823. elemWidth: elemWidth,
  824. elemHeight: elemHeight,
  825. collisionPosition: collisionPosition,
  826. collisionWidth: collisionWidth,
  827. collisionHeight: collisionHeight,
  828. offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
  829. my: options.my,
  830. at: options.at,
  831. within: within,
  832. elem: elem
  833. } );
  834. }
  835. } );
  836. if ( options.using ) {
  837. // Adds feedback as second argument to using callback, if present
  838. using = function( props ) {
  839. var left = targetOffset.left - position.left,
  840. right = left + targetWidth - elemWidth,
  841. top = targetOffset.top - position.top,
  842. bottom = top + targetHeight - elemHeight,
  843. feedback = {
  844. target: {
  845. element: target,
  846. left: targetOffset.left,
  847. top: targetOffset.top,
  848. width: targetWidth,
  849. height: targetHeight
  850. },
  851. element: {
  852. element: elem,
  853. left: position.left,
  854. top: position.top,
  855. width: elemWidth,
  856. height: elemHeight
  857. },
  858. horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
  859. vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
  860. };
  861. if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
  862. feedback.horizontal = "center";
  863. }
  864. if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
  865. feedback.vertical = "middle";
  866. }
  867. if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
  868. feedback.important = "horizontal";
  869. } else {
  870. feedback.important = "vertical";
  871. }
  872. options.using.call( this, props, feedback );
  873. };
  874. }
  875. elem.offset( $.extend( position, { using: using } ) );
  876. } );
  877. };
  878. $.ui.position = {
  879. fit: {
  880. left: function( position, data ) {
  881. var within = data.within,
  882. withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
  883. outerWidth = within.width,
  884. collisionPosLeft = position.left - data.collisionPosition.marginLeft,
  885. overLeft = withinOffset - collisionPosLeft,
  886. overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
  887. newOverRight;
  888. // Element is wider than within
  889. if ( data.collisionWidth > outerWidth ) {
  890. // Element is initially over the left side of within
  891. if ( overLeft > 0 && overRight <= 0 ) {
  892. newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
  893. withinOffset;
  894. position.left += overLeft - newOverRight;
  895. // Element is initially over right side of within
  896. } else if ( overRight > 0 && overLeft <= 0 ) {
  897. position.left = withinOffset;
  898. // Element is initially over both left and right sides of within
  899. } else {
  900. if ( overLeft > overRight ) {
  901. position.left = withinOffset + outerWidth - data.collisionWidth;
  902. } else {
  903. position.left = withinOffset;
  904. }
  905. }
  906. // Too far left -> align with left edge
  907. } else if ( overLeft > 0 ) {
  908. position.left += overLeft;
  909. // Too far right -> align with right edge
  910. } else if ( overRight > 0 ) {
  911. position.left -= overRight;
  912. // Adjust based on position and margin
  913. } else {
  914. position.left = max( position.left - collisionPosLeft, position.left );
  915. }
  916. },
  917. top: function( position, data ) {
  918. var within = data.within,
  919. withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
  920. outerHeight = data.within.height,
  921. collisionPosTop = position.top - data.collisionPosition.marginTop,
  922. overTop = withinOffset - collisionPosTop,
  923. overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
  924. newOverBottom;
  925. // Element is taller than within
  926. if ( data.collisionHeight > outerHeight ) {
  927. // Element is initially over the top of within
  928. if ( overTop > 0 && overBottom <= 0 ) {
  929. newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
  930. withinOffset;
  931. position.top += overTop - newOverBottom;
  932. // Element is initially over bottom of within
  933. } else if ( overBottom > 0 && overTop <= 0 ) {
  934. position.top = withinOffset;
  935. // Element is initially over both top and bottom of within
  936. } else {
  937. if ( overTop > overBottom ) {
  938. position.top = withinOffset + outerHeight - data.collisionHeight;
  939. } else {
  940. position.top = withinOffset;
  941. }
  942. }
  943. // Too far up -> align with top
  944. } else if ( overTop > 0 ) {
  945. position.top += overTop;
  946. // Too far down -> align with bottom edge
  947. } else if ( overBottom > 0 ) {
  948. position.top -= overBottom;
  949. // Adjust based on position and margin
  950. } else {
  951. position.top = max( position.top - collisionPosTop, position.top );
  952. }
  953. }
  954. },
  955. flip: {
  956. left: function( position, data ) {
  957. var within = data.within,
  958. withinOffset = within.offset.left + within.scrollLeft,
  959. outerWidth = within.width,
  960. offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
  961. collisionPosLeft = position.left - data.collisionPosition.marginLeft,
  962. overLeft = collisionPosLeft - offsetLeft,
  963. overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
  964. myOffset = data.my[ 0 ] === "left" ?
  965. -data.elemWidth :
  966. data.my[ 0 ] === "right" ?
  967. data.elemWidth :
  968. 0,
  969. atOffset = data.at[ 0 ] === "left" ?
  970. data.targetWidth :
  971. data.at[ 0 ] === "right" ?
  972. -data.targetWidth :
  973. 0,
  974. offset = -2 * data.offset[ 0 ],
  975. newOverRight,
  976. newOverLeft;
  977. if ( overLeft < 0 ) {
  978. newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
  979. outerWidth - withinOffset;
  980. if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
  981. position.left += myOffset + atOffset + offset;
  982. }
  983. } else if ( overRight > 0 ) {
  984. newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
  985. atOffset + offset - offsetLeft;
  986. if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
  987. position.left += myOffset + atOffset + offset;
  988. }
  989. }
  990. },
  991. top: function( position, data ) {
  992. var within = data.within,
  993. withinOffset = within.offset.top + within.scrollTop,
  994. outerHeight = within.height,
  995. offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
  996. collisionPosTop = position.top - data.collisionPosition.marginTop,
  997. overTop = collisionPosTop - offsetTop,
  998. overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
  999. top = data.my[ 1 ] === "top",
  1000. myOffset = top ?
  1001. -data.elemHeight :
  1002. data.my[ 1 ] === "bottom" ?
  1003. data.elemHeight :
  1004. 0,
  1005. atOffset = data.at[ 1 ] === "top" ?
  1006. data.targetHeight :
  1007. data.at[ 1 ] === "bottom" ?
  1008. -data.targetHeight :
  1009. 0,
  1010. offset = -2 * data.offset[ 1 ],
  1011. newOverTop,
  1012. newOverBottom;
  1013. if ( overTop < 0 ) {
  1014. newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
  1015. outerHeight - withinOffset;
  1016. if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
  1017. position.top += myOffset + atOffset + offset;
  1018. }
  1019. } else if ( overBottom > 0 ) {
  1020. newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
  1021. offset - offsetTop;
  1022. if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
  1023. position.top += myOffset + atOffset + offset;
  1024. }
  1025. }
  1026. }
  1027. },
  1028. flipfit: {
  1029. left: function() {
  1030. $.ui.position.flip.left.apply( this, arguments );
  1031. $.ui.position.fit.left.apply( this, arguments );
  1032. },
  1033. top: function() {
  1034. $.ui.position.flip.top.apply( this, arguments );
  1035. $.ui.position.fit.top.apply( this, arguments );
  1036. }
  1037. }
  1038. };
  1039. } )();
  1040. var position = $.ui.position;
  1041. /*!
  1042. * jQuery UI :data 1.12.1
  1043. * http://jqueryui.com
  1044. *
  1045. * Copyright jQuery Foundation and other contributors
  1046. * Released under the MIT license.
  1047. * http://jquery.org/license
  1048. */
  1049. //>>label: :data Selector
  1050. //>>group: Core
  1051. //>>description: Selects elements which have data stored under the specified key.
  1052. //>>docs: http://api.jqueryui.com/data-selector/
  1053. var data = $.extend( $.expr[ ":" ], {
  1054. data: $.expr.createPseudo ?
  1055. $.expr.createPseudo( function( dataName ) {
  1056. return function( elem ) {
  1057. return !!$.data( elem, dataName );
  1058. };
  1059. } ) :
  1060. // Support: jQuery <1.8
  1061. function( elem, i, match ) {
  1062. return !!$.data( elem, match[ 3 ] );
  1063. }
  1064. } );
  1065. /*!
  1066. * jQuery UI Keycode 1.12.1
  1067. * http://jqueryui.com
  1068. *
  1069. * Copyright jQuery Foundation and other contributors
  1070. * Released under the MIT license.
  1071. * http://jquery.org/license
  1072. */
  1073. //>>label: Keycode
  1074. //>>group: Core
  1075. //>>description: Provide keycodes as keynames
  1076. //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
  1077. var keycode = $.ui.keyCode = {
  1078. BACKSPACE: 8,
  1079. COMMA: 188,
  1080. DELETE: 46,
  1081. DOWN: 40,
  1082. END: 35,
  1083. ENTER: 13,
  1084. ESCAPE: 27,
  1085. HOME: 36,
  1086. LEFT: 37,
  1087. PAGE_DOWN: 34,
  1088. PAGE_UP: 33,
  1089. PERIOD: 190,
  1090. RIGHT: 39,
  1091. SPACE: 32,
  1092. TAB: 9,
  1093. UP: 38
  1094. };
  1095. /*!
  1096. * jQuery UI Scroll Parent 1.12.1
  1097. * http://jqueryui.com
  1098. *
  1099. * Copyright jQuery Foundation and other contributors
  1100. * Released under the MIT license.
  1101. * http://jquery.org/license
  1102. */
  1103. //>>label: scrollParent
  1104. //>>group: Core
  1105. //>>description: Get the closest ancestor element that is scrollable.
  1106. //>>docs: http://api.jqueryui.com/scrollParent/
  1107. var scrollParent = $.fn.scrollParent = function( includeHidden ) {
  1108. var position = this.css( "position" ),
  1109. excludeStaticParent = position === "absolute",
  1110. overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
  1111. scrollParent = this.parents().filter( function() {
  1112. var parent = $( this );
  1113. if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
  1114. return false;
  1115. }
  1116. return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
  1117. parent.css( "overflow-x" ) );
  1118. } ).eq( 0 );
  1119. return position === "fixed" || !scrollParent.length ?
  1120. $( this[ 0 ].ownerDocument || document ) :
  1121. scrollParent;
  1122. };
  1123. /*!
  1124. * jQuery UI Unique ID 1.12.1
  1125. * http://jqueryui.com
  1126. *
  1127. * Copyright jQuery Foundation and other contributors
  1128. * Released under the MIT license.
  1129. * http://jquery.org/license
  1130. */
  1131. //>>label: uniqueId
  1132. //>>group: Core
  1133. //>>description: Functions to generate and remove uniqueId's
  1134. //>>docs: http://api.jqueryui.com/uniqueId/
  1135. var uniqueId = $.fn.extend( {
  1136. uniqueId: ( function() {
  1137. var uuid = 0;
  1138. return function() {
  1139. return this.each( function() {
  1140. if ( !this.id ) {
  1141. this.id = "ui-id-" + ( ++uuid );
  1142. }
  1143. } );
  1144. };
  1145. } )(),
  1146. removeUniqueId: function() {
  1147. return this.each( function() {
  1148. if ( /^ui-id-\d+$/.test( this.id ) ) {
  1149. $( this ).removeAttr( "id" );
  1150. }
  1151. } );
  1152. }
  1153. } );
  1154. // This file is deprecated
  1155. var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
  1156. /*!
  1157. * jQuery UI Mouse 1.12.1
  1158. * http://jqueryui.com
  1159. *
  1160. * Copyright jQuery Foundation and other contributors
  1161. * Released under the MIT license.
  1162. * http://jquery.org/license
  1163. */
  1164. //>>label: Mouse
  1165. //>>group: Widgets
  1166. //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
  1167. //>>docs: http://api.jqueryui.com/mouse/
  1168. var mouseHandled = false;
  1169. $( document ).on( "mouseup", function() {
  1170. mouseHandled = false;
  1171. } );
  1172. var widgetsMouse = $.widget( "ui.mouse", {
  1173. version: "1.12.1",
  1174. options: {
  1175. cancel: "input, textarea, button, select, option",
  1176. distance: 1,
  1177. delay: 0
  1178. },
  1179. _mouseInit: function() {
  1180. var that = this;
  1181. this.element
  1182. .on( "mousedown." + this.widgetName, function( event ) {
  1183. return that._mouseDown( event );
  1184. } )
  1185. .on( "click." + this.widgetName, function( event ) {
  1186. if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
  1187. $.removeData( event.target, that.widgetName + ".preventClickEvent" );
  1188. event.stopImmediatePropagation();
  1189. return false;
  1190. }
  1191. } );
  1192. this.started = false;
  1193. },
  1194. // TODO: make sure destroying one instance of mouse doesn't mess with
  1195. // other instances of mouse
  1196. _mouseDestroy: function() {
  1197. this.element.off( "." + this.widgetName );
  1198. if ( this._mouseMoveDelegate ) {
  1199. this.document
  1200. .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  1201. .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
  1202. }
  1203. },
  1204. _mouseDown: function( event ) {
  1205. // don't let more than one widget handle mouseStart
  1206. if ( mouseHandled ) {
  1207. return;
  1208. }
  1209. this._mouseMoved = false;
  1210. // We may have missed mouseup (out of window)
  1211. ( this._mouseStarted && this._mouseUp( event ) );
  1212. this._mouseDownEvent = event;
  1213. var that = this,
  1214. btnIsLeft = ( event.which === 1 ),
  1215. // event.target.nodeName works around a bug in IE 8 with
  1216. // disabled inputs (#7620)
  1217. elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
  1218. $( event.target ).closest( this.options.cancel ).length : false );
  1219. if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
  1220. return true;
  1221. }
  1222. this.mouseDelayMet = !this.options.delay;
  1223. if ( !this.mouseDelayMet ) {
  1224. this._mouseDelayTimer = setTimeout( function() {
  1225. that.mouseDelayMet = true;
  1226. }, this.options.delay );
  1227. }
  1228. if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
  1229. this._mouseStarted = ( this._mouseStart( event ) !== false );
  1230. if ( !this._mouseStarted ) {
  1231. event.preventDefault();
  1232. return true;
  1233. }
  1234. }
  1235. // Click event may never have fired (Gecko & Opera)
  1236. if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
  1237. $.removeData( event.target, this.widgetName + ".preventClickEvent" );
  1238. }
  1239. // These delegates are required to keep context
  1240. this._mouseMoveDelegate = function( event ) {
  1241. return that._mouseMove( event );
  1242. };
  1243. this._mouseUpDelegate = function( event ) {
  1244. return that._mouseUp( event );
  1245. };
  1246. this.document
  1247. .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  1248. .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
  1249. event.preventDefault();
  1250. mouseHandled = true;
  1251. return true;
  1252. },
  1253. _mouseMove: function( event ) {
  1254. // Only check for mouseups outside the document if you've moved inside the document
  1255. // at least once. This prevents the firing of mouseup in the case of IE<9, which will
  1256. // fire a mousemove event if content is placed under the cursor. See #7778
  1257. // Support: IE <9
  1258. if ( this._mouseMoved ) {
  1259. // IE mouseup check - mouseup happened when mouse was out of window
  1260. if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
  1261. !event.button ) {
  1262. return this._mouseUp( event );
  1263. // Iframe mouseup check - mouseup occurred in another document
  1264. } else if ( !event.which ) {
  1265. // Support: Safari <=8 - 9
  1266. // Safari sets which to 0 if you press any of the following keys
  1267. // during a drag (#14461)
  1268. if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
  1269. event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
  1270. this.ignoreMissingWhich = true;
  1271. } else if ( !this.ignoreMissingWhich ) {
  1272. return this._mouseUp( event );
  1273. }
  1274. }
  1275. }
  1276. if ( event.which || event.button ) {
  1277. this._mouseMoved = true;
  1278. }
  1279. if ( this._mouseStarted ) {
  1280. this._mouseDrag( event );
  1281. return event.preventDefault();
  1282. }
  1283. if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
  1284. this._mouseStarted =
  1285. ( this._mouseStart( this._mouseDownEvent, event ) !== false );
  1286. ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
  1287. }
  1288. return !this._mouseStarted;
  1289. },
  1290. _mouseUp: function( event ) {
  1291. this.document
  1292. .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  1293. .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
  1294. if ( this._mouseStarted ) {
  1295. this._mouseStarted = false;
  1296. if ( event.target === this._mouseDownEvent.target ) {
  1297. $.data( event.target, this.widgetName + ".preventClickEvent", true );
  1298. }
  1299. this._mouseStop( event );
  1300. }
  1301. if ( this._mouseDelayTimer ) {
  1302. clearTimeout( this._mouseDelayTimer );
  1303. delete this._mouseDelayTimer;
  1304. }
  1305. this.ignoreMissingWhich = false;
  1306. mouseHandled = false;
  1307. event.preventDefault();
  1308. },
  1309. _mouseDistanceMet: function( event ) {
  1310. return ( Math.max(
  1311. Math.abs( this._mouseDownEvent.pageX - event.pageX ),
  1312. Math.abs( this._mouseDownEvent.pageY - event.pageY )
  1313. ) >= this.options.distance
  1314. );
  1315. },
  1316. _mouseDelayMet: function( /* event */ ) {
  1317. return this.mouseDelayMet;
  1318. },
  1319. // These are placeholder methods, to be overriden by extending plugin
  1320. _mouseStart: function( /* event */ ) {},
  1321. _mouseDrag: function( /* event */ ) {},
  1322. _mouseStop: function( /* event */ ) {},
  1323. _mouseCapture: function( /* event */ ) { return true; }
  1324. } );
  1325. /*!
  1326. * jQuery UI Sortable 1.12.1
  1327. * http://jqueryui.com
  1328. *
  1329. * Copyright jQuery Foundation and other contributors
  1330. * Released under the MIT license.
  1331. * http://jquery.org/license
  1332. */
  1333. //>>label: Sortable
  1334. //>>group: Interactions
  1335. //>>description: Enables items in a list to be sorted using the mouse.
  1336. //>>docs: http://api.jqueryui.com/sortable/
  1337. //>>demos: http://jqueryui.com/sortable/
  1338. //>>css.structure: ../../themes/base/sortable.css
  1339. var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
  1340. version: "1.12.1",
  1341. widgetEventPrefix: "sort",
  1342. ready: false,
  1343. options: {
  1344. appendTo: "parent",
  1345. axis: false,
  1346. connectWith: false,
  1347. containment: false,
  1348. cursor: "auto",
  1349. cursorAt: false,
  1350. dropOnEmpty: true,
  1351. forcePlaceholderSize: false,
  1352. forceHelperSize: false,
  1353. grid: false,
  1354. handle: false,
  1355. helper: "original",
  1356. items: "> *",
  1357. opacity: false,
  1358. placeholder: false,
  1359. revert: false,
  1360. scroll: true,
  1361. scrollSensitivity: 20,
  1362. scrollSpeed: 20,
  1363. scope: "default",
  1364. tolerance: "intersect",
  1365. zIndex: 1000,
  1366. // Callbacks
  1367. activate: null,
  1368. beforeStop: null,
  1369. change: null,
  1370. deactivate: null,
  1371. out: null,
  1372. over: null,
  1373. receive: null,
  1374. remove: null,
  1375. sort: null,
  1376. start: null,
  1377. stop: null,
  1378. update: null
  1379. },
  1380. _isOverAxis: function( x, reference, size ) {
  1381. return ( x >= reference ) && ( x < ( reference + size ) );
  1382. },
  1383. _isFloating: function( item ) {
  1384. return ( /left|right/ ).test( item.css( "float" ) ) ||
  1385. ( /inline|table-cell/ ).test( item.css( "display" ) );
  1386. },
  1387. _create: function() {
  1388. this.containerCache = {};
  1389. this._addClass( "ui-sortable" );
  1390. //Get the items
  1391. this.refresh();
  1392. //Let's determine the parent's offset
  1393. this.offset = this.element.offset();
  1394. //Initialize mouse events for interaction
  1395. this._mouseInit();
  1396. this._setHandleClassName();
  1397. //We're ready to go
  1398. this.ready = true;
  1399. },
  1400. _setOption: function( key, value ) {
  1401. this._super( key, value );
  1402. if ( key === "handle" ) {
  1403. this._setHandleClassName();
  1404. }
  1405. },
  1406. _setHandleClassName: function() {
  1407. var that = this;
  1408. this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
  1409. $.each( this.items, function() {
  1410. that._addClass(
  1411. this.instance.options.handle ?
  1412. this.item.find( this.instance.options.handle ) :
  1413. this.item,
  1414. "ui-sortable-handle"
  1415. );
  1416. } );
  1417. },
  1418. _destroy: function() {
  1419. this._mouseDestroy();
  1420. for ( var i = this.items.length - 1; i >= 0; i-- ) {
  1421. this.items[ i ].item.removeData( this.widgetName + "-item" );
  1422. }
  1423. return this;
  1424. },
  1425. _mouseCapture: function( event, overrideHandle ) {
  1426. var currentItem = null,
  1427. validHandle = false,
  1428. that = this;
  1429. if ( this.reverting ) {
  1430. return false;
  1431. }
  1432. if ( this.options.disabled || this.options.type === "static" ) {
  1433. return false;
  1434. }
  1435. //We have to refresh the items data once first
  1436. this._refreshItems( event );
  1437. //Find out if the clicked node (or one of its parents) is a actual item in this.items
  1438. $( event.target ).parents().each( function() {
  1439. if ( $.data( this, that.widgetName + "-item" ) === that ) {
  1440. currentItem = $( this );
  1441. return false;
  1442. }
  1443. } );
  1444. if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
  1445. currentItem = $( event.target );
  1446. }
  1447. if ( !currentItem ) {
  1448. return false;
  1449. }
  1450. if ( this.options.handle && !overrideHandle ) {
  1451. $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
  1452. if ( this === event.target ) {
  1453. validHandle = true;
  1454. }
  1455. } );
  1456. if ( !validHandle ) {
  1457. return false;
  1458. }
  1459. }
  1460. this.currentItem = currentItem;
  1461. this._removeCurrentsFromItems();
  1462. return true;
  1463. },
  1464. _mouseStart: function( event, overrideHandle, noActivation ) {
  1465. var i, body,
  1466. o = this.options;
  1467. this.currentContainer = this;
  1468. //We only need to call refreshPositions, because the refreshItems call has been moved to
  1469. // mouseCapture
  1470. this.refreshPositions();
  1471. //Create and append the visible helper
  1472. this.helper = this._createHelper( event );
  1473. //Cache the helper size
  1474. this._cacheHelperProportions();
  1475. /*
  1476. * - Position generation -
  1477. * This block generates everything position related - it's the core of draggables.
  1478. */
  1479. //Cache the margins of the original element
  1480. this._cacheMargins();
  1481. //Get the next scrolling parent
  1482. this.scrollParent = this.helper.scrollParent();
  1483. //The element's absolute position on the page minus margins
  1484. this.offset = this.currentItem.offset();
  1485. this.offset = {
  1486. top: this.offset.top - this.margins.top,
  1487. left: this.offset.left - this.margins.left
  1488. };
  1489. $.extend( this.offset, {
  1490. click: { //Where the click happened, relative to the element
  1491. left: event.pageX - this.offset.left,
  1492. top: event.pageY - this.offset.top
  1493. },
  1494. parent: this._getParentOffset(),
  1495. // This is a relative to absolute position minus the actual position calculation -
  1496. // only used for relative positioned helper
  1497. relative: this._getRelativeOffset()
  1498. } );
  1499. // Only after we got the offset, we can change the helper's position to absolute
  1500. // TODO: Still need to figure out a way to make relative sorting possible
  1501. this.helper.css( "position", "absolute" );
  1502. this.cssPosition = this.helper.css( "position" );
  1503. //Generate the original position
  1504. this.originalPosition = this._generatePosition( event );
  1505. this.originalPageX = event.pageX;
  1506. this.originalPageY = event.pageY;
  1507. //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
  1508. ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
  1509. //Cache the former DOM position
  1510. this.domPosition = {
  1511. prev: this.currentItem.prev()[ 0 ],
  1512. parent: this.currentItem.parent()[ 0 ]
  1513. };
  1514. // If the helper is not the original, hide the original so it's not playing any role during
  1515. // the drag, won't cause anything bad this way
  1516. if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
  1517. this.currentItem.hide();
  1518. }
  1519. //Create the placeholder
  1520. this._createPlaceholder();
  1521. //Set a containment if given in the options
  1522. if ( o.containment ) {
  1523. this._setContainment();
  1524. }
  1525. if ( o.cursor && o.cursor !== "auto" ) { // cursor option
  1526. body = this.document.find( "body" );
  1527. // Support: IE
  1528. this.storedCursor = body.css( "cursor" );
  1529. body.css( "cursor", o.cursor );
  1530. this.storedStylesheet =
  1531. $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
  1532. }
  1533. if ( o.opacity ) { // opacity option
  1534. if ( this.helper.css( "opacity" ) ) {
  1535. this._storedOpacity = this.helper.css( "opacity" );
  1536. }
  1537. this.helper.css( "opacity", o.opacity );
  1538. }
  1539. if ( o.zIndex ) { // zIndex option
  1540. if ( this.helper.css( "zIndex" ) ) {
  1541. this._storedZIndex = this.helper.css( "zIndex" );
  1542. }
  1543. this.helper.css( "zIndex", o.zIndex );
  1544. }
  1545. //Prepare scrolling
  1546. if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1547. this.scrollParent[ 0 ].tagName !== "HTML" ) {
  1548. this.overflowOffset = this.scrollParent.offset();
  1549. }
  1550. //Call callbacks
  1551. this._trigger( "start", event, this._uiHash() );
  1552. //Recache the helper size
  1553. if ( !this._preserveHelperProportions ) {
  1554. this._cacheHelperProportions();
  1555. }
  1556. //Post "activate" events to possible containers
  1557. if ( !noActivation ) {
  1558. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  1559. this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
  1560. }
  1561. }
  1562. //Prepare possible droppables
  1563. if ( $.ui.ddmanager ) {
  1564. $.ui.ddmanager.current = this;
  1565. }
  1566. if ( $.ui.ddmanager && !o.dropBehaviour ) {
  1567. $.ui.ddmanager.prepareOffsets( this, event );
  1568. }
  1569. this.dragging = true;
  1570. this._addClass( this.helper, "ui-sortable-helper" );
  1571. // Execute the drag once - this causes the helper not to be visiblebefore getting its
  1572. // correct position
  1573. this._mouseDrag( event );
  1574. return true;
  1575. },
  1576. _mouseDrag: function( event ) {
  1577. var i, item, itemElement, intersection,
  1578. o = this.options,
  1579. scrolled = false;
  1580. //Compute the helpers position
  1581. this.position = this._generatePosition( event );
  1582. this.positionAbs = this._convertPositionTo( "absolute" );
  1583. if ( !this.lastPositionAbs ) {
  1584. this.lastPositionAbs = this.positionAbs;
  1585. }
  1586. //Do scrolling
  1587. if ( this.options.scroll ) {
  1588. if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  1589. this.scrollParent[ 0 ].tagName !== "HTML" ) {
  1590. if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
  1591. event.pageY < o.scrollSensitivity ) {
  1592. this.scrollParent[ 0 ].scrollTop =
  1593. scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
  1594. } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
  1595. this.scrollParent[ 0 ].scrollTop =
  1596. scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
  1597. }
  1598. if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
  1599. event.pageX < o.scrollSensitivity ) {
  1600. this.scrollParent[ 0 ].scrollLeft = scrolled =
  1601. this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
  1602. } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
  1603. this.scrollParent[ 0 ].scrollLeft = scrolled =
  1604. this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
  1605. }
  1606. } else {
  1607. if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
  1608. scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
  1609. } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
  1610. o.scrollSensitivity ) {
  1611. scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
  1612. }
  1613. if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
  1614. scrolled = this.document.scrollLeft(
  1615. this.document.scrollLeft() - o.scrollSpeed
  1616. );
  1617. } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
  1618. o.scrollSensitivity ) {
  1619. scrolled = this.document.scrollLeft(
  1620. this.document.scrollLeft() + o.scrollSpeed
  1621. );
  1622. }
  1623. }
  1624. if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
  1625. $.ui.ddmanager.prepareOffsets( this, event );
  1626. }
  1627. }
  1628. //Regenerate the absolute position used for position checks
  1629. this.positionAbs = this._convertPositionTo( "absolute" );
  1630. //Set the helper position
  1631. if ( !this.options.axis || this.options.axis !== "y" ) {
  1632. this.helper[ 0 ].style.left = this.position.left + "px";
  1633. }
  1634. if ( !this.options.axis || this.options.axis !== "x" ) {
  1635. this.helper[ 0 ].style.top = this.position.top + "px";
  1636. }
  1637. //Rearrange
  1638. for ( i = this.items.length - 1; i >= 0; i-- ) {
  1639. //Cache variables and intersection, continue if no intersection
  1640. item = this.items[ i ];
  1641. itemElement = item.item[ 0 ];
  1642. intersection = this._intersectsWithPointer( item );
  1643. if ( !intersection ) {
  1644. continue;
  1645. }
  1646. // Only put the placeholder inside the current Container, skip all
  1647. // items from other containers. This works because when moving
  1648. // an item from one container to another the
  1649. // currentContainer is switched before the placeholder is moved.
  1650. //
  1651. // Without this, moving items in "sub-sortables" can cause
  1652. // the placeholder to jitter between the outer and inner container.
  1653. if ( item.instance !== this.currentContainer ) {
  1654. continue;
  1655. }
  1656. // Cannot intersect with itself
  1657. // no useless actions that have been done before
  1658. // no action if the item moved is the parent of the item checked
  1659. if ( itemElement !== this.currentItem[ 0 ] &&
  1660. this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
  1661. !$.contains( this.placeholder[ 0 ], itemElement ) &&
  1662. ( this.options.type === "semi-dynamic" ?
  1663. !$.contains( this.element[ 0 ], itemElement ) :
  1664. true
  1665. )
  1666. ) {
  1667. this.direction = intersection === 1 ? "down" : "up";
  1668. if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
  1669. this._rearrange( event, item );
  1670. } else {
  1671. break;
  1672. }
  1673. this._trigger( "change", event, this._uiHash() );
  1674. break;
  1675. }
  1676. }
  1677. //Post events to containers
  1678. this._contactContainers( event );
  1679. //Interconnect with droppables
  1680. if ( $.ui.ddmanager ) {
  1681. $.ui.ddmanager.drag( this, event );
  1682. }
  1683. //Call callbacks
  1684. this._trigger( "sort", event, this._uiHash() );
  1685. this.lastPositionAbs = this.positionAbs;
  1686. return false;
  1687. },
  1688. _mouseStop: function( event, noPropagation ) {
  1689. if ( !event ) {
  1690. return;
  1691. }
  1692. //If we are using droppables, inform the manager about the drop
  1693. if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
  1694. $.ui.ddmanager.drop( this, event );
  1695. }
  1696. if ( this.options.revert ) {
  1697. var that = this,
  1698. cur = this.placeholder.offset(),
  1699. axis = this.options.axis,
  1700. animation = {};
  1701. if ( !axis || axis === "x" ) {
  1702. animation.left = cur.left - this.offset.parent.left - this.margins.left +
  1703. ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
  1704. 0 :
  1705. this.offsetParent[ 0 ].scrollLeft
  1706. );
  1707. }
  1708. if ( !axis || axis === "y" ) {
  1709. animation.top = cur.top - this.offset.parent.top - this.margins.top +
  1710. ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
  1711. 0 :
  1712. this.offsetParent[ 0 ].scrollTop
  1713. );
  1714. }
  1715. this.reverting = true;
  1716. $( this.helper ).animate(
  1717. animation,
  1718. parseInt( this.options.revert, 10 ) || 500,
  1719. function() {
  1720. that._clear( event );
  1721. }
  1722. );
  1723. } else {
  1724. this._clear( event, noPropagation );
  1725. }
  1726. return false;
  1727. },
  1728. cancel: function() {
  1729. if ( this.dragging ) {
  1730. this._mouseUp( new $.Event( "mouseup", { target: null } ) );
  1731. if ( this.options.helper === "original" ) {
  1732. this.currentItem.css( this._storedCSS );
  1733. this._removeClass( this.currentItem, "ui-sortable-helper" );
  1734. } else {
  1735. this.currentItem.show();
  1736. }
  1737. //Post deactivating events to containers
  1738. for ( var i = this.containers.length - 1; i >= 0; i-- ) {
  1739. this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
  1740. if ( this.containers[ i ].containerCache.over ) {
  1741. this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
  1742. this.containers[ i ].containerCache.over = 0;
  1743. }
  1744. }
  1745. }
  1746. if ( this.placeholder ) {
  1747. //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
  1748. // it unbinds ALL events from the original node!
  1749. if ( this.placeholder[ 0 ].parentNode ) {
  1750. this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
  1751. }
  1752. if ( this.options.helper !== "original" && this.helper &&
  1753. this.helper[ 0 ].parentNode ) {
  1754. this.helper.remove();
  1755. }
  1756. $.extend( this, {
  1757. helper: null,
  1758. dragging: false,
  1759. reverting: false,
  1760. _noFinalSort: null
  1761. } );
  1762. if ( this.domPosition.prev ) {
  1763. $( this.domPosition.prev ).after( this.currentItem );
  1764. } else {
  1765. $( this.domPosition.parent ).prepend( this.currentItem );
  1766. }
  1767. }
  1768. return this;
  1769. },
  1770. serialize: function( o ) {
  1771. var items = this._getItemsAsjQuery( o && o.connected ),
  1772. str = [];
  1773. o = o || {};
  1774. $( items ).each( function() {
  1775. var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
  1776. .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
  1777. if ( res ) {
  1778. str.push(
  1779. ( o.key || res[ 1 ] + "[]" ) +
  1780. "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
  1781. }
  1782. } );
  1783. if ( !str.length && o.key ) {
  1784. str.push( o.key + "=" );
  1785. }
  1786. return str.join( "&" );
  1787. },
  1788. toArray: function( o ) {
  1789. var items = this._getItemsAsjQuery( o && o.connected ),
  1790. ret = [];
  1791. o = o || {};
  1792. items.each( function() {
  1793. ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
  1794. } );
  1795. return ret;
  1796. },
  1797. /* Be careful with the following core functions */
  1798. _intersectsWith: function( item ) {
  1799. var x1 = this.positionAbs.left,
  1800. x2 = x1 + this.helperProportions.width,
  1801. y1 = this.positionAbs.top,
  1802. y2 = y1 + this.helperProportions.height,
  1803. l = item.left,
  1804. r = l + item.width,
  1805. t = item.top,
  1806. b = t + item.height,
  1807. dyClick = this.offset.click.top,
  1808. dxClick = this.offset.click.left,
  1809. isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
  1810. ( y1 + dyClick ) < b ),
  1811. isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
  1812. ( x1 + dxClick ) < r ),
  1813. isOverElement = isOverElementHeight && isOverElementWidth;
  1814. if ( this.options.tolerance === "pointer" ||
  1815. this.options.forcePointerForContainers ||
  1816. ( this.options.tolerance !== "pointer" &&
  1817. this.helperProportions[ this.floating ? "width" : "height" ] >
  1818. item[ this.floating ? "width" : "height" ] )
  1819. ) {
  1820. return isOverElement;
  1821. } else {
  1822. return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
  1823. x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
  1824. t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
  1825. y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
  1826. }
  1827. },
  1828. _intersectsWithPointer: function( item ) {
  1829. var verticalDirection, horizontalDirection,
  1830. isOverElementHeight = ( this.options.axis === "x" ) ||
  1831. this._isOverAxis(
  1832. this.positionAbs.top + this.offset.click.top, item.top, item.height ),
  1833. isOverElementWidth = ( this.options.axis === "y" ) ||
  1834. this._isOverAxis(
  1835. this.positionAbs.left + this.offset.click.left, item.left, item.width ),
  1836. isOverElement = isOverElementHeight && isOverElementWidth;
  1837. if ( !isOverElement ) {
  1838. return false;
  1839. }
  1840. verticalDirection = this._getDragVerticalDirection();
  1841. horizontalDirection = this._getDragHorizontalDirection();
  1842. return this.floating ?
  1843. ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
  1844. : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
  1845. },
  1846. _intersectsWithSides: function( item ) {
  1847. var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
  1848. this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
  1849. isOverRightHalf = this._isOverAxis( this.positionAbs.left +
  1850. this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
  1851. verticalDirection = this._getDragVerticalDirection(),
  1852. horizontalDirection = this._getDragHorizontalDirection();
  1853. if ( this.floating && horizontalDirection ) {
  1854. return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
  1855. ( horizontalDirection === "left" && !isOverRightHalf ) );
  1856. } else {
  1857. return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
  1858. ( verticalDirection === "up" && !isOverBottomHalf ) );
  1859. }
  1860. },
  1861. _getDragVerticalDirection: function() {
  1862. var delta = this.positionAbs.top - this.lastPositionAbs.top;
  1863. return delta !== 0 && ( delta > 0 ? "down" : "up" );
  1864. },
  1865. _getDragHorizontalDirection: function() {
  1866. var delta = this.positionAbs.left - this.lastPositionAbs.left;
  1867. return delta !== 0 && ( delta > 0 ? "right" : "left" );
  1868. },
  1869. refresh: function( event ) {
  1870. this._refreshItems( event );
  1871. this._setHandleClassName();
  1872. this.refreshPositions();
  1873. return this;
  1874. },
  1875. _connectWith: function() {
  1876. var options = this.options;
  1877. return options.connectWith.constructor === String ?
  1878. [ options.connectWith ] :
  1879. options.connectWith;
  1880. },
  1881. _getItemsAsjQuery: function( connected ) {
  1882. var i, j, cur, inst,
  1883. items = [],
  1884. queries = [],
  1885. connectWith = this._connectWith();
  1886. if ( connectWith && connected ) {
  1887. for ( i = connectWith.length - 1; i >= 0; i-- ) {
  1888. cur = $( connectWith[ i ], this.document[ 0 ] );
  1889. for ( j = cur.length - 1; j >= 0; j-- ) {
  1890. inst = $.data( cur[ j ], this.widgetFullName );
  1891. if ( inst && inst !== this && !inst.options.disabled ) {
  1892. queries.push( [ $.isFunction( inst.options.items ) ?
  1893. inst.options.items.call( inst.element ) :
  1894. $( inst.options.items, inst.element )
  1895. .not( ".ui-sortable-helper" )
  1896. .not( ".ui-sortable-placeholder" ), inst ] );
  1897. }
  1898. }
  1899. }
  1900. }
  1901. queries.push( [ $.isFunction( this.options.items ) ?
  1902. this.options.items
  1903. .call( this.element, null, { options: this.options, item: this.currentItem } ) :
  1904. $( this.options.items, this.element )
  1905. .not( ".ui-sortable-helper" )
  1906. .not( ".ui-sortable-placeholder" ), this ] );
  1907. function addItems() {
  1908. items.push( this );
  1909. }
  1910. for ( i = queries.length - 1; i >= 0; i-- ) {
  1911. queries[ i ][ 0 ].each( addItems );
  1912. }
  1913. return $( items );
  1914. },
  1915. _removeCurrentsFromItems: function() {
  1916. var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
  1917. this.items = $.grep( this.items, function( item ) {
  1918. for ( var j = 0; j < list.length; j++ ) {
  1919. if ( list[ j ] === item.item[ 0 ] ) {
  1920. return false;
  1921. }
  1922. }
  1923. return true;
  1924. } );
  1925. },
  1926. _refreshItems: function( event ) {
  1927. this.items = [];
  1928. this.containers = [ this ];
  1929. var i, j, cur, inst, targetData, _queries, item, queriesLength,
  1930. items = this.items,
  1931. queries = [ [ $.isFunction( this.options.items ) ?
  1932. this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
  1933. $( this.options.items, this.element ), this ] ],
  1934. connectWith = this._connectWith();
  1935. //Shouldn't be run the first time through due to massive slow-down
  1936. if ( connectWith && this.ready ) {
  1937. for ( i = connectWith.length - 1; i >= 0; i-- ) {
  1938. cur = $( connectWith[ i ], this.document[ 0 ] );
  1939. for ( j = cur.length - 1; j >= 0; j-- ) {
  1940. inst = $.data( cur[ j ], this.widgetFullName );
  1941. if ( inst && inst !== this && !inst.options.disabled ) {
  1942. queries.push( [ $.isFunction( inst.options.items ) ?
  1943. inst.options.items
  1944. .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
  1945. $( inst.options.items, inst.element ), inst ] );
  1946. this.containers.push( inst );
  1947. }
  1948. }
  1949. }
  1950. }
  1951. for ( i = queries.length - 1; i >= 0; i-- ) {
  1952. targetData = queries[ i ][ 1 ];
  1953. _queries = queries[ i ][ 0 ];
  1954. for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
  1955. item = $( _queries[ j ] );
  1956. // Data for target checking (mouse manager)
  1957. item.data( this.widgetName + "-item", targetData );
  1958. items.push( {
  1959. item: item,
  1960. instance: targetData,
  1961. width: 0, height: 0,
  1962. left: 0, top: 0
  1963. } );
  1964. }
  1965. }
  1966. },
  1967. refreshPositions: function( fast ) {
  1968. // Determine whether items are being displayed horizontally
  1969. this.floating = this.items.length ?
  1970. this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
  1971. false;
  1972. //This has to be redone because due to the item being moved out/into the offsetParent,
  1973. // the offsetParent's position will change
  1974. if ( this.offsetParent && this.helper ) {
  1975. this.offset.parent = this._getParentOffset();
  1976. }
  1977. var i, item, t, p;
  1978. for ( i = this.items.length - 1; i >= 0; i-- ) {
  1979. item = this.items[ i ];
  1980. //We ignore calculating positions of all connected containers when we're not over them
  1981. if ( item.instance !== this.currentContainer && this.currentContainer &&
  1982. item.item[ 0 ] !== this.currentItem[ 0 ] ) {
  1983. continue;
  1984. }
  1985. t = this.options.toleranceElement ?
  1986. $( this.options.toleranceElement, item.item ) :
  1987. item.item;
  1988. if ( !fast ) {
  1989. item.width = t.outerWidth();
  1990. item.height = t.outerHeight();
  1991. }
  1992. p = t.offset();
  1993. item.left = p.left;
  1994. item.top = p.top;
  1995. }
  1996. if ( this.options.custom && this.options.custom.refreshContainers ) {
  1997. this.options.custom.refreshContainers.call( this );
  1998. } else {
  1999. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  2000. p = this.containers[ i ].element.offset();
  2001. this.containers[ i ].containerCache.left = p.left;
  2002. this.containers[ i ].containerCache.top = p.top;
  2003. this.containers[ i ].containerCache.width =
  2004. this.containers[ i ].element.outerWidth();
  2005. this.containers[ i ].containerCache.height =
  2006. this.containers[ i ].element.outerHeight();
  2007. }
  2008. }
  2009. return this;
  2010. },
  2011. _createPlaceholder: function( that ) {
  2012. that = that || this;
  2013. var className,
  2014. o = that.options;
  2015. if ( !o.placeholder || o.placeholder.constructor === String ) {
  2016. className = o.placeholder;
  2017. o.placeholder = {
  2018. element: function() {
  2019. var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
  2020. element = $( "<" + nodeName + ">", that.document[ 0 ] );
  2021. that._addClass( element, "ui-sortable-placeholder",
  2022. className || that.currentItem[ 0 ].className )
  2023. ._removeClass( element, "ui-sortable-helper" );
  2024. if ( nodeName === "tbody" ) {
  2025. that._createTrPlaceholder(
  2026. that.currentItem.find( "tr" ).eq( 0 ),
  2027. $( "<tr>", that.document[ 0 ] ).appendTo( element )
  2028. );
  2029. } else if ( nodeName === "tr" ) {
  2030. that._createTrPlaceholder( that.currentItem, element );
  2031. } else if ( nodeName === "img" ) {
  2032. element.attr( "src", that.currentItem.attr( "src" ) );
  2033. }
  2034. if ( !className ) {
  2035. element.css( "visibility", "hidden" );
  2036. }
  2037. return element;
  2038. },
  2039. update: function( container, p ) {
  2040. // 1. If a className is set as 'placeholder option, we don't force sizes -
  2041. // the class is responsible for that
  2042. // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
  2043. // class name is specified
  2044. if ( className && !o.forcePlaceholderSize ) {
  2045. return;
  2046. }
  2047. //If the element doesn't have a actual height by itself (without styles coming
  2048. // from a stylesheet), it receives the inline height from the dragged item
  2049. if ( !p.height() ) {
  2050. p.height(
  2051. that.currentItem.innerHeight() -
  2052. parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
  2053. parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
  2054. }
  2055. if ( !p.width() ) {
  2056. p.width(
  2057. that.currentItem.innerWidth() -
  2058. parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
  2059. parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
  2060. }
  2061. }
  2062. };
  2063. }
  2064. //Create the placeholder
  2065. that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
  2066. //Append it after the actual current item
  2067. that.currentItem.after( that.placeholder );
  2068. //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
  2069. o.placeholder.update( that, that.placeholder );
  2070. },
  2071. _createTrPlaceholder: function( sourceTr, targetTr ) {
  2072. var that = this;
  2073. sourceTr.children().each( function() {
  2074. $( "<td>&#160;</td>", that.document[ 0 ] )
  2075. .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
  2076. .appendTo( targetTr );
  2077. } );
  2078. },
  2079. _contactContainers: function( event ) {
  2080. var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
  2081. floating, axis,
  2082. innermostContainer = null,
  2083. innermostIndex = null;
  2084. // Get innermost container that intersects with item
  2085. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  2086. // Never consider a container that's located within the item itself
  2087. if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
  2088. continue;
  2089. }
  2090. if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
  2091. // If we've already found a container and it's more "inner" than this, then continue
  2092. if ( innermostContainer &&
  2093. $.contains(
  2094. this.containers[ i ].element[ 0 ],
  2095. innermostContainer.element[ 0 ] ) ) {
  2096. continue;
  2097. }
  2098. innermostContainer = this.containers[ i ];
  2099. innermostIndex = i;
  2100. } else {
  2101. // container doesn't intersect. trigger "out" event if necessary
  2102. if ( this.containers[ i ].containerCache.over ) {
  2103. this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
  2104. this.containers[ i ].containerCache.over = 0;
  2105. }
  2106. }
  2107. }
  2108. // If no intersecting containers found, return
  2109. if ( !innermostContainer ) {
  2110. return;
  2111. }
  2112. // Move the item into the container if it's not there already
  2113. if ( this.containers.length === 1 ) {
  2114. if ( !this.containers[ innermostIndex ].containerCache.over ) {
  2115. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
  2116. this.containers[ innermostIndex ].containerCache.over = 1;
  2117. }
  2118. } else {
  2119. // When entering a new container, we will find the item with the least distance and
  2120. // append our item near it
  2121. dist = 10000;
  2122. itemWithLeastDistance = null;
  2123. floating = innermostContainer.floating || this._isFloating( this.currentItem );
  2124. posProperty = floating ? "left" : "top";
  2125. sizeProperty = floating ? "width" : "height";
  2126. axis = floating ? "pageX" : "pageY";
  2127. for ( j = this.items.length - 1; j >= 0; j-- ) {
  2128. if ( !$.contains(
  2129. this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
  2130. ) {
  2131. continue;
  2132. }
  2133. if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
  2134. continue;
  2135. }
  2136. cur = this.items[ j ].item.offset()[ posProperty ];
  2137. nearBottom = false;
  2138. if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
  2139. nearBottom = true;
  2140. }
  2141. if ( Math.abs( event[ axis ] - cur ) < dist ) {
  2142. dist = Math.abs( event[ axis ] - cur );
  2143. itemWithLeastDistance = this.items[ j ];
  2144. this.direction = nearBottom ? "up" : "down";
  2145. }
  2146. }
  2147. //Check if dropOnEmpty is enabled
  2148. if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
  2149. return;
  2150. }
  2151. if ( this.currentContainer === this.containers[ innermostIndex ] ) {
  2152. if ( !this.currentContainer.containerCache.over ) {
  2153. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
  2154. this.currentContainer.containerCache.over = 1;
  2155. }
  2156. return;
  2157. }
  2158. itemWithLeastDistance ?
  2159. this._rearrange( event, itemWithLeastDistance, null, true ) :
  2160. this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
  2161. this._trigger( "change", event, this._uiHash() );
  2162. this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
  2163. this.currentContainer = this.containers[ innermostIndex ];
  2164. //Update the placeholder
  2165. this.options.placeholder.update( this.currentContainer, this.placeholder );
  2166. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
  2167. this.containers[ innermostIndex ].containerCache.over = 1;
  2168. }
  2169. },
  2170. _createHelper: function( event ) {
  2171. var o = this.options,
  2172. helper = $.isFunction( o.helper ) ?
  2173. $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
  2174. ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
  2175. //Add the helper to the DOM if that didn't happen already
  2176. if ( !helper.parents( "body" ).length ) {
  2177. $( o.appendTo !== "parent" ?
  2178. o.appendTo :
  2179. this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
  2180. }
  2181. if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
  2182. this._storedCSS = {
  2183. width: this.currentItem[ 0 ].style.width,
  2184. height: this.currentItem[ 0 ].style.height,
  2185. position: this.currentItem.css( "position" ),
  2186. top: this.currentItem.css( "top" ),
  2187. left: this.currentItem.css( "left" )
  2188. };
  2189. }
  2190. if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
  2191. helper.width( this.currentItem.width() );
  2192. }
  2193. if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
  2194. helper.height( this.currentItem.height() );
  2195. }
  2196. return helper;
  2197. },
  2198. _adjustOffsetFromHelper: function( obj ) {
  2199. if ( typeof obj === "string" ) {
  2200. obj = obj.split( " " );
  2201. }
  2202. if ( $.isArray( obj ) ) {
  2203. obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
  2204. }
  2205. if ( "left" in obj ) {
  2206. this.offset.click.left = obj.left + this.margins.left;
  2207. }
  2208. if ( "right" in obj ) {
  2209. this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
  2210. }
  2211. if ( "top" in obj ) {
  2212. this.offset.click.top = obj.top + this.margins.top;
  2213. }
  2214. if ( "bottom" in obj ) {
  2215. this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
  2216. }
  2217. },
  2218. _getParentOffset: function() {
  2219. //Get the offsetParent and cache its position
  2220. this.offsetParent = this.helper.offsetParent();
  2221. var po = this.offsetParent.offset();
  2222. // This is a special case where we need to modify a offset calculated on start, since the
  2223. // following happened:
  2224. // 1. The position of the helper is absolute, so it's position is calculated based on the
  2225. // next positioned parent
  2226. // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
  2227. // the document, which means that the scroll is included in the initial calculation of the
  2228. // offset of the parent, and never recalculated upon drag
  2229. if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  2230. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
  2231. po.left += this.scrollParent.scrollLeft();
  2232. po.top += this.scrollParent.scrollTop();
  2233. }
  2234. // This needs to be actually done for all browsers, since pageX/pageY includes this
  2235. // information with an ugly IE fix
  2236. if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
  2237. ( this.offsetParent[ 0 ].tagName &&
  2238. this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
  2239. po = { top: 0, left: 0 };
  2240. }
  2241. return {
  2242. top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
  2243. left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
  2244. };
  2245. },
  2246. _getRelativeOffset: function() {
  2247. if ( this.cssPosition === "relative" ) {
  2248. var p = this.currentItem.position();
  2249. return {
  2250. top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
  2251. this.scrollParent.scrollTop(),
  2252. left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
  2253. this.scrollParent.scrollLeft()
  2254. };
  2255. } else {
  2256. return { top: 0, left: 0 };
  2257. }
  2258. },
  2259. _cacheMargins: function() {
  2260. this.margins = {
  2261. left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
  2262. top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
  2263. };
  2264. },
  2265. _cacheHelperProportions: function() {
  2266. this.helperProportions = {
  2267. width: this.helper.outerWidth(),
  2268. height: this.helper.outerHeight()
  2269. };
  2270. },
  2271. _setContainment: function() {
  2272. var ce, co, over,
  2273. o = this.options;
  2274. if ( o.containment === "parent" ) {
  2275. o.containment = this.helper[ 0 ].parentNode;
  2276. }
  2277. if ( o.containment === "document" || o.containment === "window" ) {
  2278. this.containment = [
  2279. 0 - this.offset.relative.left - this.offset.parent.left,
  2280. 0 - this.offset.relative.top - this.offset.parent.top,
  2281. o.containment === "document" ?
  2282. this.document.width() :
  2283. this.window.width() - this.helperProportions.width - this.margins.left,
  2284. ( o.containment === "document" ?
  2285. ( this.document.height() || document.body.parentNode.scrollHeight ) :
  2286. this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
  2287. ) - this.helperProportions.height - this.margins.top
  2288. ];
  2289. }
  2290. if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
  2291. ce = $( o.containment )[ 0 ];
  2292. co = $( o.containment ).offset();
  2293. over = ( $( ce ).css( "overflow" ) !== "hidden" );
  2294. this.containment = [
  2295. co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
  2296. ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
  2297. co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
  2298. ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
  2299. co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
  2300. ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
  2301. ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
  2302. this.helperProportions.width - this.margins.left,
  2303. co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
  2304. ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
  2305. ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
  2306. this.helperProportions.height - this.margins.top
  2307. ];
  2308. }
  2309. },
  2310. _convertPositionTo: function( d, pos ) {
  2311. if ( !pos ) {
  2312. pos = this.position;
  2313. }
  2314. var mod = d === "absolute" ? 1 : -1,
  2315. scroll = this.cssPosition === "absolute" &&
  2316. !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  2317. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
  2318. this.offsetParent :
  2319. this.scrollParent,
  2320. scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
  2321. return {
  2322. top: (
  2323. // The absolute mouse position
  2324. pos.top +
  2325. // Only for relative positioned nodes: Relative offset from element to offset parent
  2326. this.offset.relative.top * mod +
  2327. // The offsetParent's offset without borders (offset + border)
  2328. this.offset.parent.top * mod -
  2329. ( ( this.cssPosition === "fixed" ?
  2330. -this.scrollParent.scrollTop() :
  2331. ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
  2332. ),
  2333. left: (
  2334. // The absolute mouse position
  2335. pos.left +
  2336. // Only for relative positioned nodes: Relative offset from element to offset parent
  2337. this.offset.relative.left * mod +
  2338. // The offsetParent's offset without borders (offset + border)
  2339. this.offset.parent.left * mod -
  2340. ( ( this.cssPosition === "fixed" ?
  2341. -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
  2342. scroll.scrollLeft() ) * mod )
  2343. )
  2344. };
  2345. },
  2346. _generatePosition: function( event ) {
  2347. var top, left,
  2348. o = this.options,
  2349. pageX = event.pageX,
  2350. pageY = event.pageY,
  2351. scroll = this.cssPosition === "absolute" &&
  2352. !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  2353. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
  2354. this.offsetParent :
  2355. this.scrollParent,
  2356. scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
  2357. // This is another very weird special case that only happens for relative elements:
  2358. // 1. If the css position is relative
  2359. // 2. and the scroll parent is the document or similar to the offset parent
  2360. // we have to refresh the relative offset during the scroll so there are no jumps
  2361. if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  2362. this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
  2363. this.offset.relative = this._getRelativeOffset();
  2364. }
  2365. /*
  2366. * - Position constraining -
  2367. * Constrain the position to a mix of grid, containment.
  2368. */
  2369. if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
  2370. if ( this.containment ) {
  2371. if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
  2372. pageX = this.containment[ 0 ] + this.offset.click.left;
  2373. }
  2374. if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
  2375. pageY = this.containment[ 1 ] + this.offset.click.top;
  2376. }
  2377. if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
  2378. pageX = this.containment[ 2 ] + this.offset.click.left;
  2379. }
  2380. if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
  2381. pageY = this.containment[ 3 ] + this.offset.click.top;
  2382. }
  2383. }
  2384. if ( o.grid ) {
  2385. top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
  2386. o.grid[ 1 ] ) * o.grid[ 1 ];
  2387. pageY = this.containment ?
  2388. ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
  2389. top - this.offset.click.top <= this.containment[ 3 ] ) ?
  2390. top :
  2391. ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
  2392. top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
  2393. top;
  2394. left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
  2395. o.grid[ 0 ] ) * o.grid[ 0 ];
  2396. pageX = this.containment ?
  2397. ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
  2398. left - this.offset.click.left <= this.containment[ 2 ] ) ?
  2399. left :
  2400. ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
  2401. left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
  2402. left;
  2403. }
  2404. }
  2405. return {
  2406. top: (
  2407. // The absolute mouse position
  2408. pageY -
  2409. // Click offset (relative to the element)
  2410. this.offset.click.top -
  2411. // Only for relative positioned nodes: Relative offset from element to offset parent
  2412. this.offset.relative.top -
  2413. // The offsetParent's offset without borders (offset + border)
  2414. this.offset.parent.top +
  2415. ( ( this.cssPosition === "fixed" ?
  2416. -this.scrollParent.scrollTop() :
  2417. ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
  2418. ),
  2419. left: (
  2420. // The absolute mouse position
  2421. pageX -
  2422. // Click offset (relative to the element)
  2423. this.offset.click.left -
  2424. // Only for relative positioned nodes: Relative offset from element to offset parent
  2425. this.offset.relative.left -
  2426. // The offsetParent's offset without borders (offset + border)
  2427. this.offset.parent.left +
  2428. ( ( this.cssPosition === "fixed" ?
  2429. -this.scrollParent.scrollLeft() :
  2430. scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
  2431. )
  2432. };
  2433. },
  2434. _rearrange: function( event, i, a, hardRefresh ) {
  2435. a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
  2436. i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
  2437. ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
  2438. //Various things done here to improve the performance:
  2439. // 1. we create a setTimeout, that calls refreshPositions
  2440. // 2. on the instance, we have a counter variable, that get's higher after every append
  2441. // 3. on the local scope, we copy the counter variable, and check in the timeout,
  2442. // if it's still the same
  2443. // 4. this lets only the last addition to the timeout stack through
  2444. this.counter = this.counter ? ++this.counter : 1;
  2445. var counter = this.counter;
  2446. this._delay( function() {
  2447. if ( counter === this.counter ) {
  2448. //Precompute after each DOM insertion, NOT on mousemove
  2449. this.refreshPositions( !hardRefresh );
  2450. }
  2451. } );
  2452. },
  2453. _clear: function( event, noPropagation ) {
  2454. this.reverting = false;
  2455. // We delay all events that have to be triggered to after the point where the placeholder
  2456. // has been removed and everything else normalized again
  2457. var i,
  2458. delayedTriggers = [];
  2459. // We first have to update the dom position of the actual currentItem
  2460. // Note: don't do it if the current item is already removed (by a user), or it gets
  2461. // reappended (see #4088)
  2462. if ( !this._noFinalSort && this.currentItem.parent().length ) {
  2463. this.placeholder.before( this.currentItem );
  2464. }
  2465. this._noFinalSort = null;
  2466. if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
  2467. for ( i in this._storedCSS ) {
  2468. if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
  2469. this._storedCSS[ i ] = "";
  2470. }
  2471. }
  2472. this.currentItem.css( this._storedCSS );
  2473. this._removeClass( this.currentItem, "ui-sortable-helper" );
  2474. } else {
  2475. this.currentItem.show();
  2476. }
  2477. if ( this.fromOutside && !noPropagation ) {
  2478. delayedTriggers.push( function( event ) {
  2479. this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
  2480. } );
  2481. }
  2482. if ( ( this.fromOutside ||
  2483. this.domPosition.prev !==
  2484. this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
  2485. this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
  2486. // Trigger update callback if the DOM position has changed
  2487. delayedTriggers.push( function( event ) {
  2488. this._trigger( "update", event, this._uiHash() );
  2489. } );
  2490. }
  2491. // Check if the items Container has Changed and trigger appropriate
  2492. // events.
  2493. if ( this !== this.currentContainer ) {
  2494. if ( !noPropagation ) {
  2495. delayedTriggers.push( function( event ) {
  2496. this._trigger( "remove", event, this._uiHash() );
  2497. } );
  2498. delayedTriggers.push( ( function( c ) {
  2499. return function( event ) {
  2500. c._trigger( "receive", event, this._uiHash( this ) );
  2501. };
  2502. } ).call( this, this.currentContainer ) );
  2503. delayedTriggers.push( ( function( c ) {
  2504. return function( event ) {
  2505. c._trigger( "update", event, this._uiHash( this ) );
  2506. };
  2507. } ).call( this, this.currentContainer ) );
  2508. }
  2509. }
  2510. //Post events to containers
  2511. function delayEvent( type, instance, container ) {
  2512. return function( event ) {
  2513. container._trigger( type, event, instance._uiHash( instance ) );
  2514. };
  2515. }
  2516. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  2517. if ( !noPropagation ) {
  2518. delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
  2519. }
  2520. if ( this.containers[ i ].containerCache.over ) {
  2521. delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
  2522. this.containers[ i ].containerCache.over = 0;
  2523. }
  2524. }
  2525. //Do what was originally in plugins
  2526. if ( this.storedCursor ) {
  2527. this.document.find( "body" ).css( "cursor", this.storedCursor );
  2528. this.storedStylesheet.remove();
  2529. }
  2530. if ( this._storedOpacity ) {
  2531. this.helper.css( "opacity", this._storedOpacity );
  2532. }
  2533. if ( this._storedZIndex ) {
  2534. this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
  2535. }
  2536. this.dragging = false;
  2537. if ( !noPropagation ) {
  2538. this._trigger( "beforeStop", event, this._uiHash() );
  2539. }
  2540. //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
  2541. // it unbinds ALL events from the original node!
  2542. this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
  2543. if ( !this.cancelHelperRemoval ) {
  2544. if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
  2545. this.helper.remove();
  2546. }
  2547. this.helper = null;
  2548. }
  2549. if ( !noPropagation ) {
  2550. for ( i = 0; i < delayedTriggers.length; i++ ) {
  2551. // Trigger all delayed events
  2552. delayedTriggers[ i ].call( this, event );
  2553. }
  2554. this._trigger( "stop", event, this._uiHash() );
  2555. }
  2556. this.fromOutside = false;
  2557. return !this.cancelHelperRemoval;
  2558. },
  2559. _trigger: function() {
  2560. if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
  2561. this.cancel();
  2562. }
  2563. },
  2564. _uiHash: function( _inst ) {
  2565. var inst = _inst || this;
  2566. return {
  2567. helper: inst.helper,
  2568. placeholder: inst.placeholder || $( [] ),
  2569. position: inst.position,
  2570. originalPosition: inst.originalPosition,
  2571. offset: inst.positionAbs,
  2572. item: inst.currentItem,
  2573. sender: _inst ? _inst.element : null
  2574. };
  2575. }
  2576. } );
  2577. var safeActiveElement = $.ui.safeActiveElement = function( document ) {
  2578. var activeElement;
  2579. // Support: IE 9 only
  2580. // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
  2581. try {
  2582. activeElement = document.activeElement;
  2583. } catch ( error ) {
  2584. activeElement = document.body;
  2585. }
  2586. // Support: IE 9 - 11 only
  2587. // IE may return null instead of an element
  2588. // Interestingly, this only seems to occur when NOT in an iframe
  2589. if ( !activeElement ) {
  2590. activeElement = document.body;
  2591. }
  2592. // Support: IE 11 only
  2593. // IE11 returns a seemingly empty object in some cases when accessing
  2594. // document.activeElement from an <iframe>
  2595. if ( !activeElement.nodeName ) {
  2596. activeElement = document.body;
  2597. }
  2598. return activeElement;
  2599. };
  2600. /*!
  2601. * jQuery UI Menu 1.12.1
  2602. * http://jqueryui.com
  2603. *
  2604. * Copyright jQuery Foundation and other contributors
  2605. * Released under the MIT license.
  2606. * http://jquery.org/license
  2607. */
  2608. //>>label: Menu
  2609. //>>group: Widgets
  2610. //>>description: Creates nestable menus.
  2611. //>>docs: http://api.jqueryui.com/menu/
  2612. //>>demos: http://jqueryui.com/menu/
  2613. //>>css.structure: ../../themes/base/core.css
  2614. //>>css.structure: ../../themes/base/menu.css
  2615. //>>css.theme: ../../themes/base/theme.css
  2616. var widgetsMenu = $.widget( "ui.menu", {
  2617. version: "1.12.1",
  2618. defaultElement: "<ul>",
  2619. delay: 300,
  2620. options: {
  2621. icons: {
  2622. submenu: "ui-icon-caret-1-e"
  2623. },
  2624. items: "> *",
  2625. menus: "ul",
  2626. position: {
  2627. my: "left top",
  2628. at: "right top"
  2629. },
  2630. role: "menu",
  2631. // Callbacks
  2632. blur: null,
  2633. focus: null,
  2634. select: null
  2635. },
  2636. _create: function() {
  2637. this.activeMenu = this.element;
  2638. // Flag used to prevent firing of the click handler
  2639. // as the event bubbles up through nested menus
  2640. this.mouseHandled = false;
  2641. this.element
  2642. .uniqueId()
  2643. .attr( {
  2644. role: this.options.role,
  2645. tabIndex: 0
  2646. } );
  2647. this._addClass( "ui-menu", "ui-widget ui-widget-content" );
  2648. this._on( {
  2649. // Prevent focus from sticking to links inside menu after clicking
  2650. // them (focus should always stay on UL during navigation).
  2651. "mousedown .ui-menu-item": function( event ) {
  2652. event.preventDefault();
  2653. },
  2654. "click .ui-menu-item": function( event ) {
  2655. var target = $( event.target );
  2656. var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
  2657. if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
  2658. this.select( event );
  2659. // Only set the mouseHandled flag if the event will bubble, see #9469.
  2660. if ( !event.isPropagationStopped() ) {
  2661. this.mouseHandled = true;
  2662. }
  2663. // Open submenu on click
  2664. if ( target.has( ".ui-menu" ).length ) {
  2665. this.expand( event );
  2666. } else if ( !this.element.is( ":focus" ) &&
  2667. active.closest( ".ui-menu" ).length ) {
  2668. // Redirect focus to the menu
  2669. this.element.trigger( "focus", [ true ] );
  2670. // If the active item is on the top level, let it stay active.
  2671. // Otherwise, blur the active item since it is no longer visible.
  2672. if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
  2673. clearTimeout( this.timer );
  2674. }
  2675. }
  2676. }
  2677. },
  2678. "mouseenter .ui-menu-item": function( event ) {
  2679. // Ignore mouse events while typeahead is active, see #10458.
  2680. // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
  2681. // is over an item in the menu
  2682. if ( this.previousFilter ) {
  2683. return;
  2684. }
  2685. var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
  2686. target = $( event.currentTarget );
  2687. // Ignore bubbled events on parent items, see #11641
  2688. if ( actualTarget[ 0 ] !== target[ 0 ] ) {
  2689. return;
  2690. }
  2691. // Remove ui-state-active class from siblings of the newly focused menu item
  2692. // to avoid a jump caused by adjacent elements both having a class with a border
  2693. this._removeClass( target.siblings().children( ".ui-state-active" ),
  2694. null, "ui-state-active" );
  2695. this.focus( event, target );
  2696. },
  2697. mouseleave: "collapseAll",
  2698. "mouseleave .ui-menu": "collapseAll",
  2699. focus: function( event, keepActiveItem ) {
  2700. // If there's already an active item, keep it active
  2701. // If not, activate the first item
  2702. var item = this.active || this.element.find( this.options.items ).eq( 0 );
  2703. if ( !keepActiveItem ) {
  2704. this.focus( event, item );
  2705. }
  2706. },
  2707. blur: function( event ) {
  2708. this._delay( function() {
  2709. var notContained = !$.contains(
  2710. this.element[ 0 ],
  2711. $.ui.safeActiveElement( this.document[ 0 ] )
  2712. );
  2713. if ( notContained ) {
  2714. this.collapseAll( event );
  2715. }
  2716. } );
  2717. },
  2718. keydown: "_keydown"
  2719. } );
  2720. this.refresh();
  2721. // Clicks outside of a menu collapse any open menus
  2722. this._on( this.document, {
  2723. click: function( event ) {
  2724. if ( this._closeOnDocumentClick( event ) ) {
  2725. this.collapseAll( event );
  2726. }
  2727. // Reset the mouseHandled flag
  2728. this.mouseHandled = false;
  2729. }
  2730. } );
  2731. },
  2732. _destroy: function() {
  2733. var items = this.element.find( ".ui-menu-item" )
  2734. .removeAttr( "role aria-disabled" ),
  2735. submenus = items.children( ".ui-menu-item-wrapper" )
  2736. .removeUniqueId()
  2737. .removeAttr( "tabIndex role aria-haspopup" );
  2738. // Destroy (sub)menus
  2739. this.element
  2740. .removeAttr( "aria-activedescendant" )
  2741. .find( ".ui-menu" ).addBack()
  2742. .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
  2743. "tabIndex" )
  2744. .removeUniqueId()
  2745. .show();
  2746. submenus.children().each( function() {
  2747. var elem = $( this );
  2748. if ( elem.data( "ui-menu-submenu-caret" ) ) {
  2749. elem.remove();
  2750. }
  2751. } );
  2752. },
  2753. _keydown: function( event ) {
  2754. var match, prev, character, skip,
  2755. preventDefault = true;
  2756. switch ( event.keyCode ) {
  2757. case $.ui.keyCode.PAGE_UP:
  2758. this.previousPage( event );
  2759. break;
  2760. case $.ui.keyCode.PAGE_DOWN:
  2761. this.nextPage( event );
  2762. break;
  2763. case $.ui.keyCode.HOME:
  2764. this._move( "first", "first", event );
  2765. break;
  2766. case $.ui.keyCode.END:
  2767. this._move( "last", "last", event );
  2768. break;
  2769. case $.ui.keyCode.UP:
  2770. this.previous( event );
  2771. break;
  2772. case $.ui.keyCode.DOWN:
  2773. this.next( event );
  2774. break;
  2775. case $.ui.keyCode.LEFT:
  2776. this.collapse( event );
  2777. break;
  2778. case $.ui.keyCode.RIGHT:
  2779. if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
  2780. this.expand( event );
  2781. }
  2782. break;
  2783. case $.ui.keyCode.ENTER:
  2784. case $.ui.keyCode.SPACE:
  2785. this._activate( event );
  2786. break;
  2787. case $.ui.keyCode.ESCAPE:
  2788. this.collapse( event );
  2789. break;
  2790. default:
  2791. preventDefault = false;
  2792. prev = this.previousFilter || "";
  2793. skip = false;
  2794. // Support number pad values
  2795. character = event.keyCode >= 96 && event.keyCode <= 105 ?
  2796. ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
  2797. clearTimeout( this.filterTimer );
  2798. if ( character === prev ) {
  2799. skip = true;
  2800. } else {
  2801. character = prev + character;
  2802. }
  2803. match = this._filterMenuItems( character );
  2804. match = skip && match.index( this.active.next() ) !== -1 ?
  2805. this.active.nextAll( ".ui-menu-item" ) :
  2806. match;
  2807. // If no matches on the current filter, reset to the last character pressed
  2808. // to move down the menu to the first item that starts with that character
  2809. if ( !match.length ) {
  2810. character = String.fromCharCode( event.keyCode );
  2811. match = this._filterMenuItems( character );
  2812. }
  2813. if ( match.length ) {
  2814. this.focus( event, match );
  2815. this.previousFilter = character;
  2816. this.filterTimer = this._delay( function() {
  2817. delete this.previousFilter;
  2818. }, 1000 );
  2819. } else {
  2820. delete this.previousFilter;
  2821. }
  2822. }
  2823. if ( preventDefault ) {
  2824. event.preventDefault();
  2825. }
  2826. },
  2827. _activate: function( event ) {
  2828. if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
  2829. if ( this.active.children( "[aria-haspopup='true']" ).length ) {
  2830. this.expand( event );
  2831. } else {
  2832. this.select( event );
  2833. }
  2834. }
  2835. },
  2836. refresh: function() {
  2837. var menus, items, newSubmenus, newItems, newWrappers,
  2838. that = this,
  2839. icon = this.options.icons.submenu,
  2840. submenus = this.element.find( this.options.menus );
  2841. this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
  2842. // Initialize nested menus
  2843. newSubmenus = submenus.filter( ":not(.ui-menu)" )
  2844. .hide()
  2845. .attr( {
  2846. role: this.options.role,
  2847. "aria-hidden": "true",
  2848. "aria-expanded": "false"
  2849. } )
  2850. .each( function() {
  2851. var menu = $( this ),
  2852. item = menu.prev(),
  2853. submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
  2854. that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
  2855. item
  2856. .attr( "aria-haspopup", "true" )
  2857. .prepend( submenuCaret );
  2858. menu.attr( "aria-labelledby", item.attr( "id" ) );
  2859. } );
  2860. this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
  2861. menus = submenus.add( this.element );
  2862. items = menus.find( this.options.items );
  2863. // Initialize menu-items containing spaces and/or dashes only as dividers
  2864. items.not( ".ui-menu-item" ).each( function() {
  2865. var item = $( this );
  2866. if ( that._isDivider( item ) ) {
  2867. that._addClass( item, "ui-menu-divider", "ui-widget-content" );
  2868. }
  2869. } );
  2870. // Don't refresh list items that are already adapted
  2871. newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
  2872. newWrappers = newItems.children()
  2873. .not( ".ui-menu" )
  2874. .uniqueId()
  2875. .attr( {
  2876. tabIndex: -1,
  2877. role: this._itemRole()
  2878. } );
  2879. this._addClass( newItems, "ui-menu-item" )
  2880. ._addClass( newWrappers, "ui-menu-item-wrapper" );
  2881. // Add aria-disabled attribute to any disabled menu item
  2882. items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
  2883. // If the active item has been removed, blur the menu
  2884. if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
  2885. this.blur();
  2886. }
  2887. },
  2888. _itemRole: function() {
  2889. return {
  2890. menu: "menuitem",
  2891. listbox: "option"
  2892. }[ this.options.role ];
  2893. },
  2894. _setOption: function( key, value ) {
  2895. if ( key === "icons" ) {
  2896. var icons = this.element.find( ".ui-menu-icon" );
  2897. this._removeClass( icons, null, this.options.icons.submenu )
  2898. ._addClass( icons, null, value.submenu );
  2899. }
  2900. this._super( key, value );
  2901. },
  2902. _setOptionDisabled: function( value ) {
  2903. this._super( value );
  2904. this.element.attr( "aria-disabled", String( value ) );
  2905. this._toggleClass( null, "ui-state-disabled", !!value );
  2906. },
  2907. focus: function( event, item ) {
  2908. var nested, focused, activeParent;
  2909. this.blur( event, event && event.type === "focus" );
  2910. this._scrollIntoView( item );
  2911. this.active = item.first();
  2912. focused = this.active.children( ".ui-menu-item-wrapper" );
  2913. this._addClass( focused, null, "ui-state-active" );
  2914. // Only update aria-activedescendant if there's a role
  2915. // otherwise we assume focus is managed elsewhere
  2916. if ( this.options.role ) {
  2917. this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
  2918. }
  2919. // Highlight active parent menu item, if any
  2920. activeParent = this.active
  2921. .parent()
  2922. .closest( ".ui-menu-item" )
  2923. .children( ".ui-menu-item-wrapper" );
  2924. this._addClass( activeParent, null, "ui-state-active" );
  2925. if ( event && event.type === "keydown" ) {
  2926. this._close();
  2927. } else {
  2928. this.timer = this._delay( function() {
  2929. this._close();
  2930. }, this.delay );
  2931. }
  2932. nested = item.children( ".ui-menu" );
  2933. if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
  2934. this._startOpening( nested );
  2935. }
  2936. this.activeMenu = item.parent();
  2937. this._trigger( "focus", event, { item: item } );
  2938. },
  2939. _scrollIntoView: function( item ) {
  2940. var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
  2941. if ( this._hasScroll() ) {
  2942. borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
  2943. paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
  2944. offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
  2945. scroll = this.activeMenu.scrollTop();
  2946. elementHeight = this.activeMenu.height();
  2947. itemHeight = item.outerHeight();
  2948. if ( offset < 0 ) {
  2949. this.activeMenu.scrollTop( scroll + offset );
  2950. } else if ( offset + itemHeight > elementHeight ) {
  2951. this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
  2952. }
  2953. }
  2954. },
  2955. blur: function( event, fromFocus ) {
  2956. if ( !fromFocus ) {
  2957. clearTimeout( this.timer );
  2958. }
  2959. if ( !this.active ) {
  2960. return;
  2961. }
  2962. this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
  2963. null, "ui-state-active" );
  2964. this._trigger( "blur", event, { item: this.active } );
  2965. this.active = null;
  2966. },
  2967. _startOpening: function( submenu ) {
  2968. clearTimeout( this.timer );
  2969. // Don't open if already open fixes a Firefox bug that caused a .5 pixel
  2970. // shift in the submenu position when mousing over the caret icon
  2971. if ( submenu.attr( "aria-hidden" ) !== "true" ) {
  2972. return;
  2973. }
  2974. this.timer = this._delay( function() {
  2975. this._close();
  2976. this._open( submenu );
  2977. }, this.delay );
  2978. },
  2979. _open: function( submenu ) {
  2980. var position = $.extend( {
  2981. of: this.active
  2982. }, this.options.position );
  2983. clearTimeout( this.timer );
  2984. this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
  2985. .hide()
  2986. .attr( "aria-hidden", "true" );
  2987. submenu
  2988. .show()
  2989. .removeAttr( "aria-hidden" )
  2990. .attr( "aria-expanded", "true" )
  2991. .position( position );
  2992. },
  2993. collapseAll: function( event, all ) {
  2994. clearTimeout( this.timer );
  2995. this.timer = this._delay( function() {
  2996. // If we were passed an event, look for the submenu that contains the event
  2997. var currentMenu = all ? this.element :
  2998. $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
  2999. // If we found no valid submenu ancestor, use the main menu to close all
  3000. // sub menus anyway
  3001. if ( !currentMenu.length ) {
  3002. currentMenu = this.element;
  3003. }
  3004. this._close( currentMenu );
  3005. this.blur( event );
  3006. // Work around active item staying active after menu is blurred
  3007. this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
  3008. this.activeMenu = currentMenu;
  3009. }, this.delay );
  3010. },
  3011. // With no arguments, closes the currently active menu - if nothing is active
  3012. // it closes all menus. If passed an argument, it will search for menus BELOW
  3013. _close: function( startMenu ) {
  3014. if ( !startMenu ) {
  3015. startMenu = this.active ? this.active.parent() : this.element;
  3016. }
  3017. startMenu.find( ".ui-menu" )
  3018. .hide()
  3019. .attr( "aria-hidden", "true" )
  3020. .attr( "aria-expanded", "false" );
  3021. },
  3022. _closeOnDocumentClick: function( event ) {
  3023. return !$( event.target ).closest( ".ui-menu" ).length;
  3024. },
  3025. _isDivider: function( item ) {
  3026. // Match hyphen, em dash, en dash
  3027. return !/[^\-\u2014\u2013\s]/.test( item.text() );
  3028. },
  3029. collapse: function( event ) {
  3030. var newItem = this.active &&
  3031. this.active.parent().closest( ".ui-menu-item", this.element );
  3032. if ( newItem && newItem.length ) {
  3033. this._close();
  3034. this.focus( event, newItem );
  3035. }
  3036. },
  3037. expand: function( event ) {
  3038. var newItem = this.active &&
  3039. this.active
  3040. .children( ".ui-menu " )
  3041. .find( this.options.items )
  3042. .first();
  3043. if ( newItem && newItem.length ) {
  3044. this._open( newItem.parent() );
  3045. // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
  3046. this._delay( function() {
  3047. this.focus( event, newItem );
  3048. } );
  3049. }
  3050. },
  3051. next: function( event ) {
  3052. this._move( "next", "first", event );
  3053. },
  3054. previous: function( event ) {
  3055. this._move( "prev", "last", event );
  3056. },
  3057. isFirstItem: function() {
  3058. return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
  3059. },
  3060. isLastItem: function() {
  3061. return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
  3062. },
  3063. _move: function( direction, filter, event ) {
  3064. var next;
  3065. if ( this.active ) {
  3066. if ( direction === "first" || direction === "last" ) {
  3067. next = this.active
  3068. [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
  3069. .eq( -1 );
  3070. } else {
  3071. next = this.active
  3072. [ direction + "All" ]( ".ui-menu-item" )
  3073. .eq( 0 );
  3074. }
  3075. }
  3076. if ( !next || !next.length || !this.active ) {
  3077. next = this.activeMenu.find( this.options.items )[ filter ]();
  3078. }
  3079. this.focus( event, next );
  3080. },
  3081. nextPage: function( event ) {
  3082. var item, base, height;
  3083. if ( !this.active ) {
  3084. this.next( event );
  3085. return;
  3086. }
  3087. if ( this.isLastItem() ) {
  3088. return;
  3089. }
  3090. if ( this._hasScroll() ) {
  3091. base = this.active.offset().top;
  3092. height = this.element.height();
  3093. this.active.nextAll( ".ui-menu-item" ).each( function() {
  3094. item = $( this );
  3095. return item.offset().top - base - height < 0;
  3096. } );
  3097. this.focus( event, item );
  3098. } else {
  3099. this.focus( event, this.activeMenu.find( this.options.items )
  3100. [ !this.active ? "first" : "last" ]() );
  3101. }
  3102. },
  3103. previousPage: function( event ) {
  3104. var item, base, height;
  3105. if ( !this.active ) {
  3106. this.next( event );
  3107. return;
  3108. }
  3109. if ( this.isFirstItem() ) {
  3110. return;
  3111. }
  3112. if ( this._hasScroll() ) {
  3113. base = this.active.offset().top;
  3114. height = this.element.height();
  3115. this.active.prevAll( ".ui-menu-item" ).each( function() {
  3116. item = $( this );
  3117. return item.offset().top - base + height > 0;
  3118. } );
  3119. this.focus( event, item );
  3120. } else {
  3121. this.focus( event, this.activeMenu.find( this.options.items ).first() );
  3122. }
  3123. },
  3124. _hasScroll: function() {
  3125. return this.element.outerHeight() < this.element.prop( "scrollHeight" );
  3126. },
  3127. select: function( event ) {
  3128. // TODO: It should never be possible to not have an active item at this
  3129. // point, but the tests don't trigger mouseenter before click.
  3130. this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
  3131. var ui = { item: this.active };
  3132. if ( !this.active.has( ".ui-menu" ).length ) {
  3133. this.collapseAll( event, true );
  3134. }
  3135. this._trigger( "select", event, ui );
  3136. },
  3137. _filterMenuItems: function( character ) {
  3138. var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
  3139. regex = new RegExp( "^" + escapedCharacter, "i" );
  3140. return this.activeMenu
  3141. .find( this.options.items )
  3142. // Only match on items, not dividers or other content (#10571)
  3143. .filter( ".ui-menu-item" )
  3144. .filter( function() {
  3145. return regex.test(
  3146. $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
  3147. } );
  3148. }
  3149. } );
  3150. /*!
  3151. * jQuery UI Autocomplete 1.12.1
  3152. * http://jqueryui.com
  3153. *
  3154. * Copyright jQuery Foundation and other contributors
  3155. * Released under the MIT license.
  3156. * http://jquery.org/license
  3157. */
  3158. //>>label: Autocomplete
  3159. //>>group: Widgets
  3160. //>>description: Lists suggested words as the user is typing.
  3161. //>>docs: http://api.jqueryui.com/autocomplete/
  3162. //>>demos: http://jqueryui.com/autocomplete/
  3163. //>>css.structure: ../../themes/base/core.css
  3164. //>>css.structure: ../../themes/base/autocomplete.css
  3165. //>>css.theme: ../../themes/base/theme.css
  3166. $.widget( "ui.autocomplete", {
  3167. version: "1.12.1",
  3168. defaultElement: "<input>",
  3169. options: {
  3170. appendTo: null,
  3171. autoFocus: false,
  3172. delay: 300,
  3173. minLength: 1,
  3174. position: {
  3175. my: "left top",
  3176. at: "left bottom",
  3177. collision: "none"
  3178. },
  3179. source: null,
  3180. // Callbacks
  3181. change: null,
  3182. close: null,
  3183. focus: null,
  3184. open: null,
  3185. response: null,
  3186. search: null,
  3187. select: null
  3188. },
  3189. requestIndex: 0,
  3190. pending: 0,
  3191. _create: function() {
  3192. // Some browsers only repeat keydown events, not keypress events,
  3193. // so we use the suppressKeyPress flag to determine if we've already
  3194. // handled the keydown event. #7269
  3195. // Unfortunately the code for & in keypress is the same as the up arrow,
  3196. // so we use the suppressKeyPressRepeat flag to avoid handling keypress
  3197. // events when we know the keydown event was used to modify the
  3198. // search term. #7799
  3199. var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
  3200. nodeName = this.element[ 0 ].nodeName.toLowerCase(),
  3201. isTextarea = nodeName === "textarea",
  3202. isInput = nodeName === "input";
  3203. // Textareas are always multi-line
  3204. // Inputs are always single-line, even if inside a contentEditable element
  3205. // IE also treats inputs as contentEditable
  3206. // All other element types are determined by whether or not they're contentEditable
  3207. this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
  3208. this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
  3209. this.isNewMenu = true;
  3210. this._addClass( "ui-autocomplete-input" );
  3211. this.element.attr( "autocomplete", "off" );
  3212. this._on( this.element, {
  3213. keydown: function( event ) {
  3214. if ( this.element.prop( "readOnly" ) ) {
  3215. suppressKeyPress = true;
  3216. suppressInput = true;
  3217. suppressKeyPressRepeat = true;
  3218. return;
  3219. }
  3220. suppressKeyPress = false;
  3221. suppressInput = false;
  3222. suppressKeyPressRepeat = false;
  3223. var keyCode = $.ui.keyCode;
  3224. switch ( event.keyCode ) {
  3225. case keyCode.PAGE_UP:
  3226. suppressKeyPress = true;
  3227. this._move( "previousPage", event );
  3228. break;
  3229. case keyCode.PAGE_DOWN:
  3230. suppressKeyPress = true;
  3231. this._move( "nextPage", event );
  3232. break;
  3233. case keyCode.UP:
  3234. suppressKeyPress = true;
  3235. this._keyEvent( "previous", event );
  3236. break;
  3237. case keyCode.DOWN:
  3238. suppressKeyPress = true;
  3239. this._keyEvent( "next", event );
  3240. break;
  3241. case keyCode.ENTER:
  3242. // when menu is open and has focus
  3243. if ( this.menu.active ) {
  3244. // #6055 - Opera still allows the keypress to occur
  3245. // which causes forms to submit
  3246. suppressKeyPress = true;
  3247. event.preventDefault();
  3248. this.menu.select( event );
  3249. }
  3250. break;
  3251. case keyCode.TAB:
  3252. if ( this.menu.active ) {
  3253. this.menu.select( event );
  3254. }
  3255. break;
  3256. case keyCode.ESCAPE:
  3257. if ( this.menu.element.is( ":visible" ) ) {
  3258. if ( !this.isMultiLine ) {
  3259. this._value( this.term );
  3260. }
  3261. this.close( event );
  3262. // Different browsers have different default behavior for escape
  3263. // Single press can mean undo or clear
  3264. // Double press in IE means clear the whole form
  3265. event.preventDefault();
  3266. }
  3267. break;
  3268. default:
  3269. suppressKeyPressRepeat = true;
  3270. // search timeout should be triggered before the input value is changed
  3271. this._searchTimeout( event );
  3272. break;
  3273. }
  3274. },
  3275. keypress: function( event ) {
  3276. if ( suppressKeyPress ) {
  3277. suppressKeyPress = false;
  3278. if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
  3279. event.preventDefault();
  3280. }
  3281. return;
  3282. }
  3283. if ( suppressKeyPressRepeat ) {
  3284. return;
  3285. }
  3286. // Replicate some key handlers to allow them to repeat in Firefox and Opera
  3287. var keyCode = $.ui.keyCode;
  3288. switch ( event.keyCode ) {
  3289. case keyCode.PAGE_UP:
  3290. this._move( "previousPage", event );
  3291. break;
  3292. case keyCode.PAGE_DOWN:
  3293. this._move( "nextPage", event );
  3294. break;
  3295. case keyCode.UP:
  3296. this._keyEvent( "previous", event );
  3297. break;
  3298. case keyCode.DOWN:
  3299. this._keyEvent( "next", event );
  3300. break;
  3301. }
  3302. },
  3303. input: function( event ) {
  3304. if ( suppressInput ) {
  3305. suppressInput = false;
  3306. event.preventDefault();
  3307. return;
  3308. }
  3309. this._searchTimeout( event );
  3310. },
  3311. focus: function() {
  3312. this.selectedItem = null;
  3313. this.previous = this._value();
  3314. },
  3315. blur: function( event ) {
  3316. if ( this.cancelBlur ) {
  3317. delete this.cancelBlur;
  3318. return;
  3319. }
  3320. clearTimeout( this.searching );
  3321. this.close( event );
  3322. this._change( event );
  3323. }
  3324. } );
  3325. this._initSource();
  3326. this.menu = $( "<ul>" )
  3327. .appendTo( this._appendTo() )
  3328. .menu( {
  3329. // disable ARIA support, the live region takes care of that
  3330. role: null
  3331. } )
  3332. .hide()
  3333. .menu( "instance" );
  3334. this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
  3335. this._on( this.menu.element, {
  3336. mousedown: function( event ) {
  3337. // prevent moving focus out of the text field
  3338. event.preventDefault();
  3339. // IE doesn't prevent moving focus even with event.preventDefault()
  3340. // so we set a flag to know when we should ignore the blur event
  3341. this.cancelBlur = true;
  3342. this._delay( function() {
  3343. delete this.cancelBlur;
  3344. // Support: IE 8 only
  3345. // Right clicking a menu item or selecting text from the menu items will
  3346. // result in focus moving out of the input. However, we've already received
  3347. // and ignored the blur event because of the cancelBlur flag set above. So
  3348. // we restore focus to ensure that the menu closes properly based on the user's
  3349. // next actions.
  3350. if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
  3351. this.element.trigger( "focus" );
  3352. }
  3353. } );
  3354. },
  3355. menufocus: function( event, ui ) {
  3356. var label, item;
  3357. // support: Firefox
  3358. // Prevent accidental activation of menu items in Firefox (#7024 #9118)
  3359. if ( this.isNewMenu ) {
  3360. this.isNewMenu = false;
  3361. if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
  3362. this.menu.blur();
  3363. this.document.one( "mousemove", function() {
  3364. $( event.target ).trigger( event.originalEvent );
  3365. } );
  3366. return;
  3367. }
  3368. }
  3369. item = ui.item.data( "ui-autocomplete-item" );
  3370. if ( false !== this._trigger( "focus", event, { item: item } ) ) {
  3371. // use value to match what will end up in the input, if it was a key event
  3372. if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
  3373. this._value( item.value );
  3374. }
  3375. }
  3376. // Announce the value in the liveRegion
  3377. label = ui.item.attr( "aria-label" ) || item.value;
  3378. if ( label && $.trim( label ).length ) {
  3379. this.liveRegion.children().hide();
  3380. $( "<div>" ).text( label ).appendTo( this.liveRegion );
  3381. }
  3382. },
  3383. menuselect: function( event, ui ) {
  3384. var item = ui.item.data( "ui-autocomplete-item" ),
  3385. previous = this.previous;
  3386. // Only trigger when focus was lost (click on menu)
  3387. if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
  3388. this.element.trigger( "focus" );
  3389. this.previous = previous;
  3390. // #6109 - IE triggers two focus events and the second
  3391. // is asynchronous, so we need to reset the previous
  3392. // term synchronously and asynchronously :-(
  3393. this._delay( function() {
  3394. this.previous = previous;
  3395. this.selectedItem = item;
  3396. } );
  3397. }
  3398. if ( false !== this._trigger( "select", event, { item: item } ) ) {
  3399. this._value( item.value );
  3400. }
  3401. // reset the term after the select event
  3402. // this allows custom select handling to work properly
  3403. this.term = this._value();
  3404. this.close( event );
  3405. this.selectedItem = item;
  3406. }
  3407. } );
  3408. this.liveRegion = $( "<div>", {
  3409. role: "status",
  3410. "aria-live": "assertive",
  3411. "aria-relevant": "additions"
  3412. } )
  3413. .appendTo( this.document[ 0 ].body );
  3414. this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
  3415. // Turning off autocomplete prevents the browser from remembering the
  3416. // value when navigating through history, so we re-enable autocomplete
  3417. // if the page is unloaded before the widget is destroyed. #7790
  3418. this._on( this.window, {
  3419. beforeunload: function() {
  3420. this.element.removeAttr( "autocomplete" );
  3421. }
  3422. } );
  3423. },
  3424. _destroy: function() {
  3425. clearTimeout( this.searching );
  3426. this.element.removeAttr( "autocomplete" );
  3427. this.menu.element.remove();
  3428. this.liveRegion.remove();
  3429. },
  3430. _setOption: function( key, value ) {
  3431. this._super( key, value );
  3432. if ( key === "source" ) {
  3433. this._initSource();
  3434. }
  3435. if ( key === "appendTo" ) {
  3436. this.menu.element.appendTo( this._appendTo() );
  3437. }
  3438. if ( key === "disabled" && value && this.xhr ) {
  3439. this.xhr.abort();
  3440. }
  3441. },
  3442. _isEventTargetInWidget: function( event ) {
  3443. var menuElement = this.menu.element[ 0 ];
  3444. return event.target === this.element[ 0 ] ||
  3445. event.target === menuElement ||
  3446. $.contains( menuElement, event.target );
  3447. },
  3448. _closeOnClickOutside: function( event ) {
  3449. if ( !this._isEventTargetInWidget( event ) ) {
  3450. this.close();
  3451. }
  3452. },
  3453. _appendTo: function() {
  3454. var element = this.options.appendTo;
  3455. if ( element ) {
  3456. element = element.jquery || element.nodeType ?
  3457. $( element ) :
  3458. this.document.find( element ).eq( 0 );
  3459. }
  3460. if ( !element || !element[ 0 ] ) {
  3461. element = this.element.closest( ".ui-front, dialog" );
  3462. }
  3463. if ( !element.length ) {
  3464. element = this.document[ 0 ].body;
  3465. }
  3466. return element;
  3467. },
  3468. _initSource: function() {
  3469. var array, url,
  3470. that = this;
  3471. if ( $.isArray( this.options.source ) ) {
  3472. array = this.options.source;
  3473. this.source = function( request, response ) {
  3474. response( $.ui.autocomplete.filter( array, request.term ) );
  3475. };
  3476. } else if ( typeof this.options.source === "string" ) {
  3477. url = this.options.source;
  3478. this.source = function( request, response ) {
  3479. if ( that.xhr ) {
  3480. that.xhr.abort();
  3481. }
  3482. that.xhr = $.ajax( {
  3483. url: url,
  3484. data: request,
  3485. dataType: "json",
  3486. success: function( data ) {
  3487. response( data );
  3488. },
  3489. error: function() {
  3490. response( [] );
  3491. }
  3492. } );
  3493. };
  3494. } else {
  3495. this.source = this.options.source;
  3496. }
  3497. },
  3498. _searchTimeout: function( event ) {
  3499. clearTimeout( this.searching );
  3500. this.searching = this._delay( function() {
  3501. // Search if the value has changed, or if the user retypes the same value (see #7434)
  3502. var equalValues = this.term === this._value(),
  3503. menuVisible = this.menu.element.is( ":visible" ),
  3504. modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
  3505. if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
  3506. this.selectedItem = null;
  3507. this.search( null, event );
  3508. }
  3509. }, this.options.delay );
  3510. },
  3511. search: function( value, event ) {
  3512. value = value != null ? value : this._value();
  3513. // Always save the actual value, not the one passed as an argument
  3514. this.term = this._value();
  3515. if ( value.length < this.options.minLength ) {
  3516. return this.close( event );
  3517. }
  3518. if ( this._trigger( "search", event ) === false ) {
  3519. return;
  3520. }
  3521. return this._search( value );
  3522. },
  3523. _search: function( value ) {
  3524. this.pending++;
  3525. this._addClass( "ui-autocomplete-loading" );
  3526. this.cancelSearch = false;
  3527. this.source( { term: value }, this._response() );
  3528. },
  3529. _response: function() {
  3530. var index = ++this.requestIndex;
  3531. return $.proxy( function( content ) {
  3532. if ( index === this.requestIndex ) {
  3533. this.__response( content );
  3534. }
  3535. this.pending--;
  3536. if ( !this.pending ) {
  3537. this._removeClass( "ui-autocomplete-loading" );
  3538. }
  3539. }, this );
  3540. },
  3541. __response: function( content ) {
  3542. if ( content ) {
  3543. content = this._normalize( content );
  3544. }
  3545. this._trigger( "response", null, { content: content } );
  3546. if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
  3547. this._suggest( content );
  3548. this._trigger( "open" );
  3549. } else {
  3550. // use ._close() instead of .close() so we don't cancel future searches
  3551. this._close();
  3552. }
  3553. },
  3554. close: function( event ) {
  3555. this.cancelSearch = true;
  3556. this._close( event );
  3557. },
  3558. _close: function( event ) {
  3559. // Remove the handler that closes the menu on outside clicks
  3560. this._off( this.document, "mousedown" );
  3561. if ( this.menu.element.is( ":visible" ) ) {
  3562. this.menu.element.hide();
  3563. this.menu.blur();
  3564. this.isNewMenu = true;
  3565. this._trigger( "close", event );
  3566. }
  3567. },
  3568. _change: function( event ) {
  3569. if ( this.previous !== this._value() ) {
  3570. this._trigger( "change", event, { item: this.selectedItem } );
  3571. }
  3572. },
  3573. _normalize: function( items ) {
  3574. // assume all items have the right format when the first item is complete
  3575. if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
  3576. return items;
  3577. }
  3578. return $.map( items, function( item ) {
  3579. if ( typeof item === "string" ) {
  3580. return {
  3581. label: item,
  3582. value: item
  3583. };
  3584. }
  3585. return $.extend( {}, item, {
  3586. label: item.label || item.value,
  3587. value: item.value || item.label
  3588. } );
  3589. } );
  3590. },
  3591. _suggest: function( items ) {
  3592. var ul = this.menu.element.empty();
  3593. this._renderMenu( ul, items );
  3594. this.isNewMenu = true;
  3595. this.menu.refresh();
  3596. // Size and position menu
  3597. ul.show();
  3598. this._resizeMenu();
  3599. ul.position( $.extend( {
  3600. of: this.element
  3601. }, this.options.position ) );
  3602. if ( this.options.autoFocus ) {
  3603. this.menu.next();
  3604. }
  3605. // Listen for interactions outside of the widget (#6642)
  3606. this._on( this.document, {
  3607. mousedown: "_closeOnClickOutside"
  3608. } );
  3609. },
  3610. _resizeMenu: function() {
  3611. var ul = this.menu.element;
  3612. ul.outerWidth( Math.max(
  3613. // Firefox wraps long text (possibly a rounding bug)
  3614. // so we add 1px to avoid the wrapping (#7513)
  3615. ul.width( "" ).outerWidth() + 1,
  3616. this.element.outerWidth()
  3617. ) );
  3618. },
  3619. _renderMenu: function( ul, items ) {
  3620. var that = this;
  3621. $.each( items, function( index, item ) {
  3622. that._renderItemData( ul, item );
  3623. } );
  3624. },
  3625. _renderItemData: function( ul, item ) {
  3626. return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
  3627. },
  3628. _renderItem: function( ul, item ) {
  3629. return $( "<li>" )
  3630. .append( $( "<div>" ).text( item.label ) )
  3631. .appendTo( ul );
  3632. },
  3633. _move: function( direction, event ) {
  3634. if ( !this.menu.element.is( ":visible" ) ) {
  3635. this.search( null, event );
  3636. return;
  3637. }
  3638. if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
  3639. this.menu.isLastItem() && /^next/.test( direction ) ) {
  3640. if ( !this.isMultiLine ) {
  3641. this._value( this.term );
  3642. }
  3643. this.menu.blur();
  3644. return;
  3645. }
  3646. this.menu[ direction ]( event );
  3647. },
  3648. widget: function() {
  3649. return this.menu.element;
  3650. },
  3651. _value: function() {
  3652. return this.valueMethod.apply( this.element, arguments );
  3653. },
  3654. _keyEvent: function( keyEvent, event ) {
  3655. if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
  3656. this._move( keyEvent, event );
  3657. // Prevents moving cursor to beginning/end of the text field in some browsers
  3658. event.preventDefault();
  3659. }
  3660. },
  3661. // Support: Chrome <=50
  3662. // We should be able to just use this.element.prop( "isContentEditable" )
  3663. // but hidden elements always report false in Chrome.
  3664. // https://code.google.com/p/chromium/issues/detail?id=313082
  3665. _isContentEditable: function( element ) {
  3666. if ( !element.length ) {
  3667. return false;
  3668. }
  3669. var editable = element.prop( "contentEditable" );
  3670. if ( editable === "inherit" ) {
  3671. return this._isContentEditable( element.parent() );
  3672. }
  3673. return editable === "true";
  3674. }
  3675. } );
  3676. $.extend( $.ui.autocomplete, {
  3677. escapeRegex: function( value ) {
  3678. return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
  3679. },
  3680. filter: function( array, term ) {
  3681. var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
  3682. return $.grep( array, function( value ) {
  3683. return matcher.test( value.label || value.value || value );
  3684. } );
  3685. }
  3686. } );
  3687. // Live region extension, adding a `messages` option
  3688. // NOTE: This is an experimental API. We are still investigating
  3689. // a full solution for string manipulation and internationalization.
  3690. $.widget( "ui.autocomplete", $.ui.autocomplete, {
  3691. options: {
  3692. messages: {
  3693. noResults: "No search results.",
  3694. results: function( amount ) {
  3695. return amount + ( amount > 1 ? " results are" : " result is" ) +
  3696. " available, use up and down arrow keys to navigate.";
  3697. }
  3698. }
  3699. },
  3700. __response: function( content ) {
  3701. var message;
  3702. this._superApply( arguments );
  3703. if ( this.options.disabled || this.cancelSearch ) {
  3704. return;
  3705. }
  3706. if ( content && content.length ) {
  3707. message = this.options.messages.results( content.length );
  3708. } else {
  3709. message = this.options.messages.noResults;
  3710. }
  3711. this.liveRegion.children().hide();
  3712. $( "<div>" ).text( message ).appendTo( this.liveRegion );
  3713. }
  3714. } );
  3715. var widgetsAutocomplete = $.ui.autocomplete;
  3716. // jscs:disable maximumLineLength
  3717. /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
  3718. /*!
  3719. * jQuery UI Datepicker 1.12.1
  3720. * http://jqueryui.com
  3721. *
  3722. * Copyright jQuery Foundation and other contributors
  3723. * Released under the MIT license.
  3724. * http://jquery.org/license
  3725. */
  3726. //>>label: Datepicker
  3727. //>>group: Widgets
  3728. //>>description: Displays a calendar from an input or inline for selecting dates.
  3729. //>>docs: http://api.jqueryui.com/datepicker/
  3730. //>>demos: http://jqueryui.com/datepicker/
  3731. //>>css.structure: ../../themes/base/core.css
  3732. //>>css.structure: ../../themes/base/datepicker.css
  3733. //>>css.theme: ../../themes/base/theme.css
  3734. $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
  3735. var datepicker_instActive;
  3736. function datepicker_getZindex( elem ) {
  3737. var position, value;
  3738. while ( elem.length && elem[ 0 ] !== document ) {
  3739. // Ignore z-index if position is set to a value where z-index is ignored by the browser
  3740. // This makes behavior of this function consistent across browsers
  3741. // WebKit always returns auto if the element is positioned
  3742. position = elem.css( "position" );
  3743. if ( position === "absolute" || position === "relative" || position === "fixed" ) {
  3744. // IE returns 0 when zIndex is not specified
  3745. // other browsers return a string
  3746. // we ignore the case of nested elements with an explicit value of 0
  3747. // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
  3748. value = parseInt( elem.css( "zIndex" ), 10 );
  3749. if ( !isNaN( value ) && value !== 0 ) {
  3750. return value;
  3751. }
  3752. }
  3753. elem = elem.parent();
  3754. }
  3755. return 0;
  3756. }
  3757. /* Date picker manager.
  3758. Use the singleton instance of this class, $.datepicker, to interact with the date picker.
  3759. Settings for (groups of) date pickers are maintained in an instance object,
  3760. allowing multiple different settings on the same page. */
  3761. function Datepicker() {
  3762. this._curInst = null; // The current instance in use
  3763. this._keyEvent = false; // If the last event was a key event
  3764. this._disabledInputs = []; // List of date picker inputs that have been disabled
  3765. this._datepickerShowing = false; // True if the popup picker is showing , false if not
  3766. this._inDialog = false; // True if showing within a "dialog", false if not
  3767. this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
  3768. this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
  3769. this._appendClass = "ui-datepicker-append"; // The name of the append marker class
  3770. this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
  3771. this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
  3772. this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
  3773. this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
  3774. this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
  3775. this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
  3776. this.regional = []; // Available regional settings, indexed by language code
  3777. this.regional[ "" ] = { // Default regional settings
  3778. closeText: "Done", // Display text for close link
  3779. prevText: "Prev", // Display text for previous month link
  3780. nextText: "Next", // Display text for next month link
  3781. currentText: "Today", // Display text for current month link
  3782. monthNames: [ "January","February","March","April","May","June",
  3783. "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
  3784. monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
  3785. dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
  3786. dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
  3787. dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
  3788. weekHeader: "Wk", // Column header for week of the year
  3789. dateFormat: "mm/dd/yy", // See format options on parseDate
  3790. firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
  3791. isRTL: false, // True if right-to-left language, false if left-to-right
  3792. showMonthAfterYear: false, // True if the year select precedes month, false for month then year
  3793. yearSuffix: "" // Additional text to append to the year in the month headers
  3794. };
  3795. this._defaults = { // Global defaults for all the date picker instances
  3796. showOn: "focus", // "focus" for popup on focus,
  3797. // "button" for trigger button, or "both" for either
  3798. showAnim: "fadeIn", // Name of jQuery animation for popup
  3799. showOptions: {}, // Options for enhanced animations
  3800. defaultDate: null, // Used when field is blank: actual date,
  3801. // +/-number for offset from today, null for today
  3802. appendText: "", // Display text following the input box, e.g. showing the format
  3803. buttonText: "...", // Text for trigger button
  3804. buttonImage: "", // URL for trigger button image
  3805. buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
  3806. hideIfNoPrevNext: false, // True to hide next/previous month links
  3807. // if not applicable, false to just disable them
  3808. navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
  3809. gotoCurrent: false, // True if today link goes back to current selection instead
  3810. changeMonth: false, // True if month can be selected directly, false if only prev/next
  3811. changeYear: false, // True if year can be selected directly, false if only prev/next
  3812. yearRange: "c-10:c+10", // Range of years to display in drop-down,
  3813. // either relative to today's year (-nn:+nn), relative to currently displayed year
  3814. // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
  3815. showOtherMonths: false, // True to show dates in other months, false to leave blank
  3816. selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
  3817. showWeek: false, // True to show week of the year, false to not show it
  3818. calculateWeek: this.iso8601Week, // How to calculate the week of the year,
  3819. // takes a Date and returns the number of the week for it
  3820. shortYearCutoff: "+10", // Short year values < this are in the current century,
  3821. // > this are in the previous century,
  3822. // string value starting with "+" for current year + value
  3823. minDate: null, // The earliest selectable date, or null for no limit
  3824. maxDate: null, // The latest selectable date, or null for no limit
  3825. duration: "fast", // Duration of display/closure
  3826. beforeShowDay: null, // Function that takes a date and returns an array with
  3827. // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
  3828. // [2] = cell title (optional), e.g. $.datepicker.noWeekends
  3829. beforeShow: null, // Function that takes an input field and
  3830. // returns a set of custom settings for the date picker
  3831. onSelect: null, // Define a callback function when a date is selected
  3832. onChangeMonthYear: null, // Define a callback function when the month or year is changed
  3833. onClose: null, // Define a callback function when the datepicker is closed
  3834. numberOfMonths: 1, // Number of months to show at a time
  3835. showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
  3836. stepMonths: 1, // Number of months to step back/forward
  3837. stepBigMonths: 12, // Number of months to step back/forward for the big links
  3838. altField: "", // Selector for an alternate field to store selected dates into
  3839. altFormat: "", // The date format to use for the alternate field
  3840. constrainInput: true, // The input is constrained by the current date format
  3841. showButtonPanel: false, // True to show button panel, false to not show it
  3842. autoSize: false, // True to size the input for the date format, false to leave as is
  3843. disabled: false // The initial disabled state
  3844. };
  3845. $.extend( this._defaults, this.regional[ "" ] );
  3846. this.regional.en = $.extend( true, {}, this.regional[ "" ] );
  3847. this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
  3848. this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
  3849. }
  3850. $.extend( Datepicker.prototype, {
  3851. /* Class name added to elements to indicate already configured with a date picker. */
  3852. markerClassName: "hasDatepicker",
  3853. //Keep track of the maximum number of rows displayed (see #7043)
  3854. maxRows: 4,
  3855. // TODO rename to "widget" when switching to widget factory
  3856. _widgetDatepicker: function() {
  3857. return this.dpDiv;
  3858. },
  3859. /* Override the default settings for all instances of the date picker.
  3860. * @param settings object - the new settings to use as defaults (anonymous object)
  3861. * @return the manager object
  3862. */
  3863. setDefaults: function( settings ) {
  3864. datepicker_extendRemove( this._defaults, settings || {} );
  3865. return this;
  3866. },
  3867. /* Attach the date picker to a jQuery selection.
  3868. * @param target element - the target input field or division or span
  3869. * @param settings object - the new settings to use for this date picker instance (anonymous)
  3870. */
  3871. _attachDatepicker: function( target, settings ) {
  3872. var nodeName, inline, inst;
  3873. nodeName = target.nodeName.toLowerCase();
  3874. inline = ( nodeName === "div" || nodeName === "span" );
  3875. if ( !target.id ) {
  3876. this.uuid += 1;
  3877. target.id = "dp" + this.uuid;
  3878. }
  3879. inst = this._newInst( $( target ), inline );
  3880. inst.settings = $.extend( {}, settings || {} );
  3881. if ( nodeName === "input" ) {
  3882. this._connectDatepicker( target, inst );
  3883. } else if ( inline ) {
  3884. this._inlineDatepicker( target, inst );
  3885. }
  3886. },
  3887. /* Create a new instance object. */
  3888. _newInst: function( target, inline ) {
  3889. var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
  3890. return { id: id, input: target, // associated target
  3891. selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
  3892. drawMonth: 0, drawYear: 0, // month being drawn
  3893. inline: inline, // is datepicker inline or not
  3894. dpDiv: ( !inline ? this.dpDiv : // presentation div
  3895. datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
  3896. },
  3897. /* Attach the date picker to an input field. */
  3898. _connectDatepicker: function( target, inst ) {
  3899. var input = $( target );
  3900. inst.append = $( [] );
  3901. inst.trigger = $( [] );
  3902. if ( input.hasClass( this.markerClassName ) ) {
  3903. return;
  3904. }
  3905. this._attachments( input, inst );
  3906. input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
  3907. on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
  3908. this._autoSize( inst );
  3909. $.data( target, "datepicker", inst );
  3910. //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
  3911. if ( inst.settings.disabled ) {
  3912. this._disableDatepicker( target );
  3913. }
  3914. },
  3915. /* Make attachments based on settings. */
  3916. _attachments: function( input, inst ) {
  3917. var showOn, buttonText, buttonImage,
  3918. appendText = this._get( inst, "appendText" ),
  3919. isRTL = this._get( inst, "isRTL" );
  3920. if ( inst.append ) {
  3921. inst.append.remove();
  3922. }
  3923. if ( appendText ) {
  3924. inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
  3925. input[ isRTL ? "before" : "after" ]( inst.append );
  3926. }
  3927. input.off( "focus", this._showDatepicker );
  3928. if ( inst.trigger ) {
  3929. inst.trigger.remove();
  3930. }
  3931. showOn = this._get( inst, "showOn" );
  3932. if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
  3933. input.on( "focus", this._showDatepicker );
  3934. }
  3935. if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
  3936. buttonText = this._get( inst, "buttonText" );
  3937. buttonImage = this._get( inst, "buttonImage" );
  3938. inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
  3939. $( "<img/>" ).addClass( this._triggerClass ).
  3940. attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
  3941. $( "<button type='button'></button>" ).addClass( this._triggerClass ).
  3942. html( !buttonImage ? buttonText : $( "<img/>" ).attr(
  3943. { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
  3944. input[ isRTL ? "before" : "after" ]( inst.trigger );
  3945. inst.trigger.on( "click", function() {
  3946. if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
  3947. $.datepicker._hideDatepicker();
  3948. } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
  3949. $.datepicker._hideDatepicker();
  3950. $.datepicker._showDatepicker( input[ 0 ] );
  3951. } else {
  3952. $.datepicker._showDatepicker( input[ 0 ] );
  3953. }
  3954. return false;
  3955. } );
  3956. }
  3957. },
  3958. /* Apply the maximum length for the date format. */
  3959. _autoSize: function( inst ) {
  3960. if ( this._get( inst, "autoSize" ) && !inst.inline ) {
  3961. var findMax, max, maxI, i,
  3962. date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
  3963. dateFormat = this._get( inst, "dateFormat" );
  3964. if ( dateFormat.match( /[DM]/ ) ) {
  3965. findMax = function( names ) {
  3966. max = 0;
  3967. maxI = 0;
  3968. for ( i = 0; i < names.length; i++ ) {
  3969. if ( names[ i ].length > max ) {
  3970. max = names[ i ].length;
  3971. maxI = i;
  3972. }
  3973. }
  3974. return maxI;
  3975. };
  3976. date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
  3977. "monthNames" : "monthNamesShort" ) ) ) );
  3978. date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
  3979. "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
  3980. }
  3981. inst.input.attr( "size", this._formatDate( inst, date ).length );
  3982. }
  3983. },
  3984. /* Attach an inline date picker to a div. */
  3985. _inlineDatepicker: function( target, inst ) {
  3986. var divSpan = $( target );
  3987. if ( divSpan.hasClass( this.markerClassName ) ) {
  3988. return;
  3989. }
  3990. divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
  3991. $.data( target, "datepicker", inst );
  3992. this._setDate( inst, this._getDefaultDate( inst ), true );
  3993. this._updateDatepicker( inst );
  3994. this._updateAlternate( inst );
  3995. //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
  3996. if ( inst.settings.disabled ) {
  3997. this._disableDatepicker( target );
  3998. }
  3999. // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
  4000. // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
  4001. inst.dpDiv.css( "display", "block" );
  4002. },
  4003. /* Pop-up the date picker in a "dialog" box.
  4004. * @param input element - ignored
  4005. * @param date string or Date - the initial date to display
  4006. * @param onSelect function - the function to call when a date is selected
  4007. * @param settings object - update the dialog date picker instance's settings (anonymous object)
  4008. * @param pos int[2] - coordinates for the dialog's position within the screen or
  4009. * event - with x/y coordinates or
  4010. * leave empty for default (screen centre)
  4011. * @return the manager object
  4012. */
  4013. _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
  4014. var id, browserWidth, browserHeight, scrollX, scrollY,
  4015. inst = this._dialogInst; // internal instance
  4016. if ( !inst ) {
  4017. this.uuid += 1;
  4018. id = "dp" + this.uuid;
  4019. this._dialogInput = $( "<input type='text' id='" + id +
  4020. "' style='position: absolute; top: -100px; width: 0px;'/>" );
  4021. this._dialogInput.on( "keydown", this._doKeyDown );
  4022. $( "body" ).append( this._dialogInput );
  4023. inst = this._dialogInst = this._newInst( this._dialogInput, false );
  4024. inst.settings = {};
  4025. $.data( this._dialogInput[ 0 ], "datepicker", inst );
  4026. }
  4027. datepicker_extendRemove( inst.settings, settings || {} );
  4028. date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
  4029. this._dialogInput.val( date );
  4030. this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
  4031. if ( !this._pos ) {
  4032. browserWidth = document.documentElement.clientWidth;
  4033. browserHeight = document.documentElement.clientHeight;
  4034. scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
  4035. scrollY = document.documentElement.scrollTop || document.body.scrollTop;
  4036. this._pos = // should use actual width/height below
  4037. [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
  4038. }
  4039. // Move input on screen for focus, but hidden behind dialog
  4040. this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
  4041. inst.settings.onSelect = onSelect;
  4042. this._inDialog = true;
  4043. this.dpDiv.addClass( this._dialogClass );
  4044. this._showDatepicker( this._dialogInput[ 0 ] );
  4045. if ( $.blockUI ) {
  4046. $.blockUI( this.dpDiv );
  4047. }
  4048. $.data( this._dialogInput[ 0 ], "datepicker", inst );
  4049. return this;
  4050. },
  4051. /* Detach a datepicker from its control.
  4052. * @param target element - the target input field or division or span
  4053. */
  4054. _destroyDatepicker: function( target ) {
  4055. var nodeName,
  4056. $target = $( target ),
  4057. inst = $.data( target, "datepicker" );
  4058. if ( !$target.hasClass( this.markerClassName ) ) {
  4059. return;
  4060. }
  4061. nodeName = target.nodeName.toLowerCase();
  4062. $.removeData( target, "datepicker" );
  4063. if ( nodeName === "input" ) {
  4064. inst.append.remove();
  4065. inst.trigger.remove();
  4066. $target.removeClass( this.markerClassName ).
  4067. off( "focus", this._showDatepicker ).
  4068. off( "keydown", this._doKeyDown ).
  4069. off( "keypress", this._doKeyPress ).
  4070. off( "keyup", this._doKeyUp );
  4071. } else if ( nodeName === "div" || nodeName === "span" ) {
  4072. $target.removeClass( this.markerClassName ).empty();
  4073. }
  4074. if ( datepicker_instActive === inst ) {
  4075. datepicker_instActive = null;
  4076. }
  4077. },
  4078. /* Enable the date picker to a jQuery selection.
  4079. * @param target element - the target input field or division or span
  4080. */
  4081. _enableDatepicker: function( target ) {
  4082. var nodeName, inline,
  4083. $target = $( target ),
  4084. inst = $.data( target, "datepicker" );
  4085. if ( !$target.hasClass( this.markerClassName ) ) {
  4086. return;
  4087. }
  4088. nodeName = target.nodeName.toLowerCase();
  4089. if ( nodeName === "input" ) {
  4090. target.disabled = false;
  4091. inst.trigger.filter( "button" ).
  4092. each( function() { this.disabled = false; } ).end().
  4093. filter( "img" ).css( { opacity: "1.0", cursor: "" } );
  4094. } else if ( nodeName === "div" || nodeName === "span" ) {
  4095. inline = $target.children( "." + this._inlineClass );
  4096. inline.children().removeClass( "ui-state-disabled" );
  4097. inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
  4098. prop( "disabled", false );
  4099. }
  4100. this._disabledInputs = $.map( this._disabledInputs,
  4101. function( value ) { return ( value === target ? null : value ); } ); // delete entry
  4102. },
  4103. /* Disable the date picker to a jQuery selection.
  4104. * @param target element - the target input field or division or span
  4105. */
  4106. _disableDatepicker: function( target ) {
  4107. var nodeName, inline,
  4108. $target = $( target ),
  4109. inst = $.data( target, "datepicker" );
  4110. if ( !$target.hasClass( this.markerClassName ) ) {
  4111. return;
  4112. }
  4113. nodeName = target.nodeName.toLowerCase();
  4114. if ( nodeName === "input" ) {
  4115. target.disabled = true;
  4116. inst.trigger.filter( "button" ).
  4117. each( function() { this.disabled = true; } ).end().
  4118. filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
  4119. } else if ( nodeName === "div" || nodeName === "span" ) {
  4120. inline = $target.children( "." + this._inlineClass );
  4121. inline.children().addClass( "ui-state-disabled" );
  4122. inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
  4123. prop( "disabled", true );
  4124. }
  4125. this._disabledInputs = $.map( this._disabledInputs,
  4126. function( value ) { return ( value === target ? null : value ); } ); // delete entry
  4127. this._disabledInputs[ this._disabledInputs.length ] = target;
  4128. },
  4129. /* Is the first field in a jQuery collection disabled as a datepicker?
  4130. * @param target element - the target input field or division or span
  4131. * @return boolean - true if disabled, false if enabled
  4132. */
  4133. _isDisabledDatepicker: function( target ) {
  4134. if ( !target ) {
  4135. return false;
  4136. }
  4137. for ( var i = 0; i < this._disabledInputs.length; i++ ) {
  4138. if ( this._disabledInputs[ i ] === target ) {
  4139. return true;
  4140. }
  4141. }
  4142. return false;
  4143. },
  4144. /* Retrieve the instance data for the target control.
  4145. * @param target element - the target input field or division or span
  4146. * @return object - the associated instance data
  4147. * @throws error if a jQuery problem getting data
  4148. */
  4149. _getInst: function( target ) {
  4150. try {
  4151. return $.data( target, "datepicker" );
  4152. }
  4153. catch ( err ) {
  4154. throw "Missing instance data for this datepicker";
  4155. }
  4156. },
  4157. /* Update or retrieve the settings for a date picker attached to an input field or division.
  4158. * @param target element - the target input field or division or span
  4159. * @param name object - the new settings to update or
  4160. * string - the name of the setting to change or retrieve,
  4161. * when retrieving also "all" for all instance settings or
  4162. * "defaults" for all global defaults
  4163. * @param value any - the new value for the setting
  4164. * (omit if above is an object or to retrieve a value)
  4165. */
  4166. _optionDatepicker: function( target, name, value ) {
  4167. var settings, date, minDate, maxDate,
  4168. inst = this._getInst( target );
  4169. if ( arguments.length === 2 && typeof name === "string" ) {
  4170. return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
  4171. ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
  4172. this._get( inst, name ) ) : null ) );
  4173. }
  4174. settings = name || {};
  4175. if ( typeof name === "string" ) {
  4176. settings = {};
  4177. settings[ name ] = value;
  4178. }
  4179. if ( inst ) {
  4180. if ( this._curInst === inst ) {
  4181. this._hideDatepicker();
  4182. }
  4183. date = this._getDateDatepicker( target, true );
  4184. minDate = this._getMinMaxDate( inst, "min" );
  4185. maxDate = this._getMinMaxDate( inst, "max" );
  4186. datepicker_extendRemove( inst.settings, settings );
  4187. // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
  4188. if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
  4189. inst.settings.minDate = this._formatDate( inst, minDate );
  4190. }
  4191. if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
  4192. inst.settings.maxDate = this._formatDate( inst, maxDate );
  4193. }
  4194. if ( "disabled" in settings ) {
  4195. if ( settings.disabled ) {
  4196. this._disableDatepicker( target );
  4197. } else {
  4198. this._enableDatepicker( target );
  4199. }
  4200. }
  4201. this._attachments( $( target ), inst );
  4202. this._autoSize( inst );
  4203. this._setDate( inst, date );
  4204. this._updateAlternate( inst );
  4205. this._updateDatepicker( inst );
  4206. }
  4207. },
  4208. // Change method deprecated
  4209. _changeDatepicker: function( target, name, value ) {
  4210. this._optionDatepicker( target, name, value );
  4211. },
  4212. /* Redraw the date picker attached to an input field or division.
  4213. * @param target element - the target input field or division or span
  4214. */
  4215. _refreshDatepicker: function( target ) {
  4216. var inst = this._getInst( target );
  4217. if ( inst ) {
  4218. this._updateDatepicker( inst );
  4219. }
  4220. },
  4221. /* Set the dates for a jQuery selection.
  4222. * @param target element - the target input field or division or span
  4223. * @param date Date - the new date
  4224. */
  4225. _setDateDatepicker: function( target, date ) {
  4226. var inst = this._getInst( target );
  4227. if ( inst ) {
  4228. this._setDate( inst, date );
  4229. this._updateDatepicker( inst );
  4230. this._updateAlternate( inst );
  4231. }
  4232. },
  4233. /* Get the date(s) for the first entry in a jQuery selection.
  4234. * @param target element - the target input field or division or span
  4235. * @param noDefault boolean - true if no default date is to be used
  4236. * @return Date - the current date
  4237. */
  4238. _getDateDatepicker: function( target, noDefault ) {
  4239. var inst = this._getInst( target );
  4240. if ( inst && !inst.inline ) {
  4241. this._setDateFromField( inst, noDefault );
  4242. }
  4243. return ( inst ? this._getDate( inst ) : null );
  4244. },
  4245. /* Handle keystrokes. */
  4246. _doKeyDown: function( event ) {
  4247. var onSelect, dateStr, sel,
  4248. inst = $.datepicker._getInst( event.target ),
  4249. handled = true,
  4250. isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
  4251. inst._keyEvent = true;
  4252. if ( $.datepicker._datepickerShowing ) {
  4253. switch ( event.keyCode ) {
  4254. case 9: $.datepicker._hideDatepicker();
  4255. handled = false;
  4256. break; // hide on tab out
  4257. case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
  4258. $.datepicker._currentClass + ")", inst.dpDiv );
  4259. if ( sel[ 0 ] ) {
  4260. $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
  4261. }
  4262. onSelect = $.datepicker._get( inst, "onSelect" );
  4263. if ( onSelect ) {
  4264. dateStr = $.datepicker._formatDate( inst );
  4265. // Trigger custom callback
  4266. onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
  4267. } else {
  4268. $.datepicker._hideDatepicker();
  4269. }
  4270. return false; // don't submit the form
  4271. case 27: $.datepicker._hideDatepicker();
  4272. break; // hide on escape
  4273. case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  4274. -$.datepicker._get( inst, "stepBigMonths" ) :
  4275. -$.datepicker._get( inst, "stepMonths" ) ), "M" );
  4276. break; // previous month/year on page up/+ ctrl
  4277. case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  4278. +$.datepicker._get( inst, "stepBigMonths" ) :
  4279. +$.datepicker._get( inst, "stepMonths" ) ), "M" );
  4280. break; // next month/year on page down/+ ctrl
  4281. case 35: if ( event.ctrlKey || event.metaKey ) {
  4282. $.datepicker._clearDate( event.target );
  4283. }
  4284. handled = event.ctrlKey || event.metaKey;
  4285. break; // clear on ctrl or command +end
  4286. case 36: if ( event.ctrlKey || event.metaKey ) {
  4287. $.datepicker._gotoToday( event.target );
  4288. }
  4289. handled = event.ctrlKey || event.metaKey;
  4290. break; // current on ctrl or command +home
  4291. case 37: if ( event.ctrlKey || event.metaKey ) {
  4292. $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
  4293. }
  4294. handled = event.ctrlKey || event.metaKey;
  4295. // -1 day on ctrl or command +left
  4296. if ( event.originalEvent.altKey ) {
  4297. $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  4298. -$.datepicker._get( inst, "stepBigMonths" ) :
  4299. -$.datepicker._get( inst, "stepMonths" ) ), "M" );
  4300. }
  4301. // next month/year on alt +left on Mac
  4302. break;
  4303. case 38: if ( event.ctrlKey || event.metaKey ) {
  4304. $.datepicker._adjustDate( event.target, -7, "D" );
  4305. }
  4306. handled = event.ctrlKey || event.metaKey;
  4307. break; // -1 week on ctrl or command +up
  4308. case 39: if ( event.ctrlKey || event.metaKey ) {
  4309. $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
  4310. }
  4311. handled = event.ctrlKey || event.metaKey;
  4312. // +1 day on ctrl or command +right
  4313. if ( event.originalEvent.altKey ) {
  4314. $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  4315. +$.datepicker._get( inst, "stepBigMonths" ) :
  4316. +$.datepicker._get( inst, "stepMonths" ) ), "M" );
  4317. }
  4318. // next month/year on alt +right
  4319. break;
  4320. case 40: if ( event.ctrlKey || event.metaKey ) {
  4321. $.datepicker._adjustDate( event.target, +7, "D" );
  4322. }
  4323. handled = event.ctrlKey || event.metaKey;
  4324. break; // +1 week on ctrl or command +down
  4325. default: handled = false;
  4326. }
  4327. } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
  4328. $.datepicker._showDatepicker( this );
  4329. } else {
  4330. handled = false;
  4331. }
  4332. if ( handled ) {
  4333. event.preventDefault();
  4334. event.stopPropagation();
  4335. }
  4336. },
  4337. /* Filter entered characters - based on date format. */
  4338. _doKeyPress: function( event ) {
  4339. var chars, chr,
  4340. inst = $.datepicker._getInst( event.target );
  4341. if ( $.datepicker._get( inst, "constrainInput" ) ) {
  4342. chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
  4343. chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
  4344. return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
  4345. }
  4346. },
  4347. /* Synchronise manual entry and field/alternate field. */
  4348. _doKeyUp: function( event ) {
  4349. var date,
  4350. inst = $.datepicker._getInst( event.target );
  4351. if ( inst.input.val() !== inst.lastVal ) {
  4352. try {
  4353. date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
  4354. ( inst.input ? inst.input.val() : null ),
  4355. $.datepicker._getFormatConfig( inst ) );
  4356. if ( date ) { // only if valid
  4357. $.datepicker._setDateFromField( inst );
  4358. $.datepicker._updateAlternate( inst );
  4359. $.datepicker._updateDatepicker( inst );
  4360. }
  4361. }
  4362. catch ( err ) {
  4363. }
  4364. }
  4365. return true;
  4366. },
  4367. /* Pop-up the date picker for a given input field.
  4368. * If false returned from beforeShow event handler do not show.
  4369. * @param input element - the input field attached to the date picker or
  4370. * event - if triggered by focus
  4371. */
  4372. _showDatepicker: function( input ) {
  4373. input = input.target || input;
  4374. if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
  4375. input = $( "input", input.parentNode )[ 0 ];
  4376. }
  4377. if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
  4378. return;
  4379. }
  4380. var inst, beforeShow, beforeShowSettings, isFixed,
  4381. offset, showAnim, duration;
  4382. inst = $.datepicker._getInst( input );
  4383. if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
  4384. $.datepicker._curInst.dpDiv.stop( true, true );
  4385. if ( inst && $.datepicker._datepickerShowing ) {
  4386. $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
  4387. }
  4388. }
  4389. beforeShow = $.datepicker._get( inst, "beforeShow" );
  4390. beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
  4391. if ( beforeShowSettings === false ) {
  4392. return;
  4393. }
  4394. datepicker_extendRemove( inst.settings, beforeShowSettings );
  4395. inst.lastVal = null;
  4396. $.datepicker._lastInput = input;
  4397. $.datepicker._setDateFromField( inst );
  4398. if ( $.datepicker._inDialog ) { // hide cursor
  4399. input.value = "";
  4400. }
  4401. if ( !$.datepicker._pos ) { // position below input
  4402. $.datepicker._pos = $.datepicker._findPos( input );
  4403. $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
  4404. }
  4405. isFixed = false;
  4406. $( input ).parents().each( function() {
  4407. isFixed |= $( this ).css( "position" ) === "fixed";
  4408. return !isFixed;
  4409. } );
  4410. offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
  4411. $.datepicker._pos = null;
  4412. //to avoid flashes on Firefox
  4413. inst.dpDiv.empty();
  4414. // determine sizing offscreen
  4415. inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
  4416. $.datepicker._updateDatepicker( inst );
  4417. // fix width for dynamic number of date pickers
  4418. // and adjust position before showing
  4419. offset = $.datepicker._checkOffset( inst, offset, isFixed );
  4420. inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
  4421. "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
  4422. left: offset.left + "px", top: offset.top + "px" } );
  4423. if ( !inst.inline ) {
  4424. showAnim = $.datepicker._get( inst, "showAnim" );
  4425. duration = $.datepicker._get( inst, "duration" );
  4426. inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
  4427. $.datepicker._datepickerShowing = true;
  4428. if ( $.effects && $.effects.effect[ showAnim ] ) {
  4429. inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
  4430. } else {
  4431. inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
  4432. }
  4433. if ( $.datepicker._shouldFocusInput( inst ) ) {
  4434. inst.input.trigger( "focus" );
  4435. }
  4436. $.datepicker._curInst = inst;
  4437. }
  4438. },
  4439. /* Generate the date picker content. */
  4440. _updateDatepicker: function( inst ) {
  4441. this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
  4442. datepicker_instActive = inst; // for delegate hover events
  4443. inst.dpDiv.empty().append( this._generateHTML( inst ) );
  4444. this._attachHandlers( inst );
  4445. var origyearshtml,
  4446. numMonths = this._getNumberOfMonths( inst ),
  4447. cols = numMonths[ 1 ],
  4448. width = 17,
  4449. activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
  4450. if ( activeCell.length > 0 ) {
  4451. datepicker_handleMouseover.apply( activeCell.get( 0 ) );
  4452. }
  4453. inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
  4454. if ( cols > 1 ) {
  4455. inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
  4456. }
  4457. inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
  4458. "Class" ]( "ui-datepicker-multi" );
  4459. inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
  4460. "Class" ]( "ui-datepicker-rtl" );
  4461. if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
  4462. inst.input.trigger( "focus" );
  4463. }
  4464. // Deffered render of the years select (to avoid flashes on Firefox)
  4465. if ( inst.yearshtml ) {
  4466. origyearshtml = inst.yearshtml;
  4467. setTimeout( function() {
  4468. //assure that inst.yearshtml didn't change.
  4469. if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
  4470. inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
  4471. }
  4472. origyearshtml = inst.yearshtml = null;
  4473. }, 0 );
  4474. }
  4475. },
  4476. // #6694 - don't focus the input if it's already focused
  4477. // this breaks the change event in IE
  4478. // Support: IE and jQuery <1.9
  4479. _shouldFocusInput: function( inst ) {
  4480. return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
  4481. },
  4482. /* Check positioning to remain on screen. */
  4483. _checkOffset: function( inst, offset, isFixed ) {
  4484. var dpWidth = inst.dpDiv.outerWidth(),
  4485. dpHeight = inst.dpDiv.outerHeight(),
  4486. inputWidth = inst.input ? inst.input.outerWidth() : 0,
  4487. inputHeight = inst.input ? inst.input.outerHeight() : 0,
  4488. viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
  4489. viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
  4490. offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
  4491. offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
  4492. offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
  4493. // Now check if datepicker is showing outside window viewport - move to a better place if so.
  4494. offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
  4495. Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
  4496. offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
  4497. Math.abs( dpHeight + inputHeight ) : 0 );
  4498. return offset;
  4499. },
  4500. /* Find an object's position on the screen. */
  4501. _findPos: function( obj ) {
  4502. var position,
  4503. inst = this._getInst( obj ),
  4504. isRTL = this._get( inst, "isRTL" );
  4505. while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
  4506. obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
  4507. }
  4508. position = $( obj ).offset();
  4509. return [ position.left, position.top ];
  4510. },
  4511. /* Hide the date picker from view.
  4512. * @param input element - the input field attached to the date picker
  4513. */
  4514. _hideDatepicker: function( input ) {
  4515. var showAnim, duration, postProcess, onClose,
  4516. inst = this._curInst;
  4517. if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
  4518. return;
  4519. }
  4520. if ( this._datepickerShowing ) {
  4521. showAnim = this._get( inst, "showAnim" );
  4522. duration = this._get( inst, "duration" );
  4523. postProcess = function() {
  4524. $.datepicker._tidyDialog( inst );
  4525. };
  4526. // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
  4527. if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
  4528. inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
  4529. } else {
  4530. inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
  4531. ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
  4532. }
  4533. if ( !showAnim ) {
  4534. postProcess();
  4535. }
  4536. this._datepickerShowing = false;
  4537. onClose = this._get( inst, "onClose" );
  4538. if ( onClose ) {
  4539. onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
  4540. }
  4541. this._lastInput = null;
  4542. if ( this._inDialog ) {
  4543. this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
  4544. if ( $.blockUI ) {
  4545. $.unblockUI();
  4546. $( "body" ).append( this.dpDiv );
  4547. }
  4548. }
  4549. this._inDialog = false;
  4550. }
  4551. },
  4552. /* Tidy up after a dialog display. */
  4553. _tidyDialog: function( inst ) {
  4554. inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
  4555. },
  4556. /* Close date picker if clicked elsewhere. */
  4557. _checkExternalClick: function( event ) {
  4558. if ( !$.datepicker._curInst ) {
  4559. return;
  4560. }
  4561. var $target = $( event.target ),
  4562. inst = $.datepicker._getInst( $target[ 0 ] );
  4563. if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
  4564. $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
  4565. !$target.hasClass( $.datepicker.markerClassName ) &&
  4566. !$target.closest( "." + $.datepicker._triggerClass ).length &&
  4567. $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
  4568. ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
  4569. $.datepicker._hideDatepicker();
  4570. }
  4571. },
  4572. /* Adjust one of the date sub-fields. */
  4573. _adjustDate: function( id, offset, period ) {
  4574. var target = $( id ),
  4575. inst = this._getInst( target[ 0 ] );
  4576. if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
  4577. return;
  4578. }
  4579. this._adjustInstDate( inst, offset +
  4580. ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
  4581. period );
  4582. this._updateDatepicker( inst );
  4583. },
  4584. /* Action for current link. */
  4585. _gotoToday: function( id ) {
  4586. var date,
  4587. target = $( id ),
  4588. inst = this._getInst( target[ 0 ] );
  4589. if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
  4590. inst.selectedDay = inst.currentDay;
  4591. inst.drawMonth = inst.selectedMonth = inst.currentMonth;
  4592. inst.drawYear = inst.selectedYear = inst.currentYear;
  4593. } else {
  4594. date = new Date();
  4595. inst.selectedDay = date.getDate();
  4596. inst.drawMonth = inst.selectedMonth = date.getMonth();
  4597. inst.drawYear = inst.selectedYear = date.getFullYear();
  4598. }
  4599. this._notifyChange( inst );
  4600. this._adjustDate( target );
  4601. },
  4602. /* Action for selecting a new month/year. */
  4603. _selectMonthYear: function( id, select, period ) {
  4604. var target = $( id ),
  4605. inst = this._getInst( target[ 0 ] );
  4606. inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
  4607. inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
  4608. parseInt( select.options[ select.selectedIndex ].value, 10 );
  4609. this._notifyChange( inst );
  4610. this._adjustDate( target );
  4611. },
  4612. /* Action for selecting a day. */
  4613. _selectDay: function( id, month, year, td ) {
  4614. var inst,
  4615. target = $( id );
  4616. if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
  4617. return;
  4618. }
  4619. inst = this._getInst( target[ 0 ] );
  4620. inst.selectedDay = inst.currentDay = $( "a", td ).html();
  4621. inst.selectedMonth = inst.currentMonth = month;
  4622. inst.selectedYear = inst.currentYear = year;
  4623. this._selectDate( id, this._formatDate( inst,
  4624. inst.currentDay, inst.currentMonth, inst.currentYear ) );
  4625. },
  4626. /* Erase the input field and hide the date picker. */
  4627. _clearDate: function( id ) {
  4628. var target = $( id );
  4629. this._selectDate( target, "" );
  4630. },
  4631. /* Update the input field with the selected date. */
  4632. _selectDate: function( id, dateStr ) {
  4633. var onSelect,
  4634. target = $( id ),
  4635. inst = this._getInst( target[ 0 ] );
  4636. dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
  4637. if ( inst.input ) {
  4638. inst.input.val( dateStr );
  4639. }
  4640. this._updateAlternate( inst );
  4641. onSelect = this._get( inst, "onSelect" );
  4642. if ( onSelect ) {
  4643. onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
  4644. } else if ( inst.input ) {
  4645. inst.input.trigger( "change" ); // fire the change event
  4646. }
  4647. if ( inst.inline ) {
  4648. this._updateDatepicker( inst );
  4649. } else {
  4650. this._hideDatepicker();
  4651. this._lastInput = inst.input[ 0 ];
  4652. if ( typeof( inst.input[ 0 ] ) !== "object" ) {
  4653. inst.input.trigger( "focus" ); // restore focus
  4654. }
  4655. this._lastInput = null;
  4656. }
  4657. },
  4658. /* Update any alternate field to synchronise with the main field. */
  4659. _updateAlternate: function( inst ) {
  4660. var altFormat, date, dateStr,
  4661. altField = this._get( inst, "altField" );
  4662. if ( altField ) { // update alternate field too
  4663. altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
  4664. date = this._getDate( inst );
  4665. dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
  4666. $( altField ).val( dateStr );
  4667. }
  4668. },
  4669. /* Set as beforeShowDay function to prevent selection of weekends.
  4670. * @param date Date - the date to customise
  4671. * @return [boolean, string] - is this date selectable?, what is its CSS class?
  4672. */
  4673. noWeekends: function( date ) {
  4674. var day = date.getDay();
  4675. return [ ( day > 0 && day < 6 ), "" ];
  4676. },
  4677. /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
  4678. * @param date Date - the date to get the week for
  4679. * @return number - the number of the week within the year that contains this date
  4680. */
  4681. iso8601Week: function( date ) {
  4682. var time,
  4683. checkDate = new Date( date.getTime() );
  4684. // Find Thursday of this week starting on Monday
  4685. checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
  4686. time = checkDate.getTime();
  4687. checkDate.setMonth( 0 ); // Compare with Jan 1
  4688. checkDate.setDate( 1 );
  4689. return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
  4690. },
  4691. /* Parse a string value into a date object.
  4692. * See formatDate below for the possible formats.
  4693. *
  4694. * @param format string - the expected format of the date
  4695. * @param value string - the date in the above format
  4696. * @param settings Object - attributes include:
  4697. * shortYearCutoff number - the cutoff year for determining the century (optional)
  4698. * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
  4699. * dayNames string[7] - names of the days from Sunday (optional)
  4700. * monthNamesShort string[12] - abbreviated names of the months (optional)
  4701. * monthNames string[12] - names of the months (optional)
  4702. * @return Date - the extracted date value or null if value is blank
  4703. */
  4704. parseDate: function( format, value, settings ) {
  4705. if ( format == null || value == null ) {
  4706. throw "Invalid arguments";
  4707. }
  4708. value = ( typeof value === "object" ? value.toString() : value + "" );
  4709. if ( value === "" ) {
  4710. return null;
  4711. }
  4712. var iFormat, dim, extra,
  4713. iValue = 0,
  4714. shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
  4715. shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
  4716. new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
  4717. dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
  4718. dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
  4719. monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
  4720. monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
  4721. year = -1,
  4722. month = -1,
  4723. day = -1,
  4724. doy = -1,
  4725. literal = false,
  4726. date,
  4727. // Check whether a format character is doubled
  4728. lookAhead = function( match ) {
  4729. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  4730. if ( matches ) {
  4731. iFormat++;
  4732. }
  4733. return matches;
  4734. },
  4735. // Extract a number from the string value
  4736. getNumber = function( match ) {
  4737. var isDoubled = lookAhead( match ),
  4738. size = ( match === "@" ? 14 : ( match === "!" ? 20 :
  4739. ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
  4740. minSize = ( match === "y" ? size : 1 ),
  4741. digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
  4742. num = value.substring( iValue ).match( digits );
  4743. if ( !num ) {
  4744. throw "Missing number at position " + iValue;
  4745. }
  4746. iValue += num[ 0 ].length;
  4747. return parseInt( num[ 0 ], 10 );
  4748. },
  4749. // Extract a name from the string value and convert to an index
  4750. getName = function( match, shortNames, longNames ) {
  4751. var index = -1,
  4752. names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
  4753. return [ [ k, v ] ];
  4754. } ).sort( function( a, b ) {
  4755. return -( a[ 1 ].length - b[ 1 ].length );
  4756. } );
  4757. $.each( names, function( i, pair ) {
  4758. var name = pair[ 1 ];
  4759. if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
  4760. index = pair[ 0 ];
  4761. iValue += name.length;
  4762. return false;
  4763. }
  4764. } );
  4765. if ( index !== -1 ) {
  4766. return index + 1;
  4767. } else {
  4768. throw "Unknown name at position " + iValue;
  4769. }
  4770. },
  4771. // Confirm that a literal character matches the string value
  4772. checkLiteral = function() {
  4773. if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
  4774. throw "Unexpected literal at position " + iValue;
  4775. }
  4776. iValue++;
  4777. };
  4778. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  4779. if ( literal ) {
  4780. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  4781. literal = false;
  4782. } else {
  4783. checkLiteral();
  4784. }
  4785. } else {
  4786. switch ( format.charAt( iFormat ) ) {
  4787. case "d":
  4788. day = getNumber( "d" );
  4789. break;
  4790. case "D":
  4791. getName( "D", dayNamesShort, dayNames );
  4792. break;
  4793. case "o":
  4794. doy = getNumber( "o" );
  4795. break;
  4796. case "m":
  4797. month = getNumber( "m" );
  4798. break;
  4799. case "M":
  4800. month = getName( "M", monthNamesShort, monthNames );
  4801. break;
  4802. case "y":
  4803. year = getNumber( "y" );
  4804. break;
  4805. case "@":
  4806. date = new Date( getNumber( "@" ) );
  4807. year = date.getFullYear();
  4808. month = date.getMonth() + 1;
  4809. day = date.getDate();
  4810. break;
  4811. case "!":
  4812. date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
  4813. year = date.getFullYear();
  4814. month = date.getMonth() + 1;
  4815. day = date.getDate();
  4816. break;
  4817. case "'":
  4818. if ( lookAhead( "'" ) ) {
  4819. checkLiteral();
  4820. } else {
  4821. literal = true;
  4822. }
  4823. break;
  4824. default:
  4825. checkLiteral();
  4826. }
  4827. }
  4828. }
  4829. if ( iValue < value.length ) {
  4830. extra = value.substr( iValue );
  4831. if ( !/^\s+/.test( extra ) ) {
  4832. throw "Extra/unparsed characters found in date: " + extra;
  4833. }
  4834. }
  4835. if ( year === -1 ) {
  4836. year = new Date().getFullYear();
  4837. } else if ( year < 100 ) {
  4838. year += new Date().getFullYear() - new Date().getFullYear() % 100 +
  4839. ( year <= shortYearCutoff ? 0 : -100 );
  4840. }
  4841. if ( doy > -1 ) {
  4842. month = 1;
  4843. day = doy;
  4844. do {
  4845. dim = this._getDaysInMonth( year, month - 1 );
  4846. if ( day <= dim ) {
  4847. break;
  4848. }
  4849. month++;
  4850. day -= dim;
  4851. } while ( true );
  4852. }
  4853. date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
  4854. if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
  4855. throw "Invalid date"; // E.g. 31/02/00
  4856. }
  4857. return date;
  4858. },
  4859. /* Standard date formats. */
  4860. ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
  4861. COOKIE: "D, dd M yy",
  4862. ISO_8601: "yy-mm-dd",
  4863. RFC_822: "D, d M y",
  4864. RFC_850: "DD, dd-M-y",
  4865. RFC_1036: "D, d M y",
  4866. RFC_1123: "D, d M yy",
  4867. RFC_2822: "D, d M yy",
  4868. RSS: "D, d M y", // RFC 822
  4869. TICKS: "!",
  4870. TIMESTAMP: "@",
  4871. W3C: "yy-mm-dd", // ISO 8601
  4872. _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
  4873. Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
  4874. /* Format a date object into a string value.
  4875. * The format can be combinations of the following:
  4876. * d - day of month (no leading zero)
  4877. * dd - day of month (two digit)
  4878. * o - day of year (no leading zeros)
  4879. * oo - day of year (three digit)
  4880. * D - day name short
  4881. * DD - day name long
  4882. * m - month of year (no leading zero)
  4883. * mm - month of year (two digit)
  4884. * M - month name short
  4885. * MM - month name long
  4886. * y - year (two digit)
  4887. * yy - year (four digit)
  4888. * @ - Unix timestamp (ms since 01/01/1970)
  4889. * ! - Windows ticks (100ns since 01/01/0001)
  4890. * "..." - literal text
  4891. * '' - single quote
  4892. *
  4893. * @param format string - the desired format of the date
  4894. * @param date Date - the date value to format
  4895. * @param settings Object - attributes include:
  4896. * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
  4897. * dayNames string[7] - names of the days from Sunday (optional)
  4898. * monthNamesShort string[12] - abbreviated names of the months (optional)
  4899. * monthNames string[12] - names of the months (optional)
  4900. * @return string - the date in the above format
  4901. */
  4902. formatDate: function( format, date, settings ) {
  4903. if ( !date ) {
  4904. return "";
  4905. }
  4906. var iFormat,
  4907. dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
  4908. dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
  4909. monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
  4910. monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
  4911. // Check whether a format character is doubled
  4912. lookAhead = function( match ) {
  4913. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  4914. if ( matches ) {
  4915. iFormat++;
  4916. }
  4917. return matches;
  4918. },
  4919. // Format a number, with leading zero if necessary
  4920. formatNumber = function( match, value, len ) {
  4921. var num = "" + value;
  4922. if ( lookAhead( match ) ) {
  4923. while ( num.length < len ) {
  4924. num = "0" + num;
  4925. }
  4926. }
  4927. return num;
  4928. },
  4929. // Format a name, short or long as requested
  4930. formatName = function( match, value, shortNames, longNames ) {
  4931. return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
  4932. },
  4933. output = "",
  4934. literal = false;
  4935. if ( date ) {
  4936. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  4937. if ( literal ) {
  4938. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  4939. literal = false;
  4940. } else {
  4941. output += format.charAt( iFormat );
  4942. }
  4943. } else {
  4944. switch ( format.charAt( iFormat ) ) {
  4945. case "d":
  4946. output += formatNumber( "d", date.getDate(), 2 );
  4947. break;
  4948. case "D":
  4949. output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
  4950. break;
  4951. case "o":
  4952. output += formatNumber( "o",
  4953. Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
  4954. break;
  4955. case "m":
  4956. output += formatNumber( "m", date.getMonth() + 1, 2 );
  4957. break;
  4958. case "M":
  4959. output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
  4960. break;
  4961. case "y":
  4962. output += ( lookAhead( "y" ) ? date.getFullYear() :
  4963. ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
  4964. break;
  4965. case "@":
  4966. output += date.getTime();
  4967. break;
  4968. case "!":
  4969. output += date.getTime() * 10000 + this._ticksTo1970;
  4970. break;
  4971. case "'":
  4972. if ( lookAhead( "'" ) ) {
  4973. output += "'";
  4974. } else {
  4975. literal = true;
  4976. }
  4977. break;
  4978. default:
  4979. output += format.charAt( iFormat );
  4980. }
  4981. }
  4982. }
  4983. }
  4984. return output;
  4985. },
  4986. /* Extract all possible characters from the date format. */
  4987. _possibleChars: function( format ) {
  4988. var iFormat,
  4989. chars = "",
  4990. literal = false,
  4991. // Check whether a format character is doubled
  4992. lookAhead = function( match ) {
  4993. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  4994. if ( matches ) {
  4995. iFormat++;
  4996. }
  4997. return matches;
  4998. };
  4999. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  5000. if ( literal ) {
  5001. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  5002. literal = false;
  5003. } else {
  5004. chars += format.charAt( iFormat );
  5005. }
  5006. } else {
  5007. switch ( format.charAt( iFormat ) ) {
  5008. case "d": case "m": case "y": case "@":
  5009. chars += "0123456789";
  5010. break;
  5011. case "D": case "M":
  5012. return null; // Accept anything
  5013. case "'":
  5014. if ( lookAhead( "'" ) ) {
  5015. chars += "'";
  5016. } else {
  5017. literal = true;
  5018. }
  5019. break;
  5020. default:
  5021. chars += format.charAt( iFormat );
  5022. }
  5023. }
  5024. }
  5025. return chars;
  5026. },
  5027. /* Get a setting value, defaulting if necessary. */
  5028. _get: function( inst, name ) {
  5029. return inst.settings[ name ] !== undefined ?
  5030. inst.settings[ name ] : this._defaults[ name ];
  5031. },
  5032. /* Parse existing date and initialise date picker. */
  5033. _setDateFromField: function( inst, noDefault ) {
  5034. if ( inst.input.val() === inst.lastVal ) {
  5035. return;
  5036. }
  5037. var dateFormat = this._get( inst, "dateFormat" ),
  5038. dates = inst.lastVal = inst.input ? inst.input.val() : null,
  5039. defaultDate = this._getDefaultDate( inst ),
  5040. date = defaultDate,
  5041. settings = this._getFormatConfig( inst );
  5042. try {
  5043. date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
  5044. } catch ( event ) {
  5045. dates = ( noDefault ? "" : dates );
  5046. }
  5047. inst.selectedDay = date.getDate();
  5048. inst.drawMonth = inst.selectedMonth = date.getMonth();
  5049. inst.drawYear = inst.selectedYear = date.getFullYear();
  5050. inst.currentDay = ( dates ? date.getDate() : 0 );
  5051. inst.currentMonth = ( dates ? date.getMonth() : 0 );
  5052. inst.currentYear = ( dates ? date.getFullYear() : 0 );
  5053. this._adjustInstDate( inst );
  5054. },
  5055. /* Retrieve the default date shown on opening. */
  5056. _getDefaultDate: function( inst ) {
  5057. return this._restrictMinMax( inst,
  5058. this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
  5059. },
  5060. /* A date may be specified as an exact value or a relative one. */
  5061. _determineDate: function( inst, date, defaultDate ) {
  5062. var offsetNumeric = function( offset ) {
  5063. var date = new Date();
  5064. date.setDate( date.getDate() + offset );
  5065. return date;
  5066. },
  5067. offsetString = function( offset ) {
  5068. try {
  5069. return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
  5070. offset, $.datepicker._getFormatConfig( inst ) );
  5071. }
  5072. catch ( e ) {
  5073. // Ignore
  5074. }
  5075. var date = ( offset.toLowerCase().match( /^c/ ) ?
  5076. $.datepicker._getDate( inst ) : null ) || new Date(),
  5077. year = date.getFullYear(),
  5078. month = date.getMonth(),
  5079. day = date.getDate(),
  5080. pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
  5081. matches = pattern.exec( offset );
  5082. while ( matches ) {
  5083. switch ( matches[ 2 ] || "d" ) {
  5084. case "d" : case "D" :
  5085. day += parseInt( matches[ 1 ], 10 ); break;
  5086. case "w" : case "W" :
  5087. day += parseInt( matches[ 1 ], 10 ) * 7; break;
  5088. case "m" : case "M" :
  5089. month += parseInt( matches[ 1 ], 10 );
  5090. day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
  5091. break;
  5092. case "y": case "Y" :
  5093. year += parseInt( matches[ 1 ], 10 );
  5094. day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
  5095. break;
  5096. }
  5097. matches = pattern.exec( offset );
  5098. }
  5099. return new Date( year, month, day );
  5100. },
  5101. newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
  5102. ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
  5103. newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
  5104. if ( newDate ) {
  5105. newDate.setHours( 0 );
  5106. newDate.setMinutes( 0 );
  5107. newDate.setSeconds( 0 );
  5108. newDate.setMilliseconds( 0 );
  5109. }
  5110. return this._daylightSavingAdjust( newDate );
  5111. },
  5112. /* Handle switch to/from daylight saving.
  5113. * Hours may be non-zero on daylight saving cut-over:
  5114. * > 12 when midnight changeover, but then cannot generate
  5115. * midnight datetime, so jump to 1AM, otherwise reset.
  5116. * @param date (Date) the date to check
  5117. * @return (Date) the corrected date
  5118. */
  5119. _daylightSavingAdjust: function( date ) {
  5120. if ( !date ) {
  5121. return null;
  5122. }
  5123. date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
  5124. return date;
  5125. },
  5126. /* Set the date(s) directly. */
  5127. _setDate: function( inst, date, noChange ) {
  5128. var clear = !date,
  5129. origMonth = inst.selectedMonth,
  5130. origYear = inst.selectedYear,
  5131. newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
  5132. inst.selectedDay = inst.currentDay = newDate.getDate();
  5133. inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
  5134. inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
  5135. if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
  5136. this._notifyChange( inst );
  5137. }
  5138. this._adjustInstDate( inst );
  5139. if ( inst.input ) {
  5140. inst.input.val( clear ? "" : this._formatDate( inst ) );
  5141. }
  5142. },
  5143. /* Retrieve the date(s) directly. */
  5144. _getDate: function( inst ) {
  5145. var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
  5146. this._daylightSavingAdjust( new Date(
  5147. inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
  5148. return startDate;
  5149. },
  5150. /* Attach the onxxx handlers. These are declared statically so
  5151. * they work with static code transformers like Caja.
  5152. */
  5153. _attachHandlers: function( inst ) {
  5154. var stepMonths = this._get( inst, "stepMonths" ),
  5155. id = "#" + inst.id.replace( /\\\\/g, "\\" );
  5156. inst.dpDiv.find( "[data-handler]" ).map( function() {
  5157. var handler = {
  5158. prev: function() {
  5159. $.datepicker._adjustDate( id, -stepMonths, "M" );
  5160. },
  5161. next: function() {
  5162. $.datepicker._adjustDate( id, +stepMonths, "M" );
  5163. },
  5164. hide: function() {
  5165. $.datepicker._hideDatepicker();
  5166. },
  5167. today: function() {
  5168. $.datepicker._gotoToday( id );
  5169. },
  5170. selectDay: function() {
  5171. $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
  5172. return false;
  5173. },
  5174. selectMonth: function() {
  5175. $.datepicker._selectMonthYear( id, this, "M" );
  5176. return false;
  5177. },
  5178. selectYear: function() {
  5179. $.datepicker._selectMonthYear( id, this, "Y" );
  5180. return false;
  5181. }
  5182. };
  5183. $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
  5184. } );
  5185. },
  5186. /* Generate the HTML for the current state of the date picker. */
  5187. _generateHTML: function( inst ) {
  5188. var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
  5189. controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
  5190. monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
  5191. selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
  5192. cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
  5193. printDate, dRow, tbody, daySettings, otherMonth, unselectable,
  5194. tempDate = new Date(),
  5195. today = this._daylightSavingAdjust(
  5196. new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
  5197. isRTL = this._get( inst, "isRTL" ),
  5198. showButtonPanel = this._get( inst, "showButtonPanel" ),
  5199. hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
  5200. navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
  5201. numMonths = this._getNumberOfMonths( inst ),
  5202. showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
  5203. stepMonths = this._get( inst, "stepMonths" ),
  5204. isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
  5205. currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
  5206. new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
  5207. minDate = this._getMinMaxDate( inst, "min" ),
  5208. maxDate = this._getMinMaxDate( inst, "max" ),
  5209. drawMonth = inst.drawMonth - showCurrentAtPos,
  5210. drawYear = inst.drawYear;
  5211. if ( drawMonth < 0 ) {
  5212. drawMonth += 12;
  5213. drawYear--;
  5214. }
  5215. if ( maxDate ) {
  5216. maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
  5217. maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
  5218. maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
  5219. while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
  5220. drawMonth--;
  5221. if ( drawMonth < 0 ) {
  5222. drawMonth = 11;
  5223. drawYear--;
  5224. }
  5225. }
  5226. }
  5227. inst.drawMonth = drawMonth;
  5228. inst.drawYear = drawYear;
  5229. prevText = this._get( inst, "prevText" );
  5230. prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
  5231. this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
  5232. this._getFormatConfig( inst ) ) );
  5233. prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
  5234. "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
  5235. " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
  5236. ( 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>" ) );
  5237. nextText = this._get( inst, "nextText" );
  5238. nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
  5239. this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
  5240. this._getFormatConfig( inst ) ) );
  5241. next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
  5242. "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
  5243. " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
  5244. ( 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>" ) );
  5245. currentText = this._get( inst, "currentText" );
  5246. gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
  5247. currentText = ( !navigationAsDateFormat ? currentText :
  5248. this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
  5249. 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'>" +
  5250. this._get( inst, "closeText" ) + "</button>" : "" );
  5251. buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
  5252. ( 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'" +
  5253. ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
  5254. firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
  5255. firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
  5256. showWeek = this._get( inst, "showWeek" );
  5257. dayNames = this._get( inst, "dayNames" );
  5258. dayNamesMin = this._get( inst, "dayNamesMin" );
  5259. monthNames = this._get( inst, "monthNames" );
  5260. monthNamesShort = this._get( inst, "monthNamesShort" );
  5261. beforeShowDay = this._get( inst, "beforeShowDay" );
  5262. showOtherMonths = this._get( inst, "showOtherMonths" );
  5263. selectOtherMonths = this._get( inst, "selectOtherMonths" );
  5264. defaultDate = this._getDefaultDate( inst );
  5265. html = "";
  5266. for ( row = 0; row < numMonths[ 0 ]; row++ ) {
  5267. group = "";
  5268. this.maxRows = 4;
  5269. for ( col = 0; col < numMonths[ 1 ]; col++ ) {
  5270. selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
  5271. cornerClass = " ui-corner-all";
  5272. calender = "";
  5273. if ( isMultiMonth ) {
  5274. calender += "<div class='ui-datepicker-group";
  5275. if ( numMonths[ 1 ] > 1 ) {
  5276. switch ( col ) {
  5277. case 0: calender += " ui-datepicker-group-first";
  5278. cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
  5279. case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
  5280. cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
  5281. default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
  5282. }
  5283. }
  5284. calender += "'>";
  5285. }
  5286. calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
  5287. ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
  5288. ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
  5289. this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
  5290. row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
  5291. "</div><table class='ui-datepicker-calendar'><thead>" +
  5292. "<tr>";
  5293. thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
  5294. for ( dow = 0; dow < 7; dow++ ) { // days of the week
  5295. day = ( dow + firstDay ) % 7;
  5296. thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
  5297. "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
  5298. }
  5299. calender += thead + "</tr></thead><tbody>";
  5300. daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
  5301. if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
  5302. inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
  5303. }
  5304. leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
  5305. curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
  5306. numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
  5307. this.maxRows = numRows;
  5308. printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
  5309. for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
  5310. calender += "<tr>";
  5311. tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
  5312. this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
  5313. for ( dow = 0; dow < 7; dow++ ) { // create date picker days
  5314. daySettings = ( beforeShowDay ?
  5315. beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
  5316. otherMonth = ( printDate.getMonth() !== drawMonth );
  5317. unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
  5318. ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
  5319. tbody += "<td class='" +
  5320. ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
  5321. ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
  5322. ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
  5323. ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
  5324. // or defaultDate is current printedDate and defaultDate is selectedDate
  5325. " " + this._dayOverClass : "" ) + // highlight selected day
  5326. ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
  5327. ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
  5328. ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
  5329. ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
  5330. ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
  5331. ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
  5332. ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
  5333. ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
  5334. ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
  5335. ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
  5336. ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
  5337. "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
  5338. printDate.setDate( printDate.getDate() + 1 );
  5339. printDate = this._daylightSavingAdjust( printDate );
  5340. }
  5341. calender += tbody + "</tr>";
  5342. }
  5343. drawMonth++;
  5344. if ( drawMonth > 11 ) {
  5345. drawMonth = 0;
  5346. drawYear++;
  5347. }
  5348. calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
  5349. ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
  5350. group += calender;
  5351. }
  5352. html += group;
  5353. }
  5354. html += buttonPanel;
  5355. inst._keyEvent = false;
  5356. return html;
  5357. },
  5358. /* Generate the month and year header. */
  5359. _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
  5360. secondary, monthNames, monthNamesShort ) {
  5361. var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
  5362. changeMonth = this._get( inst, "changeMonth" ),
  5363. changeYear = this._get( inst, "changeYear" ),
  5364. showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
  5365. html = "<div class='ui-datepicker-title'>",
  5366. monthHtml = "";
  5367. // Month selection
  5368. if ( secondary || !changeMonth ) {
  5369. monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
  5370. } else {
  5371. inMinYear = ( minDate && minDate.getFullYear() === drawYear );
  5372. inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
  5373. monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
  5374. for ( month = 0; month < 12; month++ ) {
  5375. if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
  5376. monthHtml += "<option value='" + month + "'" +
  5377. ( month === drawMonth ? " selected='selected'" : "" ) +
  5378. ">" + monthNamesShort[ month ] + "</option>";
  5379. }
  5380. }
  5381. monthHtml += "</select>";
  5382. }
  5383. if ( !showMonthAfterYear ) {
  5384. html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
  5385. }
  5386. // Year selection
  5387. if ( !inst.yearshtml ) {
  5388. inst.yearshtml = "";
  5389. if ( secondary || !changeYear ) {
  5390. html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
  5391. } else {
  5392. // determine range of years to display
  5393. years = this._get( inst, "yearRange" ).split( ":" );
  5394. thisYear = new Date().getFullYear();
  5395. determineYear = function( value ) {
  5396. var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
  5397. ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
  5398. parseInt( value, 10 ) ) );
  5399. return ( isNaN( year ) ? thisYear : year );
  5400. };
  5401. year = determineYear( years[ 0 ] );
  5402. endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
  5403. year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
  5404. endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
  5405. inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
  5406. for ( ; year <= endYear; year++ ) {
  5407. inst.yearshtml += "<option value='" + year + "'" +
  5408. ( year === drawYear ? " selected='selected'" : "" ) +
  5409. ">" + year + "</option>";
  5410. }
  5411. inst.yearshtml += "</select>";
  5412. html += inst.yearshtml;
  5413. inst.yearshtml = null;
  5414. }
  5415. }
  5416. html += this._get( inst, "yearSuffix" );
  5417. if ( showMonthAfterYear ) {
  5418. html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
  5419. }
  5420. html += "</div>"; // Close datepicker_header
  5421. return html;
  5422. },
  5423. /* Adjust one of the date sub-fields. */
  5424. _adjustInstDate: function( inst, offset, period ) {
  5425. var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
  5426. month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
  5427. day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
  5428. date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
  5429. inst.selectedDay = date.getDate();
  5430. inst.drawMonth = inst.selectedMonth = date.getMonth();
  5431. inst.drawYear = inst.selectedYear = date.getFullYear();
  5432. if ( period === "M" || period === "Y" ) {
  5433. this._notifyChange( inst );
  5434. }
  5435. },
  5436. /* Ensure a date is within any min/max bounds. */
  5437. _restrictMinMax: function( inst, date ) {
  5438. var minDate = this._getMinMaxDate( inst, "min" ),
  5439. maxDate = this._getMinMaxDate( inst, "max" ),
  5440. newDate = ( minDate && date < minDate ? minDate : date );
  5441. return ( maxDate && newDate > maxDate ? maxDate : newDate );
  5442. },
  5443. /* Notify change of month/year. */
  5444. _notifyChange: function( inst ) {
  5445. var onChange = this._get( inst, "onChangeMonthYear" );
  5446. if ( onChange ) {
  5447. onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
  5448. [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
  5449. }
  5450. },
  5451. /* Determine the number of months to show. */
  5452. _getNumberOfMonths: function( inst ) {
  5453. var numMonths = this._get( inst, "numberOfMonths" );
  5454. return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
  5455. },
  5456. /* Determine the current maximum date - ensure no time components are set. */
  5457. _getMinMaxDate: function( inst, minMax ) {
  5458. return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
  5459. },
  5460. /* Find the number of days in a given month. */
  5461. _getDaysInMonth: function( year, month ) {
  5462. return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
  5463. },
  5464. /* Find the day of the week of the first of a month. */
  5465. _getFirstDayOfMonth: function( year, month ) {
  5466. return new Date( year, month, 1 ).getDay();
  5467. },
  5468. /* Determines if we should allow a "next/prev" month display change. */
  5469. _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
  5470. var numMonths = this._getNumberOfMonths( inst ),
  5471. date = this._daylightSavingAdjust( new Date( curYear,
  5472. curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
  5473. if ( offset < 0 ) {
  5474. date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
  5475. }
  5476. return this._isInRange( inst, date );
  5477. },
  5478. /* Is the given date in the accepted range? */
  5479. _isInRange: function( inst, date ) {
  5480. var yearSplit, currentYear,
  5481. minDate = this._getMinMaxDate( inst, "min" ),
  5482. maxDate = this._getMinMaxDate( inst, "max" ),
  5483. minYear = null,
  5484. maxYear = null,
  5485. years = this._get( inst, "yearRange" );
  5486. if ( years ) {
  5487. yearSplit = years.split( ":" );
  5488. currentYear = new Date().getFullYear();
  5489. minYear = parseInt( yearSplit[ 0 ], 10 );
  5490. maxYear = parseInt( yearSplit[ 1 ], 10 );
  5491. if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
  5492. minYear += currentYear;
  5493. }
  5494. if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
  5495. maxYear += currentYear;
  5496. }
  5497. }
  5498. return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
  5499. ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
  5500. ( !minYear || date.getFullYear() >= minYear ) &&
  5501. ( !maxYear || date.getFullYear() <= maxYear ) );
  5502. },
  5503. /* Provide the configuration settings for formatting/parsing. */
  5504. _getFormatConfig: function( inst ) {
  5505. var shortYearCutoff = this._get( inst, "shortYearCutoff" );
  5506. shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
  5507. new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
  5508. return { shortYearCutoff: shortYearCutoff,
  5509. dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
  5510. monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
  5511. },
  5512. /* Format the given date for display. */
  5513. _formatDate: function( inst, day, month, year ) {
  5514. if ( !day ) {
  5515. inst.currentDay = inst.selectedDay;
  5516. inst.currentMonth = inst.selectedMonth;
  5517. inst.currentYear = inst.selectedYear;
  5518. }
  5519. var date = ( day ? ( typeof day === "object" ? day :
  5520. this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
  5521. this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
  5522. return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
  5523. }
  5524. } );
  5525. /*
  5526. * Bind hover events for datepicker elements.
  5527. * Done via delegate so the binding only occurs once in the lifetime of the parent div.
  5528. * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
  5529. */
  5530. function datepicker_bindHover( dpDiv ) {
  5531. var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
  5532. return dpDiv.on( "mouseout", selector, function() {
  5533. $( this ).removeClass( "ui-state-hover" );
  5534. if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
  5535. $( this ).removeClass( "ui-datepicker-prev-hover" );
  5536. }
  5537. if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
  5538. $( this ).removeClass( "ui-datepicker-next-hover" );
  5539. }
  5540. } )
  5541. .on( "mouseover", selector, datepicker_handleMouseover );
  5542. }
  5543. function datepicker_handleMouseover() {
  5544. if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
  5545. $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
  5546. $( this ).addClass( "ui-state-hover" );
  5547. if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
  5548. $( this ).addClass( "ui-datepicker-prev-hover" );
  5549. }
  5550. if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
  5551. $( this ).addClass( "ui-datepicker-next-hover" );
  5552. }
  5553. }
  5554. }
  5555. /* jQuery extend now ignores nulls! */
  5556. function datepicker_extendRemove( target, props ) {
  5557. $.extend( target, props );
  5558. for ( var name in props ) {
  5559. if ( props[ name ] == null ) {
  5560. target[ name ] = props[ name ];
  5561. }
  5562. }
  5563. return target;
  5564. }
  5565. /* Invoke the datepicker functionality.
  5566. @param options string - a command, optionally followed by additional parameters or
  5567. Object - settings for attaching new datepicker functionality
  5568. @return jQuery object */
  5569. $.fn.datepicker = function( options ) {
  5570. /* Verify an empty collection wasn't passed - Fixes #6976 */
  5571. if ( !this.length ) {
  5572. return this;
  5573. }
  5574. /* Initialise the date picker. */
  5575. if ( !$.datepicker.initialized ) {
  5576. $( document ).on( "mousedown", $.datepicker._checkExternalClick );
  5577. $.datepicker.initialized = true;
  5578. }
  5579. /* Append datepicker main container to body if not exist. */
  5580. if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
  5581. $( "body" ).append( $.datepicker.dpDiv );
  5582. }
  5583. var otherArgs = Array.prototype.slice.call( arguments, 1 );
  5584. if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
  5585. return $.datepicker[ "_" + options + "Datepicker" ].
  5586. apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
  5587. }
  5588. if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
  5589. return $.datepicker[ "_" + options + "Datepicker" ].
  5590. apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
  5591. }
  5592. return this.each( function() {
  5593. typeof options === "string" ?
  5594. $.datepicker[ "_" + options + "Datepicker" ].
  5595. apply( $.datepicker, [ this ].concat( otherArgs ) ) :
  5596. $.datepicker._attachDatepicker( this, options );
  5597. } );
  5598. };
  5599. $.datepicker = new Datepicker(); // singleton instance
  5600. $.datepicker.initialized = false;
  5601. $.datepicker.uuid = new Date().getTime();
  5602. $.datepicker.version = "1.12.1";
  5603. var widgetsDatepicker = $.datepicker;
  5604. }));