Нет описания

jquery-ui-timepicker-addon.js 84KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195
  1. /*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20
  2. * http://trentrichardson.com/examples/timepicker
  3. * Copyright (c) 2016 Trent Richardson; Licensed MIT */
  4. ( function ( factory ) {
  5. if ( typeof define === 'function' && define.amd ) {
  6. define( [ 'jquery', 'jquery-ui' ], factory );
  7. } else {
  8. factory( jQuery );
  9. }
  10. } )( function ( $ ) {
  11. /*
  12. * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
  13. */
  14. $.ui.timepicker = $.ui.timepicker || {};
  15. if ( $.ui.timepicker.version ) {
  16. return;
  17. }
  18. /*
  19. * Extend jQueryUI, get it started with our version number
  20. */
  21. $.extend( $.ui, {
  22. timepicker: {
  23. version: '1.6.3',
  24. },
  25. } );
  26. /*
  27. * Timepicker manager.
  28. * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
  29. * Settings for (groups of) time pickers are maintained in an instance object,
  30. * allowing multiple different settings on the same page.
  31. */
  32. var Timepicker = function () {
  33. this.regional = []; // Available regional settings, indexed by language code
  34. this.regional[ '' ] = {
  35. // Default regional settings
  36. currentText: 'Now',
  37. closeText: 'Done',
  38. amNames: [ 'AM', 'A' ],
  39. pmNames: [ 'PM', 'P' ],
  40. timeFormat: 'HH:mm',
  41. timeSuffix: '',
  42. timeOnlyTitle: 'Choose Time',
  43. timeText: 'Time',
  44. hourText: 'Hour',
  45. minuteText: 'Minute',
  46. secondText: 'Second',
  47. millisecText: 'Millisecond',
  48. microsecText: 'Microsecond',
  49. timezoneText: 'Time Zone',
  50. isRTL: false,
  51. };
  52. this._defaults = {
  53. // Global defaults for all the datetime picker instances
  54. showButtonPanel: true,
  55. timeOnly: false,
  56. timeOnlyShowDate: false,
  57. showHour: null,
  58. showMinute: null,
  59. showSecond: null,
  60. showMillisec: null,
  61. showMicrosec: null,
  62. showTimezone: null,
  63. showTime: true,
  64. stepHour: 1,
  65. stepMinute: 1,
  66. stepSecond: 1,
  67. stepMillisec: 1,
  68. stepMicrosec: 1,
  69. hour: 0,
  70. minute: 0,
  71. second: 0,
  72. millisec: 0,
  73. microsec: 0,
  74. timezone: null,
  75. hourMin: 0,
  76. minuteMin: 0,
  77. secondMin: 0,
  78. millisecMin: 0,
  79. microsecMin: 0,
  80. hourMax: 23,
  81. minuteMax: 59,
  82. secondMax: 59,
  83. millisecMax: 999,
  84. microsecMax: 999,
  85. minDateTime: null,
  86. maxDateTime: null,
  87. maxTime: null,
  88. minTime: null,
  89. onSelect: null,
  90. hourGrid: 0,
  91. minuteGrid: 0,
  92. secondGrid: 0,
  93. millisecGrid: 0,
  94. microsecGrid: 0,
  95. alwaysSetTime: true,
  96. separator: ' ',
  97. altFieldTimeOnly: true,
  98. altTimeFormat: null,
  99. altSeparator: null,
  100. altTimeSuffix: null,
  101. altRedirectFocus: true,
  102. pickerTimeFormat: null,
  103. pickerTimeSuffix: null,
  104. showTimepicker: true,
  105. timezoneList: null,
  106. addSliderAccess: false,
  107. sliderAccessArgs: null,
  108. controlType: 'slider',
  109. oneLine: false,
  110. defaultValue: null,
  111. parse: 'strict',
  112. afterInject: null,
  113. };
  114. $.extend( this._defaults, this.regional[ '' ] );
  115. };
  116. $.extend( Timepicker.prototype, {
  117. $input: null,
  118. $altInput: null,
  119. $timeObj: null,
  120. inst: null,
  121. hour_slider: null,
  122. minute_slider: null,
  123. second_slider: null,
  124. millisec_slider: null,
  125. microsec_slider: null,
  126. timezone_select: null,
  127. maxTime: null,
  128. minTime: null,
  129. hour: 0,
  130. minute: 0,
  131. second: 0,
  132. millisec: 0,
  133. microsec: 0,
  134. timezone: null,
  135. hourMinOriginal: null,
  136. minuteMinOriginal: null,
  137. secondMinOriginal: null,
  138. millisecMinOriginal: null,
  139. microsecMinOriginal: null,
  140. hourMaxOriginal: null,
  141. minuteMaxOriginal: null,
  142. secondMaxOriginal: null,
  143. millisecMaxOriginal: null,
  144. microsecMaxOriginal: null,
  145. ampm: '',
  146. formattedDate: '',
  147. formattedTime: '',
  148. formattedDateTime: '',
  149. timezoneList: null,
  150. units: [ 'hour', 'minute', 'second', 'millisec', 'microsec' ],
  151. support: {},
  152. control: null,
  153. /*
  154. * Override the default settings for all instances of the time picker.
  155. * @param {Object} settings object - the new settings to use as defaults (anonymous object)
  156. * @return {Object} the manager object
  157. */
  158. setDefaults: function ( settings ) {
  159. extendRemove( this._defaults, settings || {} );
  160. return this;
  161. },
  162. /*
  163. * Create a new Timepicker instance
  164. */
  165. _newInst: function ( $input, opts ) {
  166. var tp_inst = new Timepicker(),
  167. inlineSettings = {},
  168. fns = {},
  169. overrides,
  170. i;
  171. for ( var attrName in this._defaults ) {
  172. if ( this._defaults.hasOwnProperty( attrName ) ) {
  173. var attrValue = $input.attr( 'time:' + attrName );
  174. if ( attrValue ) {
  175. try {
  176. inlineSettings[ attrName ] = eval( attrValue );
  177. } catch ( err ) {
  178. inlineSettings[ attrName ] = attrValue;
  179. }
  180. }
  181. }
  182. }
  183. overrides = {
  184. beforeShow: function ( input, dp_inst ) {
  185. if ( $.isFunction( tp_inst._defaults.evnts.beforeShow ) ) {
  186. return tp_inst._defaults.evnts.beforeShow.call(
  187. $input[ 0 ],
  188. input,
  189. dp_inst,
  190. tp_inst
  191. );
  192. }
  193. },
  194. onChangeMonthYear: function ( year, month, dp_inst ) {
  195. // Update the time as well : this prevents the time from disappearing from the $input field.
  196. // tp_inst._updateDateTime(dp_inst);
  197. if (
  198. $.isFunction(
  199. tp_inst._defaults.evnts.onChangeMonthYear
  200. )
  201. ) {
  202. tp_inst._defaults.evnts.onChangeMonthYear.call(
  203. $input[ 0 ],
  204. year,
  205. month,
  206. dp_inst,
  207. tp_inst
  208. );
  209. }
  210. },
  211. onClose: function ( dateText, dp_inst ) {
  212. if ( tp_inst.timeDefined === true && $input.val() !== '' ) {
  213. tp_inst._updateDateTime( dp_inst );
  214. }
  215. if ( $.isFunction( tp_inst._defaults.evnts.onClose ) ) {
  216. tp_inst._defaults.evnts.onClose.call(
  217. $input[ 0 ],
  218. dateText,
  219. dp_inst,
  220. tp_inst
  221. );
  222. }
  223. },
  224. };
  225. for ( i in overrides ) {
  226. if ( overrides.hasOwnProperty( i ) ) {
  227. fns[ i ] = opts[ i ] || this._defaults[ i ] || null;
  228. }
  229. }
  230. tp_inst._defaults = $.extend(
  231. {},
  232. this._defaults,
  233. inlineSettings,
  234. opts,
  235. overrides,
  236. {
  237. evnts: fns,
  238. timepicker: tp_inst, // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
  239. }
  240. );
  241. tp_inst.amNames = $.map(
  242. tp_inst._defaults.amNames,
  243. function ( val ) {
  244. return val.toUpperCase();
  245. }
  246. );
  247. tp_inst.pmNames = $.map(
  248. tp_inst._defaults.pmNames,
  249. function ( val ) {
  250. return val.toUpperCase();
  251. }
  252. );
  253. // detect which units are supported
  254. tp_inst.support = detectSupport(
  255. tp_inst._defaults.timeFormat +
  256. ( tp_inst._defaults.pickerTimeFormat
  257. ? tp_inst._defaults.pickerTimeFormat
  258. : '' ) +
  259. ( tp_inst._defaults.altTimeFormat
  260. ? tp_inst._defaults.altTimeFormat
  261. : '' )
  262. );
  263. // controlType is string - key to our this._controls
  264. if ( typeof tp_inst._defaults.controlType === 'string' ) {
  265. if (
  266. tp_inst._defaults.controlType === 'slider' &&
  267. typeof $.ui.slider === 'undefined'
  268. ) {
  269. tp_inst._defaults.controlType = 'select';
  270. }
  271. tp_inst.control =
  272. tp_inst._controls[ tp_inst._defaults.controlType ];
  273. }
  274. // controlType is an object and must implement create, options, value methods
  275. else {
  276. tp_inst.control = tp_inst._defaults.controlType;
  277. }
  278. // prep the timezone options
  279. var timezoneList = [
  280. -720,
  281. -660,
  282. -600,
  283. -570,
  284. -540,
  285. -480,
  286. -420,
  287. -360,
  288. -300,
  289. -270,
  290. -240,
  291. -210,
  292. -180,
  293. -120,
  294. -60,
  295. 0,
  296. 60,
  297. 120,
  298. 180,
  299. 210,
  300. 240,
  301. 270,
  302. 300,
  303. 330,
  304. 345,
  305. 360,
  306. 390,
  307. 420,
  308. 480,
  309. 525,
  310. 540,
  311. 570,
  312. 600,
  313. 630,
  314. 660,
  315. 690,
  316. 720,
  317. 765,
  318. 780,
  319. 840,
  320. ];
  321. if ( tp_inst._defaults.timezoneList !== null ) {
  322. timezoneList = tp_inst._defaults.timezoneList;
  323. }
  324. var tzl = timezoneList.length,
  325. tzi = 0,
  326. tzv = null;
  327. if ( tzl > 0 && typeof timezoneList[ 0 ] !== 'object' ) {
  328. for ( ; tzi < tzl; tzi++ ) {
  329. tzv = timezoneList[ tzi ];
  330. timezoneList[ tzi ] = {
  331. value: tzv,
  332. label: $.timepicker.timezoneOffsetString(
  333. tzv,
  334. tp_inst.support.iso8601
  335. ),
  336. };
  337. }
  338. }
  339. tp_inst._defaults.timezoneList = timezoneList;
  340. // set the default units
  341. tp_inst.timezone =
  342. tp_inst._defaults.timezone !== null
  343. ? $.timepicker.timezoneOffsetNumber(
  344. tp_inst._defaults.timezone
  345. )
  346. : new Date().getTimezoneOffset() * -1;
  347. tp_inst.hour =
  348. tp_inst._defaults.hour < tp_inst._defaults.hourMin
  349. ? tp_inst._defaults.hourMin
  350. : tp_inst._defaults.hour > tp_inst._defaults.hourMax
  351. ? tp_inst._defaults.hourMax
  352. : tp_inst._defaults.hour;
  353. tp_inst.minute =
  354. tp_inst._defaults.minute < tp_inst._defaults.minuteMin
  355. ? tp_inst._defaults.minuteMin
  356. : tp_inst._defaults.minute > tp_inst._defaults.minuteMax
  357. ? tp_inst._defaults.minuteMax
  358. : tp_inst._defaults.minute;
  359. tp_inst.second =
  360. tp_inst._defaults.second < tp_inst._defaults.secondMin
  361. ? tp_inst._defaults.secondMin
  362. : tp_inst._defaults.second > tp_inst._defaults.secondMax
  363. ? tp_inst._defaults.secondMax
  364. : tp_inst._defaults.second;
  365. tp_inst.millisec =
  366. tp_inst._defaults.millisec < tp_inst._defaults.millisecMin
  367. ? tp_inst._defaults.millisecMin
  368. : tp_inst._defaults.millisec > tp_inst._defaults.millisecMax
  369. ? tp_inst._defaults.millisecMax
  370. : tp_inst._defaults.millisec;
  371. tp_inst.microsec =
  372. tp_inst._defaults.microsec < tp_inst._defaults.microsecMin
  373. ? tp_inst._defaults.microsecMin
  374. : tp_inst._defaults.microsec > tp_inst._defaults.microsecMax
  375. ? tp_inst._defaults.microsecMax
  376. : tp_inst._defaults.microsec;
  377. tp_inst.ampm = '';
  378. tp_inst.$input = $input;
  379. if ( tp_inst._defaults.altField ) {
  380. tp_inst.$altInput = $( tp_inst._defaults.altField );
  381. if ( tp_inst._defaults.altRedirectFocus === true ) {
  382. tp_inst.$altInput
  383. .css( {
  384. cursor: 'pointer',
  385. } )
  386. .focus( function () {
  387. $input.trigger( 'focus' );
  388. } );
  389. }
  390. }
  391. if (
  392. tp_inst._defaults.minDate === 0 ||
  393. tp_inst._defaults.minDateTime === 0
  394. ) {
  395. tp_inst._defaults.minDate = new Date();
  396. }
  397. if (
  398. tp_inst._defaults.maxDate === 0 ||
  399. tp_inst._defaults.maxDateTime === 0
  400. ) {
  401. tp_inst._defaults.maxDate = new Date();
  402. }
  403. // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
  404. if (
  405. tp_inst._defaults.minDate !== undefined &&
  406. tp_inst._defaults.minDate instanceof Date
  407. ) {
  408. tp_inst._defaults.minDateTime = new Date(
  409. tp_inst._defaults.minDate.getTime()
  410. );
  411. }
  412. if (
  413. tp_inst._defaults.minDateTime !== undefined &&
  414. tp_inst._defaults.minDateTime instanceof Date
  415. ) {
  416. tp_inst._defaults.minDate = new Date(
  417. tp_inst._defaults.minDateTime.getTime()
  418. );
  419. }
  420. if (
  421. tp_inst._defaults.maxDate !== undefined &&
  422. tp_inst._defaults.maxDate instanceof Date
  423. ) {
  424. tp_inst._defaults.maxDateTime = new Date(
  425. tp_inst._defaults.maxDate.getTime()
  426. );
  427. }
  428. if (
  429. tp_inst._defaults.maxDateTime !== undefined &&
  430. tp_inst._defaults.maxDateTime instanceof Date
  431. ) {
  432. tp_inst._defaults.maxDate = new Date(
  433. tp_inst._defaults.maxDateTime.getTime()
  434. );
  435. }
  436. tp_inst.$input.bind( 'focus', function () {
  437. tp_inst._onFocus();
  438. } );
  439. return tp_inst;
  440. },
  441. /*
  442. * add our sliders to the calendar
  443. */
  444. _addTimePicker: function ( dp_inst ) {
  445. var currDT = $.trim(
  446. this.$altInput && this._defaults.altFieldTimeOnly
  447. ? this.$input.val() + ' ' + this.$altInput.val()
  448. : this.$input.val()
  449. );
  450. this.timeDefined = this._parseTime( currDT );
  451. this._limitMinMaxDateTime( dp_inst, false );
  452. this._injectTimePicker();
  453. this._afterInject();
  454. },
  455. /*
  456. * parse the time string from input value or _setTime
  457. */
  458. _parseTime: function ( timeString, withDate ) {
  459. if ( ! this.inst ) {
  460. this.inst = $.datepicker._getInst( this.$input[ 0 ] );
  461. }
  462. if ( withDate || ! this._defaults.timeOnly ) {
  463. var dp_dateFormat = $.datepicker._get(
  464. this.inst,
  465. 'dateFormat'
  466. );
  467. try {
  468. var parseRes = parseDateTimeInternal(
  469. dp_dateFormat,
  470. this._defaults.timeFormat,
  471. timeString,
  472. $.datepicker._getFormatConfig( this.inst ),
  473. this._defaults
  474. );
  475. if ( ! parseRes.timeObj ) {
  476. return false;
  477. }
  478. $.extend( this, parseRes.timeObj );
  479. } catch ( err ) {
  480. $.timepicker.log(
  481. 'Error parsing the date/time string: ' +
  482. err +
  483. '\ndate/time string = ' +
  484. timeString +
  485. '\ntimeFormat = ' +
  486. this._defaults.timeFormat +
  487. '\ndateFormat = ' +
  488. dp_dateFormat
  489. );
  490. return false;
  491. }
  492. return true;
  493. } else {
  494. var timeObj = $.datepicker.parseTime(
  495. this._defaults.timeFormat,
  496. timeString,
  497. this._defaults
  498. );
  499. if ( ! timeObj ) {
  500. return false;
  501. }
  502. $.extend( this, timeObj );
  503. return true;
  504. }
  505. },
  506. /*
  507. * Handle callback option after injecting timepicker
  508. */
  509. _afterInject: function () {
  510. var o = this.inst.settings;
  511. if ( $.isFunction( o.afterInject ) ) {
  512. o.afterInject.call( this );
  513. }
  514. },
  515. /*
  516. * generate and inject html for timepicker into ui datepicker
  517. */
  518. _injectTimePicker: function () {
  519. var $dp = this.inst.dpDiv,
  520. o = this.inst.settings,
  521. tp_inst = this,
  522. litem = '',
  523. uitem = '',
  524. show = null,
  525. max = {},
  526. gridSize = {},
  527. size = null,
  528. i = 0,
  529. l = 0;
  530. // Prevent displaying twice
  531. if (
  532. $dp.find( 'div.ui-timepicker-div' ).length === 0 &&
  533. o.showTimepicker
  534. ) {
  535. var noDisplay = ' ui_tpicker_unit_hide',
  536. html =
  537. '<div class="ui-timepicker-div' +
  538. ( o.isRTL ? ' ui-timepicker-rtl' : '' ) +
  539. ( o.oneLine && o.controlType === 'select'
  540. ? ' ui-timepicker-oneLine'
  541. : '' ) +
  542. '"><dl>' +
  543. '<dt class="ui_tpicker_time_label' +
  544. ( o.showTime ? '' : noDisplay ) +
  545. '">' +
  546. o.timeText +
  547. '</dt>' +
  548. '<dd class="ui_tpicker_time ' +
  549. ( o.showTime ? '' : noDisplay ) +
  550. '"><input class="ui_tpicker_time_input" ' +
  551. ( o.timeInput ? '' : 'disabled' ) +
  552. '/></dd>';
  553. // Create the markup
  554. for ( i = 0, l = this.units.length; i < l; i++ ) {
  555. litem = this.units[ i ];
  556. uitem =
  557. litem.substr( 0, 1 ).toUpperCase() + litem.substr( 1 );
  558. show =
  559. o[ 'show' + uitem ] !== null
  560. ? o[ 'show' + uitem ]
  561. : this.support[ litem ];
  562. // Added by Peter Medeiros:
  563. // - Figure out what the hour/minute/second max should be based on the step values.
  564. // - Example: if stepMinute is 15, then minMax is 45.
  565. max[ litem ] = parseInt(
  566. o[ litem + 'Max' ] -
  567. ( ( o[ litem + 'Max' ] - o[ litem + 'Min' ] ) %
  568. o[ 'step' + uitem ] ),
  569. 10
  570. );
  571. gridSize[ litem ] = 0;
  572. html +=
  573. '<dt class="ui_tpicker_' +
  574. litem +
  575. '_label' +
  576. ( show ? '' : noDisplay ) +
  577. '">' +
  578. o[ litem + 'Text' ] +
  579. '</dt>' +
  580. '<dd class="ui_tpicker_' +
  581. litem +
  582. ( show ? '' : noDisplay ) +
  583. '"><div class="ui_tpicker_' +
  584. litem +
  585. '_slider' +
  586. ( show ? '' : noDisplay ) +
  587. '"></div>';
  588. if ( show && o[ litem + 'Grid' ] > 0 ) {
  589. html +=
  590. '<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
  591. if ( litem === 'hour' ) {
  592. for (
  593. var h = o[ litem + 'Min' ];
  594. h <= max[ litem ];
  595. h += parseInt( o[ litem + 'Grid' ], 10 )
  596. ) {
  597. gridSize[ litem ]++;
  598. var tmph = $.datepicker.formatTime(
  599. this.support.ampm ? 'hht' : 'HH',
  600. { hour: h },
  601. o
  602. );
  603. html +=
  604. '<td data-for="' +
  605. litem +
  606. '">' +
  607. tmph +
  608. '</td>';
  609. }
  610. } else {
  611. for (
  612. var m = o[ litem + 'Min' ];
  613. m <= max[ litem ];
  614. m += parseInt( o[ litem + 'Grid' ], 10 )
  615. ) {
  616. gridSize[ litem ]++;
  617. html +=
  618. '<td data-for="' +
  619. litem +
  620. '">' +
  621. ( m < 10 ? '0' : '' ) +
  622. m +
  623. '</td>';
  624. }
  625. }
  626. html += '</tr></table></div>';
  627. }
  628. html += '</dd>';
  629. }
  630. // Timezone
  631. var showTz =
  632. o.showTimezone !== null
  633. ? o.showTimezone
  634. : this.support.timezone;
  635. html +=
  636. '<dt class="ui_tpicker_timezone_label' +
  637. ( showTz ? '' : noDisplay ) +
  638. '">' +
  639. o.timezoneText +
  640. '</dt>';
  641. html +=
  642. '<dd class="ui_tpicker_timezone' +
  643. ( showTz ? '' : noDisplay ) +
  644. '"></dd>';
  645. // Create the elements from string
  646. html += '</dl></div>';
  647. var $tp = $( html );
  648. // if we only want time picker...
  649. if ( o.timeOnly === true ) {
  650. $tp.prepend(
  651. '<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' +
  652. '<div class="ui-datepicker-title">' +
  653. o.timeOnlyTitle +
  654. '</div>' +
  655. '</div>'
  656. );
  657. $dp.find(
  658. '.ui-datepicker-header, .ui-datepicker-calendar'
  659. ).hide();
  660. }
  661. // add sliders, adjust grids, add events
  662. for ( i = 0, l = tp_inst.units.length; i < l; i++ ) {
  663. litem = tp_inst.units[ i ];
  664. uitem =
  665. litem.substr( 0, 1 ).toUpperCase() + litem.substr( 1 );
  666. show =
  667. o[ 'show' + uitem ] !== null
  668. ? o[ 'show' + uitem ]
  669. : this.support[ litem ];
  670. // add the slider
  671. tp_inst[ litem + '_slider' ] = tp_inst.control.create(
  672. tp_inst,
  673. $tp.find( '.ui_tpicker_' + litem + '_slider' ),
  674. litem,
  675. tp_inst[ litem ],
  676. o[ litem + 'Min' ],
  677. max[ litem ],
  678. o[ 'step' + uitem ]
  679. );
  680. // adjust the grid and add click event
  681. if ( show && o[ litem + 'Grid' ] > 0 ) {
  682. size =
  683. ( 100 * gridSize[ litem ] * o[ litem + 'Grid' ] ) /
  684. ( max[ litem ] - o[ litem + 'Min' ] );
  685. $tp.find( '.ui_tpicker_' + litem + ' table' )
  686. .css( {
  687. width: size + '%',
  688. marginLeft: o.isRTL
  689. ? '0'
  690. : size / ( -2 * gridSize[ litem ] ) + '%',
  691. marginRight: o.isRTL
  692. ? size / ( -2 * gridSize[ litem ] ) + '%'
  693. : '0',
  694. borderCollapse: 'collapse',
  695. } )
  696. .find( 'td' )
  697. .click( function ( e ) {
  698. var $t = $( this ),
  699. h = $t.html(),
  700. n = parseInt( h.replace( /[^0-9]/g ), 10 ),
  701. ap = h.replace( /[^apm]/gi ),
  702. f = $t.data( 'for' ); // loses scope, so we use data-for
  703. if ( f === 'hour' ) {
  704. if ( ap.indexOf( 'p' ) !== -1 && n < 12 ) {
  705. n += 12;
  706. } else {
  707. if (
  708. ap.indexOf( 'a' ) !== -1 &&
  709. n === 12
  710. ) {
  711. n = 0;
  712. }
  713. }
  714. }
  715. tp_inst.control.value(
  716. tp_inst,
  717. tp_inst[ f + '_slider' ],
  718. litem,
  719. n
  720. );
  721. tp_inst._onTimeChange();
  722. tp_inst._onSelectHandler();
  723. } )
  724. .css( {
  725. cursor: 'pointer',
  726. width: 100 / gridSize[ litem ] + '%',
  727. textAlign: 'center',
  728. overflow: 'hidden',
  729. } );
  730. } // end if grid > 0
  731. } // end for loop
  732. // Add timezone options
  733. this.timezone_select = $tp
  734. .find( '.ui_tpicker_timezone' )
  735. .append( '<select></select>' )
  736. .find( 'select' );
  737. $.fn.append.apply(
  738. this.timezone_select,
  739. $.map( o.timezoneList, function ( val, idx ) {
  740. return $( '<option />' )
  741. .val( typeof val === 'object' ? val.value : val )
  742. .text( typeof val === 'object' ? val.label : val );
  743. } )
  744. );
  745. if (
  746. typeof this.timezone !== 'undefined' &&
  747. this.timezone !== null &&
  748. this.timezone !== ''
  749. ) {
  750. var local_timezone =
  751. new Date(
  752. this.inst.selectedYear,
  753. this.inst.selectedMonth,
  754. this.inst.selectedDay,
  755. 12
  756. ).getTimezoneOffset() * -1;
  757. if ( local_timezone === this.timezone ) {
  758. selectLocalTimezone( tp_inst );
  759. } else {
  760. this.timezone_select.val( this.timezone );
  761. }
  762. } else {
  763. if (
  764. typeof this.hour !== 'undefined' &&
  765. this.hour !== null &&
  766. this.hour !== ''
  767. ) {
  768. this.timezone_select.val( o.timezone );
  769. } else {
  770. selectLocalTimezone( tp_inst );
  771. }
  772. }
  773. this.timezone_select.change( function () {
  774. tp_inst._onTimeChange();
  775. tp_inst._onSelectHandler();
  776. tp_inst._afterInject();
  777. } );
  778. // End timezone options
  779. // inject timepicker into datepicker
  780. var $buttonPanel = $dp.find( '.ui-datepicker-buttonpane' );
  781. if ( $buttonPanel.length ) {
  782. $buttonPanel.before( $tp );
  783. } else {
  784. $dp.append( $tp );
  785. }
  786. this.$timeObj = $tp.find( '.ui_tpicker_time_input' );
  787. this.$timeObj.change( function () {
  788. var timeFormat = tp_inst.inst.settings.timeFormat;
  789. var parsedTime = $.datepicker.parseTime(
  790. timeFormat,
  791. this.value
  792. );
  793. var update = new Date();
  794. if ( parsedTime ) {
  795. update.setHours( parsedTime.hour );
  796. update.setMinutes( parsedTime.minute );
  797. update.setSeconds( parsedTime.second );
  798. $.datepicker._setTime( tp_inst.inst, update );
  799. } else {
  800. this.value = tp_inst.formattedTime;
  801. this.blur();
  802. }
  803. } );
  804. if ( this.inst !== null ) {
  805. var timeDefined = this.timeDefined;
  806. this._onTimeChange();
  807. this.timeDefined = timeDefined;
  808. }
  809. // slideAccess integration: http://trentrichardson.com/2011/11/11/jquery-ui-sliders-and-touch-accessibility/
  810. if ( this._defaults.addSliderAccess ) {
  811. var sliderAccessArgs = this._defaults.sliderAccessArgs,
  812. rtl = this._defaults.isRTL;
  813. sliderAccessArgs.isRTL = rtl;
  814. setTimeout( function () {
  815. // fix for inline mode
  816. if ( $tp.find( '.ui-slider-access' ).length === 0 ) {
  817. $tp.find( '.ui-slider:visible' ).sliderAccess(
  818. sliderAccessArgs
  819. );
  820. // fix any grids since sliders are shorter
  821. var sliderAccessWidth = $tp
  822. .find( '.ui-slider-access:eq(0)' )
  823. .outerWidth( true );
  824. if ( sliderAccessWidth ) {
  825. $tp.find( 'table:visible' ).each( function () {
  826. var $g = $( this ),
  827. oldWidth = $g.outerWidth(),
  828. oldMarginLeft = $g
  829. .css(
  830. rtl
  831. ? 'marginRight'
  832. : 'marginLeft'
  833. )
  834. .toString()
  835. .replace( '%', '' ),
  836. newWidth = oldWidth - sliderAccessWidth,
  837. newMarginLeft =
  838. ( oldMarginLeft * newWidth ) /
  839. oldWidth +
  840. '%',
  841. css = {
  842. width: newWidth,
  843. marginRight: 0,
  844. marginLeft: 0,
  845. };
  846. css[
  847. rtl ? 'marginRight' : 'marginLeft'
  848. ] = newMarginLeft;
  849. $g.css( css );
  850. } );
  851. }
  852. }
  853. }, 10 );
  854. }
  855. // end slideAccess integration
  856. tp_inst._limitMinMaxDateTime( this.inst, true );
  857. }
  858. },
  859. /*
  860. * This function tries to limit the ability to go outside the
  861. * min/max date range
  862. */
  863. _limitMinMaxDateTime: function ( dp_inst, adjustSliders ) {
  864. var o = this._defaults,
  865. dp_date = new Date(
  866. dp_inst.selectedYear,
  867. dp_inst.selectedMonth,
  868. dp_inst.selectedDay
  869. );
  870. if ( ! this._defaults.showTimepicker ) {
  871. return;
  872. } // No time so nothing to check here
  873. if (
  874. $.datepicker._get( dp_inst, 'minDateTime' ) !== null &&
  875. $.datepicker._get( dp_inst, 'minDateTime' ) !== undefined &&
  876. dp_date
  877. ) {
  878. var minDateTime = $.datepicker._get( dp_inst, 'minDateTime' ),
  879. minDateTimeDate = new Date(
  880. minDateTime.getFullYear(),
  881. minDateTime.getMonth(),
  882. minDateTime.getDate(),
  883. 0,
  884. 0,
  885. 0,
  886. 0
  887. );
  888. if (
  889. this.hourMinOriginal === null ||
  890. this.minuteMinOriginal === null ||
  891. this.secondMinOriginal === null ||
  892. this.millisecMinOriginal === null ||
  893. this.microsecMinOriginal === null
  894. ) {
  895. this.hourMinOriginal = o.hourMin;
  896. this.minuteMinOriginal = o.minuteMin;
  897. this.secondMinOriginal = o.secondMin;
  898. this.millisecMinOriginal = o.millisecMin;
  899. this.microsecMinOriginal = o.microsecMin;
  900. }
  901. if (
  902. dp_inst.settings.timeOnly ||
  903. minDateTimeDate.getTime() === dp_date.getTime()
  904. ) {
  905. this._defaults.hourMin = minDateTime.getHours();
  906. if ( this.hour <= this._defaults.hourMin ) {
  907. this.hour = this._defaults.hourMin;
  908. this._defaults.minuteMin = minDateTime.getMinutes();
  909. if ( this.minute <= this._defaults.minuteMin ) {
  910. this.minute = this._defaults.minuteMin;
  911. this._defaults.secondMin = minDateTime.getSeconds();
  912. if ( this.second <= this._defaults.secondMin ) {
  913. this.second = this._defaults.secondMin;
  914. this._defaults.millisecMin = minDateTime.getMilliseconds();
  915. if (
  916. this.millisec <= this._defaults.millisecMin
  917. ) {
  918. this.millisec = this._defaults.millisecMin;
  919. this._defaults.microsecMin = minDateTime.getMicroseconds();
  920. } else {
  921. if (
  922. this.microsec <
  923. this._defaults.microsecMin
  924. ) {
  925. this.microsec = this._defaults.microsecMin;
  926. }
  927. this._defaults.microsecMin = this.microsecMinOriginal;
  928. }
  929. } else {
  930. this._defaults.millisecMin = this.millisecMinOriginal;
  931. this._defaults.microsecMin = this.microsecMinOriginal;
  932. }
  933. } else {
  934. this._defaults.secondMin = this.secondMinOriginal;
  935. this._defaults.millisecMin = this.millisecMinOriginal;
  936. this._defaults.microsecMin = this.microsecMinOriginal;
  937. }
  938. } else {
  939. this._defaults.minuteMin = this.minuteMinOriginal;
  940. this._defaults.secondMin = this.secondMinOriginal;
  941. this._defaults.millisecMin = this.millisecMinOriginal;
  942. this._defaults.microsecMin = this.microsecMinOriginal;
  943. }
  944. } else {
  945. this._defaults.hourMin = this.hourMinOriginal;
  946. this._defaults.minuteMin = this.minuteMinOriginal;
  947. this._defaults.secondMin = this.secondMinOriginal;
  948. this._defaults.millisecMin = this.millisecMinOriginal;
  949. this._defaults.microsecMin = this.microsecMinOriginal;
  950. }
  951. }
  952. if (
  953. $.datepicker._get( dp_inst, 'maxDateTime' ) !== null &&
  954. $.datepicker._get( dp_inst, 'maxDateTime' ) !== undefined &&
  955. dp_date
  956. ) {
  957. var maxDateTime = $.datepicker._get( dp_inst, 'maxDateTime' ),
  958. maxDateTimeDate = new Date(
  959. maxDateTime.getFullYear(),
  960. maxDateTime.getMonth(),
  961. maxDateTime.getDate(),
  962. 0,
  963. 0,
  964. 0,
  965. 0
  966. );
  967. if (
  968. this.hourMaxOriginal === null ||
  969. this.minuteMaxOriginal === null ||
  970. this.secondMaxOriginal === null ||
  971. this.millisecMaxOriginal === null
  972. ) {
  973. this.hourMaxOriginal = o.hourMax;
  974. this.minuteMaxOriginal = o.minuteMax;
  975. this.secondMaxOriginal = o.secondMax;
  976. this.millisecMaxOriginal = o.millisecMax;
  977. this.microsecMaxOriginal = o.microsecMax;
  978. }
  979. if (
  980. dp_inst.settings.timeOnly ||
  981. maxDateTimeDate.getTime() === dp_date.getTime()
  982. ) {
  983. this._defaults.hourMax = maxDateTime.getHours();
  984. if ( this.hour >= this._defaults.hourMax ) {
  985. this.hour = this._defaults.hourMax;
  986. this._defaults.minuteMax = maxDateTime.getMinutes();
  987. if ( this.minute >= this._defaults.minuteMax ) {
  988. this.minute = this._defaults.minuteMax;
  989. this._defaults.secondMax = maxDateTime.getSeconds();
  990. if ( this.second >= this._defaults.secondMax ) {
  991. this.second = this._defaults.secondMax;
  992. this._defaults.millisecMax = maxDateTime.getMilliseconds();
  993. if (
  994. this.millisec >= this._defaults.millisecMax
  995. ) {
  996. this.millisec = this._defaults.millisecMax;
  997. this._defaults.microsecMax = maxDateTime.getMicroseconds();
  998. } else {
  999. if (
  1000. this.microsec >
  1001. this._defaults.microsecMax
  1002. ) {
  1003. this.microsec = this._defaults.microsecMax;
  1004. }
  1005. this._defaults.microsecMax = this.microsecMaxOriginal;
  1006. }
  1007. } else {
  1008. this._defaults.millisecMax = this.millisecMaxOriginal;
  1009. this._defaults.microsecMax = this.microsecMaxOriginal;
  1010. }
  1011. } else {
  1012. this._defaults.secondMax = this.secondMaxOriginal;
  1013. this._defaults.millisecMax = this.millisecMaxOriginal;
  1014. this._defaults.microsecMax = this.microsecMaxOriginal;
  1015. }
  1016. } else {
  1017. this._defaults.minuteMax = this.minuteMaxOriginal;
  1018. this._defaults.secondMax = this.secondMaxOriginal;
  1019. this._defaults.millisecMax = this.millisecMaxOriginal;
  1020. this._defaults.microsecMax = this.microsecMaxOriginal;
  1021. }
  1022. } else {
  1023. this._defaults.hourMax = this.hourMaxOriginal;
  1024. this._defaults.minuteMax = this.minuteMaxOriginal;
  1025. this._defaults.secondMax = this.secondMaxOriginal;
  1026. this._defaults.millisecMax = this.millisecMaxOriginal;
  1027. this._defaults.microsecMax = this.microsecMaxOriginal;
  1028. }
  1029. }
  1030. if ( dp_inst.settings.minTime !== null ) {
  1031. var tempMinTime = new Date(
  1032. '01/01/1970 ' + dp_inst.settings.minTime
  1033. );
  1034. if ( this.hour < tempMinTime.getHours() ) {
  1035. this.hour = this._defaults.hourMin = tempMinTime.getHours();
  1036. this.minute = this._defaults.minuteMin = tempMinTime.getMinutes();
  1037. } else if (
  1038. this.hour === tempMinTime.getHours() &&
  1039. this.minute < tempMinTime.getMinutes()
  1040. ) {
  1041. this.minute = this._defaults.minuteMin = tempMinTime.getMinutes();
  1042. } else {
  1043. if ( this._defaults.hourMin < tempMinTime.getHours() ) {
  1044. this._defaults.hourMin = tempMinTime.getHours();
  1045. this._defaults.minuteMin = tempMinTime.getMinutes();
  1046. } else if (
  1047. ( this._defaults.hourMin ===
  1048. tempMinTime.getHours() ) ===
  1049. this.hour &&
  1050. this._defaults.minuteMin < tempMinTime.getMinutes()
  1051. ) {
  1052. this._defaults.minuteMin = tempMinTime.getMinutes();
  1053. } else {
  1054. this._defaults.minuteMin = 0;
  1055. }
  1056. }
  1057. }
  1058. if ( dp_inst.settings.maxTime !== null ) {
  1059. var tempMaxTime = new Date(
  1060. '01/01/1970 ' + dp_inst.settings.maxTime
  1061. );
  1062. if ( this.hour > tempMaxTime.getHours() ) {
  1063. this.hour = this._defaults.hourMax = tempMaxTime.getHours();
  1064. this.minute = this._defaults.minuteMax = tempMaxTime.getMinutes();
  1065. } else if (
  1066. this.hour === tempMaxTime.getHours() &&
  1067. this.minute > tempMaxTime.getMinutes()
  1068. ) {
  1069. this.minute = this._defaults.minuteMax = tempMaxTime.getMinutes();
  1070. } else {
  1071. if ( this._defaults.hourMax > tempMaxTime.getHours() ) {
  1072. this._defaults.hourMax = tempMaxTime.getHours();
  1073. this._defaults.minuteMax = tempMaxTime.getMinutes();
  1074. } else if (
  1075. ( this._defaults.hourMax ===
  1076. tempMaxTime.getHours() ) ===
  1077. this.hour &&
  1078. this._defaults.minuteMax > tempMaxTime.getMinutes()
  1079. ) {
  1080. this._defaults.minuteMax = tempMaxTime.getMinutes();
  1081. } else {
  1082. this._defaults.minuteMax = 59;
  1083. }
  1084. }
  1085. }
  1086. if ( adjustSliders !== undefined && adjustSliders === true ) {
  1087. var hourMax = parseInt(
  1088. this._defaults.hourMax -
  1089. ( ( this._defaults.hourMax -
  1090. this._defaults.hourMin ) %
  1091. this._defaults.stepHour ),
  1092. 10
  1093. ),
  1094. minMax = parseInt(
  1095. this._defaults.minuteMax -
  1096. ( ( this._defaults.minuteMax -
  1097. this._defaults.minuteMin ) %
  1098. this._defaults.stepMinute ),
  1099. 10
  1100. ),
  1101. secMax = parseInt(
  1102. this._defaults.secondMax -
  1103. ( ( this._defaults.secondMax -
  1104. this._defaults.secondMin ) %
  1105. this._defaults.stepSecond ),
  1106. 10
  1107. ),
  1108. millisecMax = parseInt(
  1109. this._defaults.millisecMax -
  1110. ( ( this._defaults.millisecMax -
  1111. this._defaults.millisecMin ) %
  1112. this._defaults.stepMillisec ),
  1113. 10
  1114. ),
  1115. microsecMax = parseInt(
  1116. this._defaults.microsecMax -
  1117. ( ( this._defaults.microsecMax -
  1118. this._defaults.microsecMin ) %
  1119. this._defaults.stepMicrosec ),
  1120. 10
  1121. );
  1122. if ( this.hour_slider ) {
  1123. this.control.options( this, this.hour_slider, 'hour', {
  1124. min: this._defaults.hourMin,
  1125. max: hourMax,
  1126. step: this._defaults.stepHour,
  1127. } );
  1128. this.control.value(
  1129. this,
  1130. this.hour_slider,
  1131. 'hour',
  1132. this.hour - ( this.hour % this._defaults.stepHour )
  1133. );
  1134. }
  1135. if ( this.minute_slider ) {
  1136. this.control.options( this, this.minute_slider, 'minute', {
  1137. min: this._defaults.minuteMin,
  1138. max: minMax,
  1139. step: this._defaults.stepMinute,
  1140. } );
  1141. this.control.value(
  1142. this,
  1143. this.minute_slider,
  1144. 'minute',
  1145. this.minute -
  1146. ( this.minute % this._defaults.stepMinute )
  1147. );
  1148. }
  1149. if ( this.second_slider ) {
  1150. this.control.options( this, this.second_slider, 'second', {
  1151. min: this._defaults.secondMin,
  1152. max: secMax,
  1153. step: this._defaults.stepSecond,
  1154. } );
  1155. this.control.value(
  1156. this,
  1157. this.second_slider,
  1158. 'second',
  1159. this.second -
  1160. ( this.second % this._defaults.stepSecond )
  1161. );
  1162. }
  1163. if ( this.millisec_slider ) {
  1164. this.control.options(
  1165. this,
  1166. this.millisec_slider,
  1167. 'millisec',
  1168. {
  1169. min: this._defaults.millisecMin,
  1170. max: millisecMax,
  1171. step: this._defaults.stepMillisec,
  1172. }
  1173. );
  1174. this.control.value(
  1175. this,
  1176. this.millisec_slider,
  1177. 'millisec',
  1178. this.millisec -
  1179. ( this.millisec % this._defaults.stepMillisec )
  1180. );
  1181. }
  1182. if ( this.microsec_slider ) {
  1183. this.control.options(
  1184. this,
  1185. this.microsec_slider,
  1186. 'microsec',
  1187. {
  1188. min: this._defaults.microsecMin,
  1189. max: microsecMax,
  1190. step: this._defaults.stepMicrosec,
  1191. }
  1192. );
  1193. this.control.value(
  1194. this,
  1195. this.microsec_slider,
  1196. 'microsec',
  1197. this.microsec -
  1198. ( this.microsec % this._defaults.stepMicrosec )
  1199. );
  1200. }
  1201. }
  1202. },
  1203. /*
  1204. * when a slider moves, set the internal time...
  1205. * on time change is also called when the time is updated in the text field
  1206. */
  1207. _onTimeChange: function () {
  1208. if ( ! this._defaults.showTimepicker ) {
  1209. return;
  1210. }
  1211. var hour = this.hour_slider
  1212. ? this.control.value( this, this.hour_slider, 'hour' )
  1213. : false,
  1214. minute = this.minute_slider
  1215. ? this.control.value( this, this.minute_slider, 'minute' )
  1216. : false,
  1217. second = this.second_slider
  1218. ? this.control.value( this, this.second_slider, 'second' )
  1219. : false,
  1220. millisec = this.millisec_slider
  1221. ? this.control.value(
  1222. this,
  1223. this.millisec_slider,
  1224. 'millisec'
  1225. )
  1226. : false,
  1227. microsec = this.microsec_slider
  1228. ? this.control.value(
  1229. this,
  1230. this.microsec_slider,
  1231. 'microsec'
  1232. )
  1233. : false,
  1234. timezone = this.timezone_select
  1235. ? this.timezone_select.val()
  1236. : false,
  1237. o = this._defaults,
  1238. pickerTimeFormat = o.pickerTimeFormat || o.timeFormat,
  1239. pickerTimeSuffix = o.pickerTimeSuffix || o.timeSuffix;
  1240. if ( typeof hour === 'object' ) {
  1241. hour = false;
  1242. }
  1243. if ( typeof minute === 'object' ) {
  1244. minute = false;
  1245. }
  1246. if ( typeof second === 'object' ) {
  1247. second = false;
  1248. }
  1249. if ( typeof millisec === 'object' ) {
  1250. millisec = false;
  1251. }
  1252. if ( typeof microsec === 'object' ) {
  1253. microsec = false;
  1254. }
  1255. if ( typeof timezone === 'object' ) {
  1256. timezone = false;
  1257. }
  1258. if ( hour !== false ) {
  1259. hour = parseInt( hour, 10 );
  1260. }
  1261. if ( minute !== false ) {
  1262. minute = parseInt( minute, 10 );
  1263. }
  1264. if ( second !== false ) {
  1265. second = parseInt( second, 10 );
  1266. }
  1267. if ( millisec !== false ) {
  1268. millisec = parseInt( millisec, 10 );
  1269. }
  1270. if ( microsec !== false ) {
  1271. microsec = parseInt( microsec, 10 );
  1272. }
  1273. if ( timezone !== false ) {
  1274. timezone = timezone.toString();
  1275. }
  1276. var ampm = o[ hour < 12 ? 'amNames' : 'pmNames' ][ 0 ];
  1277. // If the update was done in the input field, the input field should not be updated.
  1278. // If the update was done using the sliders, update the input field.
  1279. var hasChanged =
  1280. hour !== parseInt( this.hour, 10 ) || // sliders should all be numeric
  1281. minute !== parseInt( this.minute, 10 ) ||
  1282. second !== parseInt( this.second, 10 ) ||
  1283. millisec !== parseInt( this.millisec, 10 ) ||
  1284. microsec !== parseInt( this.microsec, 10 ) ||
  1285. ( this.ampm.length > 0 &&
  1286. hour < 12 !==
  1287. ( $.inArray( this.ampm.toUpperCase(), this.amNames ) !==
  1288. -1 ) ) ||
  1289. ( this.timezone !== null &&
  1290. timezone !== this.timezone.toString() ); // could be numeric or "EST" format, so use toString()
  1291. if ( hasChanged ) {
  1292. if ( hour !== false ) {
  1293. this.hour = hour;
  1294. }
  1295. if ( minute !== false ) {
  1296. this.minute = minute;
  1297. }
  1298. if ( second !== false ) {
  1299. this.second = second;
  1300. }
  1301. if ( millisec !== false ) {
  1302. this.millisec = millisec;
  1303. }
  1304. if ( microsec !== false ) {
  1305. this.microsec = microsec;
  1306. }
  1307. if ( timezone !== false ) {
  1308. this.timezone = timezone;
  1309. }
  1310. if ( ! this.inst ) {
  1311. this.inst = $.datepicker._getInst( this.$input[ 0 ] );
  1312. }
  1313. this._limitMinMaxDateTime( this.inst, true );
  1314. }
  1315. if ( this.support.ampm ) {
  1316. this.ampm = ampm;
  1317. }
  1318. // Updates the time within the timepicker
  1319. this.formattedTime = $.datepicker.formatTime(
  1320. o.timeFormat,
  1321. this,
  1322. o
  1323. );
  1324. if ( this.$timeObj ) {
  1325. if ( pickerTimeFormat === o.timeFormat ) {
  1326. this.$timeObj.val( this.formattedTime + pickerTimeSuffix );
  1327. } else {
  1328. this.$timeObj.val(
  1329. $.datepicker.formatTime( pickerTimeFormat, this, o ) +
  1330. pickerTimeSuffix
  1331. );
  1332. }
  1333. /*
  1334. // Input loses focus when typing with picker open
  1335. // https://github.com/trentrichardson/jQuery-Timepicker-Addon/issues/848
  1336. if (this.$timeObj[0].setSelectionRange) {
  1337. var sPos = this.$timeObj[0].selectionStart;
  1338. var ePos = this.$timeObj[0].selectionEnd;
  1339. this.$timeObj[0].setSelectionRange(sPos, ePos);
  1340. }
  1341. */
  1342. }
  1343. this.timeDefined = true;
  1344. if ( hasChanged ) {
  1345. this._updateDateTime();
  1346. //this.$input.focus(); // may automatically open the picker on setDate
  1347. }
  1348. },
  1349. /*
  1350. * call custom onSelect.
  1351. * bind to sliders slidestop, and grid click.
  1352. */
  1353. _onSelectHandler: function () {
  1354. var onSelect =
  1355. this._defaults.onSelect || this.inst.settings.onSelect;
  1356. var inputEl = this.$input ? this.$input[ 0 ] : null;
  1357. if ( onSelect && inputEl ) {
  1358. onSelect.apply( inputEl, [ this.formattedDateTime, this ] );
  1359. }
  1360. },
  1361. /*
  1362. * update our input with the new date time..
  1363. */
  1364. _updateDateTime: function ( dp_inst ) {
  1365. dp_inst = this.inst || dp_inst;
  1366. var dtTmp =
  1367. dp_inst.currentYear > 0
  1368. ? new Date(
  1369. dp_inst.currentYear,
  1370. dp_inst.currentMonth,
  1371. dp_inst.currentDay
  1372. )
  1373. : new Date(
  1374. dp_inst.selectedYear,
  1375. dp_inst.selectedMonth,
  1376. dp_inst.selectedDay
  1377. ),
  1378. dt = $.datepicker._daylightSavingAdjust( dtTmp ),
  1379. //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay)),
  1380. //dt = $.datepicker._daylightSavingAdjust(new Date(dp_inst.currentYear, dp_inst.currentMonth, dp_inst.currentDay)),
  1381. dateFmt = $.datepicker._get( dp_inst, 'dateFormat' ),
  1382. formatCfg = $.datepicker._getFormatConfig( dp_inst ),
  1383. timeAvailable = dt !== null && this.timeDefined;
  1384. this.formattedDate = $.datepicker.formatDate(
  1385. dateFmt,
  1386. dt === null ? new Date() : dt,
  1387. formatCfg
  1388. );
  1389. var formattedDateTime = this.formattedDate;
  1390. // if a slider was changed but datepicker doesn't have a value yet, set it
  1391. if ( dp_inst.lastVal === '' ) {
  1392. dp_inst.currentYear = dp_inst.selectedYear;
  1393. dp_inst.currentMonth = dp_inst.selectedMonth;
  1394. dp_inst.currentDay = dp_inst.selectedDay;
  1395. }
  1396. /*
  1397. * remove following lines to force every changes in date picker to change the input value
  1398. * Bug descriptions: when an input field has a default value, and click on the field to pop up the date picker.
  1399. * If the user manually empty the value in the input field, the date picker will never change selected value.
  1400. */
  1401. //if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0)) {
  1402. // return;
  1403. //}
  1404. if (
  1405. this._defaults.timeOnly === true &&
  1406. this._defaults.timeOnlyShowDate === false
  1407. ) {
  1408. formattedDateTime = this.formattedTime;
  1409. } else if (
  1410. ( this._defaults.timeOnly !== true &&
  1411. ( this._defaults.alwaysSetTime || timeAvailable ) ) ||
  1412. ( this._defaults.timeOnly === true &&
  1413. this._defaults.timeOnlyShowDate === true )
  1414. ) {
  1415. formattedDateTime +=
  1416. this._defaults.separator +
  1417. this.formattedTime +
  1418. this._defaults.timeSuffix;
  1419. }
  1420. this.formattedDateTime = formattedDateTime;
  1421. if ( ! this._defaults.showTimepicker ) {
  1422. this.$input.val( this.formattedDate );
  1423. } else if (
  1424. this.$altInput &&
  1425. this._defaults.timeOnly === false &&
  1426. this._defaults.altFieldTimeOnly === true
  1427. ) {
  1428. this.$altInput.val( this.formattedTime );
  1429. this.$input.val( this.formattedDate );
  1430. } else if ( this.$altInput ) {
  1431. this.$input.val( formattedDateTime );
  1432. var altFormattedDateTime = '',
  1433. altSeparator =
  1434. this._defaults.altSeparator !== null
  1435. ? this._defaults.altSeparator
  1436. : this._defaults.separator,
  1437. altTimeSuffix =
  1438. this._defaults.altTimeSuffix !== null
  1439. ? this._defaults.altTimeSuffix
  1440. : this._defaults.timeSuffix;
  1441. if ( ! this._defaults.timeOnly ) {
  1442. if ( this._defaults.altFormat ) {
  1443. altFormattedDateTime = $.datepicker.formatDate(
  1444. this._defaults.altFormat,
  1445. dt === null ? new Date() : dt,
  1446. formatCfg
  1447. );
  1448. } else {
  1449. altFormattedDateTime = this.formattedDate;
  1450. }
  1451. if ( altFormattedDateTime ) {
  1452. altFormattedDateTime += altSeparator;
  1453. }
  1454. }
  1455. if ( this._defaults.altTimeFormat !== null ) {
  1456. altFormattedDateTime +=
  1457. $.datepicker.formatTime(
  1458. this._defaults.altTimeFormat,
  1459. this,
  1460. this._defaults
  1461. ) + altTimeSuffix;
  1462. } else {
  1463. altFormattedDateTime += this.formattedTime + altTimeSuffix;
  1464. }
  1465. this.$altInput.val( altFormattedDateTime );
  1466. } else {
  1467. this.$input.val( formattedDateTime );
  1468. }
  1469. this.$input.trigger( 'change' );
  1470. },
  1471. _onFocus: function () {
  1472. if ( ! this.$input.val() && this._defaults.defaultValue ) {
  1473. this.$input.val( this._defaults.defaultValue );
  1474. var inst = $.datepicker._getInst( this.$input.get( 0 ) ),
  1475. tp_inst = $.datepicker._get( inst, 'timepicker' );
  1476. if ( tp_inst ) {
  1477. if (
  1478. tp_inst._defaults.timeOnly &&
  1479. inst.input.val() !== inst.lastVal
  1480. ) {
  1481. try {
  1482. $.datepicker._updateDatepicker( inst );
  1483. } catch ( err ) {
  1484. $.timepicker.log( err );
  1485. }
  1486. }
  1487. }
  1488. }
  1489. },
  1490. /*
  1491. * Small abstraction to control types
  1492. * We can add more, just be sure to follow the pattern: create, options, value
  1493. */
  1494. _controls: {
  1495. // slider methods
  1496. slider: {
  1497. create: function ( tp_inst, obj, unit, val, min, max, step ) {
  1498. var rtl = tp_inst._defaults.isRTL; // if rtl go -60->0 instead of 0->60
  1499. return obj.prop( 'slide', null ).slider( {
  1500. orientation: 'horizontal',
  1501. value: rtl ? val * -1 : val,
  1502. min: rtl ? max * -1 : min,
  1503. max: rtl ? min * -1 : max,
  1504. step: step,
  1505. slide: function ( event, ui ) {
  1506. tp_inst.control.value(
  1507. tp_inst,
  1508. $( this ),
  1509. unit,
  1510. rtl ? ui.value * -1 : ui.value
  1511. );
  1512. tp_inst._onTimeChange();
  1513. },
  1514. stop: function ( event, ui ) {
  1515. tp_inst._onSelectHandler();
  1516. },
  1517. } );
  1518. },
  1519. options: function ( tp_inst, obj, unit, opts, val ) {
  1520. if ( tp_inst._defaults.isRTL ) {
  1521. if ( typeof opts === 'string' ) {
  1522. if ( opts === 'min' || opts === 'max' ) {
  1523. if ( val !== undefined ) {
  1524. return obj.slider( opts, val * -1 );
  1525. }
  1526. return Math.abs( obj.slider( opts ) );
  1527. }
  1528. return obj.slider( opts );
  1529. }
  1530. var min = opts.min,
  1531. max = opts.max;
  1532. opts.min = opts.max = null;
  1533. if ( min !== undefined ) {
  1534. opts.max = min * -1;
  1535. }
  1536. if ( max !== undefined ) {
  1537. opts.min = max * -1;
  1538. }
  1539. return obj.slider( opts );
  1540. }
  1541. if ( typeof opts === 'string' && val !== undefined ) {
  1542. return obj.slider( opts, val );
  1543. }
  1544. return obj.slider( opts );
  1545. },
  1546. value: function ( tp_inst, obj, unit, val ) {
  1547. if ( tp_inst._defaults.isRTL ) {
  1548. if ( val !== undefined ) {
  1549. return obj.slider( 'value', val * -1 );
  1550. }
  1551. return Math.abs( obj.slider( 'value' ) );
  1552. }
  1553. if ( val !== undefined ) {
  1554. return obj.slider( 'value', val );
  1555. }
  1556. return obj.slider( 'value' );
  1557. },
  1558. },
  1559. // select methods
  1560. select: {
  1561. create: function ( tp_inst, obj, unit, val, min, max, step ) {
  1562. var sel =
  1563. '<select class="ui-timepicker-select ui-state-default ui-corner-all" data-unit="' +
  1564. unit +
  1565. '" data-min="' +
  1566. min +
  1567. '" data-max="' +
  1568. max +
  1569. '" data-step="' +
  1570. step +
  1571. '">',
  1572. format =
  1573. tp_inst._defaults.pickerTimeFormat ||
  1574. tp_inst._defaults.timeFormat;
  1575. for ( var i = min; i <= max; i += step ) {
  1576. sel +=
  1577. '<option value="' +
  1578. i +
  1579. '"' +
  1580. ( i === val ? ' selected' : '' ) +
  1581. '>';
  1582. if ( unit === 'hour' ) {
  1583. sel += $.datepicker.formatTime(
  1584. $.trim( format.replace( /[^ht ]/gi, '' ) ),
  1585. { hour: i },
  1586. tp_inst._defaults
  1587. );
  1588. } else if (
  1589. unit === 'millisec' ||
  1590. unit === 'microsec' ||
  1591. i >= 10
  1592. ) {
  1593. sel += i;
  1594. } else {
  1595. sel += '0' + i.toString();
  1596. }
  1597. sel += '</option>';
  1598. }
  1599. sel += '</select>';
  1600. obj.children( 'select' ).remove();
  1601. $( sel )
  1602. .appendTo( obj )
  1603. .change( function ( e ) {
  1604. tp_inst._onTimeChange();
  1605. tp_inst._onSelectHandler();
  1606. tp_inst._afterInject();
  1607. } );
  1608. return obj;
  1609. },
  1610. options: function ( tp_inst, obj, unit, opts, val ) {
  1611. var o = {},
  1612. $t = obj.children( 'select' );
  1613. if ( typeof opts === 'string' ) {
  1614. if ( val === undefined ) {
  1615. return $t.data( opts );
  1616. }
  1617. o[ opts ] = val;
  1618. } else {
  1619. o = opts;
  1620. }
  1621. return tp_inst.control.create(
  1622. tp_inst,
  1623. obj,
  1624. $t.data( 'unit' ),
  1625. $t.val(),
  1626. o.min >= 0 ? o.min : $t.data( 'min' ),
  1627. o.max || $t.data( 'max' ),
  1628. o.step || $t.data( 'step' )
  1629. );
  1630. },
  1631. value: function ( tp_inst, obj, unit, val ) {
  1632. var $t = obj.children( 'select' );
  1633. if ( val !== undefined ) {
  1634. return $t.val( val );
  1635. }
  1636. return $t.val();
  1637. },
  1638. },
  1639. }, // end _controls
  1640. } );
  1641. $.fn.extend( {
  1642. /*
  1643. * shorthand just to use timepicker.
  1644. */
  1645. timepicker: function ( o ) {
  1646. o = o || {};
  1647. var tmp_args = Array.prototype.slice.call( arguments );
  1648. if ( typeof o === 'object' ) {
  1649. tmp_args[ 0 ] = $.extend( o, {
  1650. timeOnly: true,
  1651. } );
  1652. }
  1653. return $( this ).each( function () {
  1654. $.fn.datetimepicker.apply( $( this ), tmp_args );
  1655. } );
  1656. },
  1657. /*
  1658. * extend timepicker to datepicker
  1659. */
  1660. datetimepicker: function ( o ) {
  1661. o = o || {};
  1662. var tmp_args = arguments;
  1663. if ( typeof o === 'string' ) {
  1664. if (
  1665. o === 'getDate' ||
  1666. ( o === 'option' &&
  1667. tmp_args.length === 2 &&
  1668. typeof tmp_args[ 1 ] === 'string' )
  1669. ) {
  1670. return $.fn.datepicker.apply( $( this[ 0 ] ), tmp_args );
  1671. } else {
  1672. return this.each( function () {
  1673. var $t = $( this );
  1674. $t.datepicker.apply( $t, tmp_args );
  1675. } );
  1676. }
  1677. } else {
  1678. return this.each( function () {
  1679. var $t = $( this );
  1680. $t.datepicker( $.timepicker._newInst( $t, o )._defaults );
  1681. } );
  1682. }
  1683. },
  1684. } );
  1685. /*
  1686. * Public Utility to parse date and time
  1687. */
  1688. $.datepicker.parseDateTime = function (
  1689. dateFormat,
  1690. timeFormat,
  1691. dateTimeString,
  1692. dateSettings,
  1693. timeSettings
  1694. ) {
  1695. var parseRes = parseDateTimeInternal(
  1696. dateFormat,
  1697. timeFormat,
  1698. dateTimeString,
  1699. dateSettings,
  1700. timeSettings
  1701. );
  1702. if ( parseRes.timeObj ) {
  1703. var t = parseRes.timeObj;
  1704. parseRes.date.setHours( t.hour, t.minute, t.second, t.millisec );
  1705. parseRes.date.setMicroseconds( t.microsec );
  1706. }
  1707. return parseRes.date;
  1708. };
  1709. /*
  1710. * Public utility to parse time
  1711. */
  1712. $.datepicker.parseTime = function ( timeFormat, timeString, options ) {
  1713. var o = extendRemove(
  1714. extendRemove( {}, $.timepicker._defaults ),
  1715. options || {}
  1716. ),
  1717. iso8601 =
  1718. timeFormat.replace( /\'.*?\'/g, '' ).indexOf( 'Z' ) !== -1;
  1719. // Strict parse requires the timeString to match the timeFormat exactly
  1720. var strictParse = function ( f, s, o ) {
  1721. // pattern for standard and localized AM/PM markers
  1722. var getPatternAmpm = function ( amNames, pmNames ) {
  1723. var markers = [];
  1724. if ( amNames ) {
  1725. $.merge( markers, amNames );
  1726. }
  1727. if ( pmNames ) {
  1728. $.merge( markers, pmNames );
  1729. }
  1730. markers = $.map( markers, function ( val ) {
  1731. return val.replace( /[.*+?|()\[\]{}\\]/g, '\\$&' );
  1732. } );
  1733. return '(' + markers.join( '|' ) + ')?';
  1734. };
  1735. // figure out position of time elements.. cause js cant do named captures
  1736. var getFormatPositions = function ( timeFormat ) {
  1737. var finds = timeFormat
  1738. .toLowerCase()
  1739. .match(
  1740. /(h{1,2}|m{1,2}|s{1,2}|l{1}|c{1}|t{1,2}|z|'.*?')/g
  1741. ),
  1742. orders = {
  1743. h: -1,
  1744. m: -1,
  1745. s: -1,
  1746. l: -1,
  1747. c: -1,
  1748. t: -1,
  1749. z: -1,
  1750. };
  1751. if ( finds ) {
  1752. for ( var i = 0; i < finds.length; i++ ) {
  1753. if (
  1754. orders[ finds[ i ].toString().charAt( 0 ) ] === -1
  1755. ) {
  1756. orders[ finds[ i ].toString().charAt( 0 ) ] = i + 1;
  1757. }
  1758. }
  1759. }
  1760. return orders;
  1761. };
  1762. var regstr =
  1763. '^' +
  1764. f
  1765. .toString()
  1766. .replace(
  1767. /([hH]{1,2}|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g,
  1768. function ( match ) {
  1769. var ml = match.length;
  1770. switch ( match.charAt( 0 ).toLowerCase() ) {
  1771. case 'h':
  1772. return ml === 1
  1773. ? '(\\d?\\d)'
  1774. : '(\\d{' + ml + '})';
  1775. case 'm':
  1776. return ml === 1
  1777. ? '(\\d?\\d)'
  1778. : '(\\d{' + ml + '})';
  1779. case 's':
  1780. return ml === 1
  1781. ? '(\\d?\\d)'
  1782. : '(\\d{' + ml + '})';
  1783. case 'l':
  1784. return '(\\d?\\d?\\d)';
  1785. case 'c':
  1786. return '(\\d?\\d?\\d)';
  1787. case 'z':
  1788. return '(z|[-+]\\d\\d:?\\d\\d|\\S+)?';
  1789. case 't':
  1790. return getPatternAmpm(
  1791. o.amNames,
  1792. o.pmNames
  1793. );
  1794. default:
  1795. // literal escaped in quotes
  1796. return (
  1797. '(' +
  1798. match
  1799. .replace( /\'/g, '' )
  1800. .replace(
  1801. /(\.|\$|\^|\\|\/|\(|\)|\[|\]|\?|\+|\*)/g,
  1802. function ( m ) {
  1803. return '\\' + m;
  1804. }
  1805. ) +
  1806. ')?'
  1807. );
  1808. }
  1809. }
  1810. )
  1811. .replace( /\s/g, '\\s?' ) +
  1812. o.timeSuffix +
  1813. '$',
  1814. order = getFormatPositions( f ),
  1815. ampm = '',
  1816. treg;
  1817. treg = s.match( new RegExp( regstr, 'i' ) );
  1818. var resTime = {
  1819. hour: 0,
  1820. minute: 0,
  1821. second: 0,
  1822. millisec: 0,
  1823. microsec: 0,
  1824. };
  1825. if ( treg ) {
  1826. if ( order.t !== -1 ) {
  1827. if (
  1828. treg[ order.t ] === undefined ||
  1829. treg[ order.t ].length === 0
  1830. ) {
  1831. ampm = '';
  1832. resTime.ampm = '';
  1833. } else {
  1834. ampm =
  1835. $.inArray(
  1836. treg[ order.t ].toUpperCase(),
  1837. $.map( o.amNames, function ( x, i ) {
  1838. return x.toUpperCase();
  1839. } )
  1840. ) !== -1
  1841. ? 'AM'
  1842. : 'PM';
  1843. resTime.ampm =
  1844. o[ ampm === 'AM' ? 'amNames' : 'pmNames' ][ 0 ];
  1845. }
  1846. }
  1847. if ( order.h !== -1 ) {
  1848. if ( ampm === 'AM' && treg[ order.h ] === '12' ) {
  1849. resTime.hour = 0; // 12am = 0 hour
  1850. } else {
  1851. if ( ampm === 'PM' && treg[ order.h ] !== '12' ) {
  1852. resTime.hour = parseInt( treg[ order.h ], 10 ) + 12; // 12pm = 12 hour, any other pm = hour + 12
  1853. } else {
  1854. resTime.hour = Number( treg[ order.h ] );
  1855. }
  1856. }
  1857. }
  1858. if ( order.m !== -1 ) {
  1859. resTime.minute = Number( treg[ order.m ] );
  1860. }
  1861. if ( order.s !== -1 ) {
  1862. resTime.second = Number( treg[ order.s ] );
  1863. }
  1864. if ( order.l !== -1 ) {
  1865. resTime.millisec = Number( treg[ order.l ] );
  1866. }
  1867. if ( order.c !== -1 ) {
  1868. resTime.microsec = Number( treg[ order.c ] );
  1869. }
  1870. if ( order.z !== -1 && treg[ order.z ] !== undefined ) {
  1871. resTime.timezone = $.timepicker.timezoneOffsetNumber(
  1872. treg[ order.z ]
  1873. );
  1874. }
  1875. return resTime;
  1876. }
  1877. return false;
  1878. }; // end strictParse
  1879. // First try JS Date, if that fails, use strictParse
  1880. var looseParse = function ( f, s, o ) {
  1881. try {
  1882. var d = new Date( '2012-01-01 ' + s );
  1883. if ( isNaN( d.getTime() ) ) {
  1884. d = new Date( '2012-01-01T' + s );
  1885. if ( isNaN( d.getTime() ) ) {
  1886. d = new Date( '01/01/2012 ' + s );
  1887. if ( isNaN( d.getTime() ) ) {
  1888. throw 'Unable to parse time with native Date: ' + s;
  1889. }
  1890. }
  1891. }
  1892. return {
  1893. hour: d.getHours(),
  1894. minute: d.getMinutes(),
  1895. second: d.getSeconds(),
  1896. millisec: d.getMilliseconds(),
  1897. microsec: d.getMicroseconds(),
  1898. timezone: d.getTimezoneOffset() * -1,
  1899. };
  1900. } catch ( err ) {
  1901. try {
  1902. return strictParse( f, s, o );
  1903. } catch ( err2 ) {
  1904. $.timepicker.log(
  1905. 'Unable to parse \ntimeString: ' +
  1906. s +
  1907. '\ntimeFormat: ' +
  1908. f
  1909. );
  1910. }
  1911. }
  1912. return false;
  1913. }; // end looseParse
  1914. if ( typeof o.parse === 'function' ) {
  1915. return o.parse( timeFormat, timeString, o );
  1916. }
  1917. if ( o.parse === 'loose' ) {
  1918. return looseParse( timeFormat, timeString, o );
  1919. }
  1920. return strictParse( timeFormat, timeString, o );
  1921. };
  1922. /**
  1923. * Public utility to format the time
  1924. * @param {string} format format of the time
  1925. * @param {Object} time Object not a Date for timezones
  1926. * @param {Object} [options] essentially the regional[].. amNames, pmNames, ampm
  1927. * @returns {string} the formatted time
  1928. */
  1929. $.datepicker.formatTime = function ( format, time, options ) {
  1930. options = options || {};
  1931. options = $.extend( {}, $.timepicker._defaults, options );
  1932. time = $.extend(
  1933. {
  1934. hour: 0,
  1935. minute: 0,
  1936. second: 0,
  1937. millisec: 0,
  1938. microsec: 0,
  1939. timezone: null,
  1940. },
  1941. time
  1942. );
  1943. var tmptime = format,
  1944. ampmName = options.amNames[ 0 ],
  1945. hour = parseInt( time.hour, 10 );
  1946. if ( hour > 11 ) {
  1947. ampmName = options.pmNames[ 0 ];
  1948. }
  1949. tmptime = tmptime.replace(
  1950. /(?:HH?|hh?|mm?|ss?|[tT]{1,2}|[zZ]|[lc]|'.*?')/g,
  1951. function ( match ) {
  1952. switch ( match ) {
  1953. case 'HH':
  1954. return ( '0' + hour ).slice( -2 );
  1955. case 'H':
  1956. return hour;
  1957. case 'hh':
  1958. return ( '0' + convert24to12( hour ) ).slice( -2 );
  1959. case 'h':
  1960. return convert24to12( hour );
  1961. case 'mm':
  1962. return ( '0' + time.minute ).slice( -2 );
  1963. case 'm':
  1964. return time.minute;
  1965. case 'ss':
  1966. return ( '0' + time.second ).slice( -2 );
  1967. case 's':
  1968. return time.second;
  1969. case 'l':
  1970. return ( '00' + time.millisec ).slice( -3 );
  1971. case 'c':
  1972. return ( '00' + time.microsec ).slice( -3 );
  1973. case 'z':
  1974. return $.timepicker.timezoneOffsetString(
  1975. time.timezone === null
  1976. ? options.timezone
  1977. : time.timezone,
  1978. false
  1979. );
  1980. case 'Z':
  1981. return $.timepicker.timezoneOffsetString(
  1982. time.timezone === null
  1983. ? options.timezone
  1984. : time.timezone,
  1985. true
  1986. );
  1987. case 'T':
  1988. return ampmName.charAt( 0 ).toUpperCase();
  1989. case 'TT':
  1990. return ampmName.toUpperCase();
  1991. case 't':
  1992. return ampmName.charAt( 0 ).toLowerCase();
  1993. case 'tt':
  1994. return ampmName.toLowerCase();
  1995. default:
  1996. return match.replace( /'/g, '' );
  1997. }
  1998. }
  1999. );
  2000. return tmptime;
  2001. };
  2002. /*
  2003. * the bad hack :/ override datepicker so it doesn't close on select
  2004. // inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
  2005. */
  2006. $.datepicker._base_selectDate = $.datepicker._selectDate;
  2007. $.datepicker._selectDate = function ( id, dateStr ) {
  2008. var inst = this._getInst( $( id )[ 0 ] ),
  2009. tp_inst = this._get( inst, 'timepicker' ),
  2010. was_inline;
  2011. if ( tp_inst && inst.settings.showTimepicker ) {
  2012. tp_inst._limitMinMaxDateTime( inst, true );
  2013. was_inline = inst.inline;
  2014. inst.inline = inst.stay_open = true;
  2015. //This way the onSelect handler called from calendarpicker get the full dateTime
  2016. this._base_selectDate( id, dateStr );
  2017. inst.inline = was_inline;
  2018. inst.stay_open = false;
  2019. this._notifyChange( inst );
  2020. this._updateDatepicker( inst );
  2021. } else {
  2022. this._base_selectDate( id, dateStr );
  2023. }
  2024. };
  2025. /*
  2026. * second bad hack :/ override datepicker so it triggers an event when changing the input field
  2027. * and does not redraw the datepicker on every selectDate event
  2028. */
  2029. $.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
  2030. $.datepicker._updateDatepicker = function ( inst ) {
  2031. // don't popup the datepicker if there is another instance already opened
  2032. var input = inst.input[ 0 ];
  2033. if (
  2034. $.datepicker._curInst &&
  2035. $.datepicker._curInst !== inst &&
  2036. $.datepicker._datepickerShowing &&
  2037. $.datepicker._lastInput !== input
  2038. ) {
  2039. return;
  2040. }
  2041. if ( typeof inst.stay_open !== 'boolean' || inst.stay_open === false ) {
  2042. this._base_updateDatepicker( inst );
  2043. // Reload the time control when changing something in the input text field.
  2044. var tp_inst = this._get( inst, 'timepicker' );
  2045. if ( tp_inst ) {
  2046. tp_inst._addTimePicker( inst );
  2047. }
  2048. }
  2049. };
  2050. /*
  2051. * third bad hack :/ override datepicker so it allows spaces and colon in the input field
  2052. */
  2053. $.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
  2054. $.datepicker._doKeyPress = function ( event ) {
  2055. var inst = $.datepicker._getInst( event.target ),
  2056. tp_inst = $.datepicker._get( inst, 'timepicker' );
  2057. if ( tp_inst ) {
  2058. if ( $.datepicker._get( inst, 'constrainInput' ) ) {
  2059. var ampm = tp_inst.support.ampm,
  2060. tz =
  2061. tp_inst._defaults.showTimezone !== null
  2062. ? tp_inst._defaults.showTimezone
  2063. : tp_inst.support.timezone,
  2064. dateChars = $.datepicker._possibleChars(
  2065. $.datepicker._get( inst, 'dateFormat' )
  2066. ),
  2067. datetimeChars =
  2068. tp_inst._defaults.timeFormat
  2069. .toString()
  2070. .replace( /[hms]/g, '' )
  2071. .replace( /TT/g, ampm ? 'APM' : '' )
  2072. .replace( /Tt/g, ampm ? 'AaPpMm' : '' )
  2073. .replace( /tT/g, ampm ? 'AaPpMm' : '' )
  2074. .replace( /T/g, ampm ? 'AP' : '' )
  2075. .replace( /tt/g, ampm ? 'apm' : '' )
  2076. .replace( /t/g, ampm ? 'ap' : '' ) +
  2077. ' ' +
  2078. tp_inst._defaults.separator +
  2079. tp_inst._defaults.timeSuffix +
  2080. ( tz
  2081. ? tp_inst._defaults.timezoneList.join( '' )
  2082. : '' ) +
  2083. tp_inst._defaults.amNames.join( '' ) +
  2084. tp_inst._defaults.pmNames.join( '' ) +
  2085. dateChars,
  2086. chr = String.fromCharCode(
  2087. event.charCode === undefined
  2088. ? event.keyCode
  2089. : event.charCode
  2090. );
  2091. return (
  2092. event.ctrlKey ||
  2093. chr < ' ' ||
  2094. ! dateChars ||
  2095. datetimeChars.indexOf( chr ) > -1
  2096. );
  2097. }
  2098. }
  2099. return $.datepicker._base_doKeyPress( event );
  2100. };
  2101. /*
  2102. * Fourth bad hack :/ override _updateAlternate function used in inline mode to init altField
  2103. * Update any alternate field to synchronise with the main field.
  2104. */
  2105. $.datepicker._base_updateAlternate = $.datepicker._updateAlternate;
  2106. $.datepicker._updateAlternate = function ( inst ) {
  2107. var tp_inst = this._get( inst, 'timepicker' );
  2108. if ( tp_inst ) {
  2109. var altField = tp_inst._defaults.altField;
  2110. if ( altField ) {
  2111. // update alternate field too
  2112. var altFormat =
  2113. tp_inst._defaults.altFormat ||
  2114. tp_inst._defaults.dateFormat,
  2115. date = this._getDate( inst ),
  2116. formatCfg = $.datepicker._getFormatConfig( inst ),
  2117. altFormattedDateTime = '',
  2118. altSeparator = tp_inst._defaults.altSeparator
  2119. ? tp_inst._defaults.altSeparator
  2120. : tp_inst._defaults.separator,
  2121. altTimeSuffix = tp_inst._defaults.altTimeSuffix
  2122. ? tp_inst._defaults.altTimeSuffix
  2123. : tp_inst._defaults.timeSuffix,
  2124. altTimeFormat =
  2125. tp_inst._defaults.altTimeFormat !== null
  2126. ? tp_inst._defaults.altTimeFormat
  2127. : tp_inst._defaults.timeFormat;
  2128. altFormattedDateTime +=
  2129. $.datepicker.formatTime(
  2130. altTimeFormat,
  2131. tp_inst,
  2132. tp_inst._defaults
  2133. ) + altTimeSuffix;
  2134. if (
  2135. ! tp_inst._defaults.timeOnly &&
  2136. ! tp_inst._defaults.altFieldTimeOnly &&
  2137. date !== null
  2138. ) {
  2139. if ( tp_inst._defaults.altFormat ) {
  2140. altFormattedDateTime =
  2141. $.datepicker.formatDate(
  2142. tp_inst._defaults.altFormat,
  2143. date,
  2144. formatCfg
  2145. ) +
  2146. altSeparator +
  2147. altFormattedDateTime;
  2148. } else {
  2149. altFormattedDateTime =
  2150. tp_inst.formattedDate +
  2151. altSeparator +
  2152. altFormattedDateTime;
  2153. }
  2154. }
  2155. $( altField ).val(
  2156. inst.input.val() ? altFormattedDateTime : ''
  2157. );
  2158. }
  2159. } else {
  2160. $.datepicker._base_updateAlternate( inst );
  2161. }
  2162. };
  2163. /*
  2164. * Override key up event to sync manual input changes.
  2165. */
  2166. $.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
  2167. $.datepicker._doKeyUp = function ( event ) {
  2168. var inst = $.datepicker._getInst( event.target ),
  2169. tp_inst = $.datepicker._get( inst, 'timepicker' );
  2170. if ( tp_inst ) {
  2171. if (
  2172. tp_inst._defaults.timeOnly &&
  2173. inst.input.val() !== inst.lastVal
  2174. ) {
  2175. try {
  2176. $.datepicker._updateDatepicker( inst );
  2177. } catch ( err ) {
  2178. $.timepicker.log( err );
  2179. }
  2180. }
  2181. }
  2182. return $.datepicker._base_doKeyUp( event );
  2183. };
  2184. /*
  2185. * override "Today" button to also grab the time and set it to input field.
  2186. */
  2187. $.datepicker._base_gotoToday = $.datepicker._gotoToday;
  2188. $.datepicker._gotoToday = function ( id ) {
  2189. var inst = this._getInst( $( id )[ 0 ] );
  2190. this._base_gotoToday( id );
  2191. var tp_inst = this._get( inst, 'timepicker' );
  2192. if ( ! tp_inst ) {
  2193. return;
  2194. }
  2195. var tzoffset = $.timepicker.timezoneOffsetNumber( tp_inst.timezone );
  2196. var now = new Date();
  2197. now.setMinutes(
  2198. now.getMinutes() +
  2199. now.getTimezoneOffset() +
  2200. parseInt( tzoffset, 10 )
  2201. );
  2202. this._setTime( inst, now );
  2203. this._setDate( inst, now );
  2204. tp_inst._onSelectHandler();
  2205. };
  2206. /*
  2207. * Disable & enable the Time in the datetimepicker
  2208. */
  2209. $.datepicker._disableTimepickerDatepicker = function ( target ) {
  2210. var inst = this._getInst( target );
  2211. if ( ! inst ) {
  2212. return;
  2213. }
  2214. var tp_inst = this._get( inst, 'timepicker' );
  2215. $( target ).datepicker( 'getDate' ); // Init selected[Year|Month|Day]
  2216. if ( tp_inst ) {
  2217. inst.settings.showTimepicker = false;
  2218. tp_inst._defaults.showTimepicker = false;
  2219. tp_inst._updateDateTime( inst );
  2220. }
  2221. };
  2222. $.datepicker._enableTimepickerDatepicker = function ( target ) {
  2223. var inst = this._getInst( target );
  2224. if ( ! inst ) {
  2225. return;
  2226. }
  2227. var tp_inst = this._get( inst, 'timepicker' );
  2228. $( target ).datepicker( 'getDate' ); // Init selected[Year|Month|Day]
  2229. if ( tp_inst ) {
  2230. inst.settings.showTimepicker = true;
  2231. tp_inst._defaults.showTimepicker = true;
  2232. tp_inst._addTimePicker( inst ); // Could be disabled on page load
  2233. tp_inst._updateDateTime( inst );
  2234. }
  2235. };
  2236. /*
  2237. * Create our own set time function
  2238. */
  2239. $.datepicker._setTime = function ( inst, date ) {
  2240. var tp_inst = this._get( inst, 'timepicker' );
  2241. if ( tp_inst ) {
  2242. var defaults = tp_inst._defaults;
  2243. // calling _setTime with no date sets time to defaults
  2244. tp_inst.hour = date ? date.getHours() : defaults.hour;
  2245. tp_inst.minute = date ? date.getMinutes() : defaults.minute;
  2246. tp_inst.second = date ? date.getSeconds() : defaults.second;
  2247. tp_inst.millisec = date
  2248. ? date.getMilliseconds()
  2249. : defaults.millisec;
  2250. tp_inst.microsec = date
  2251. ? date.getMicroseconds()
  2252. : defaults.microsec;
  2253. //check if within min/max times..
  2254. tp_inst._limitMinMaxDateTime( inst, true );
  2255. tp_inst._onTimeChange();
  2256. tp_inst._updateDateTime( inst );
  2257. }
  2258. };
  2259. /*
  2260. * Create new public method to set only time, callable as $().datepicker('setTime', date)
  2261. */
  2262. $.datepicker._setTimeDatepicker = function ( target, date, withDate ) {
  2263. var inst = this._getInst( target );
  2264. if ( ! inst ) {
  2265. return;
  2266. }
  2267. var tp_inst = this._get( inst, 'timepicker' );
  2268. if ( tp_inst ) {
  2269. this._setDateFromField( inst );
  2270. var tp_date;
  2271. if ( date ) {
  2272. if ( typeof date === 'string' ) {
  2273. tp_inst._parseTime( date, withDate );
  2274. tp_date = new Date();
  2275. tp_date.setHours(
  2276. tp_inst.hour,
  2277. tp_inst.minute,
  2278. tp_inst.second,
  2279. tp_inst.millisec
  2280. );
  2281. tp_date.setMicroseconds( tp_inst.microsec );
  2282. } else {
  2283. tp_date = new Date( date.getTime() );
  2284. tp_date.setMicroseconds( date.getMicroseconds() );
  2285. }
  2286. if ( tp_date.toString() === 'Invalid Date' ) {
  2287. tp_date = undefined;
  2288. }
  2289. this._setTime( inst, tp_date );
  2290. }
  2291. }
  2292. };
  2293. /*
  2294. * override setDate() to allow setting time too within Date object
  2295. */
  2296. $.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
  2297. $.datepicker._setDateDatepicker = function ( target, _date ) {
  2298. var inst = this._getInst( target );
  2299. var date = _date;
  2300. if ( ! inst ) {
  2301. return;
  2302. }
  2303. if ( typeof _date === 'string' ) {
  2304. date = new Date( _date );
  2305. if ( ! date.getTime() ) {
  2306. this._base_setDateDatepicker.apply( this, arguments );
  2307. date = $( target ).datepicker( 'getDate' );
  2308. }
  2309. }
  2310. var tp_inst = this._get( inst, 'timepicker' );
  2311. var tp_date;
  2312. if ( date instanceof Date ) {
  2313. tp_date = new Date( date.getTime() );
  2314. tp_date.setMicroseconds( date.getMicroseconds() );
  2315. } else {
  2316. tp_date = date;
  2317. }
  2318. // This is important if you are using the timezone option, javascript's Date
  2319. // object will only return the timezone offset for the current locale, so we
  2320. // adjust it accordingly. If not using timezone option this won't matter..
  2321. // If a timezone is different in tp, keep the timezone as is
  2322. if ( tp_inst && tp_date ) {
  2323. // look out for DST if tz wasn't specified
  2324. if (
  2325. ! tp_inst.support.timezone &&
  2326. tp_inst._defaults.timezone === null
  2327. ) {
  2328. tp_inst.timezone = tp_date.getTimezoneOffset() * -1;
  2329. }
  2330. date = $.timepicker.timezoneAdjust(
  2331. date,
  2332. $.timepicker.timezoneOffsetString( -date.getTimezoneOffset() ),
  2333. tp_inst.timezone
  2334. );
  2335. tp_date = $.timepicker.timezoneAdjust(
  2336. tp_date,
  2337. $.timepicker.timezoneOffsetString(
  2338. -tp_date.getTimezoneOffset()
  2339. ),
  2340. tp_inst.timezone
  2341. );
  2342. }
  2343. this._updateDatepicker( inst );
  2344. this._base_setDateDatepicker.apply( this, arguments );
  2345. this._setTimeDatepicker( target, tp_date, true );
  2346. };
  2347. /*
  2348. * override getDate() to allow getting time too within Date object
  2349. */
  2350. $.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
  2351. $.datepicker._getDateDatepicker = function ( target, noDefault ) {
  2352. var inst = this._getInst( target );
  2353. if ( ! inst ) {
  2354. return;
  2355. }
  2356. var tp_inst = this._get( inst, 'timepicker' );
  2357. if ( tp_inst ) {
  2358. // if it hasn't yet been defined, grab from field
  2359. if ( inst.lastVal === undefined ) {
  2360. this._setDateFromField( inst, noDefault );
  2361. }
  2362. var date = this._getDate( inst );
  2363. var currDT = null;
  2364. if ( tp_inst.$altInput && tp_inst._defaults.altFieldTimeOnly ) {
  2365. currDT = tp_inst.$input.val() + ' ' + tp_inst.$altInput.val();
  2366. } else if (
  2367. tp_inst.$input.get( 0 ).tagName !== 'INPUT' &&
  2368. tp_inst.$altInput
  2369. ) {
  2370. /**
  2371. * in case the datetimepicker has been applied to a non-input tag for inline UI,
  2372. * and the user has not configured the plugin to display only time in altInput,
  2373. * pick current date time from the altInput (and hope for the best, for now, until "ER1" is applied)
  2374. *
  2375. * @todo ER1. Since altInput can have a totally difference format, convert it to standard format by reading input format from "altFormat" and "altTimeFormat" option values
  2376. */
  2377. currDT = tp_inst.$altInput.val();
  2378. } else {
  2379. currDT = tp_inst.$input.val();
  2380. }
  2381. if (
  2382. date &&
  2383. tp_inst._parseTime( currDT, ! inst.settings.timeOnly )
  2384. ) {
  2385. date.setHours(
  2386. tp_inst.hour,
  2387. tp_inst.minute,
  2388. tp_inst.second,
  2389. tp_inst.millisec
  2390. );
  2391. date.setMicroseconds( tp_inst.microsec );
  2392. // This is important if you are using the timezone option, javascript's Date
  2393. // object will only return the timezone offset for the current locale, so we
  2394. // adjust it accordingly. If not using timezone option this won't matter..
  2395. if ( tp_inst.timezone != null ) {
  2396. // look out for DST if tz wasn't specified
  2397. if (
  2398. ! tp_inst.support.timezone &&
  2399. tp_inst._defaults.timezone === null
  2400. ) {
  2401. tp_inst.timezone = date.getTimezoneOffset() * -1;
  2402. }
  2403. date = $.timepicker.timezoneAdjust(
  2404. date,
  2405. tp_inst.timezone,
  2406. $.timepicker.timezoneOffsetString(
  2407. -date.getTimezoneOffset()
  2408. )
  2409. );
  2410. }
  2411. }
  2412. return date;
  2413. }
  2414. return this._base_getDateDatepicker( target, noDefault );
  2415. };
  2416. /*
  2417. * override parseDate() because UI 1.8.14 throws an error about "Extra characters"
  2418. * An option in datapicker to ignore extra format characters would be nicer.
  2419. */
  2420. $.datepicker._base_parseDate = $.datepicker.parseDate;
  2421. $.datepicker.parseDate = function ( format, value, settings ) {
  2422. var date;
  2423. try {
  2424. date = this._base_parseDate( format, value, settings );
  2425. } catch ( err ) {
  2426. // Hack! The error message ends with a colon, a space, and
  2427. // the "extra" characters. We rely on that instead of
  2428. // attempting to perfectly reproduce the parsing algorithm.
  2429. if ( err.indexOf( ':' ) >= 0 ) {
  2430. date = this._base_parseDate(
  2431. format,
  2432. value.substring(
  2433. 0,
  2434. value.length - ( err.length - err.indexOf( ':' ) - 2 )
  2435. ),
  2436. settings
  2437. );
  2438. $.timepicker.log(
  2439. 'Error parsing the date string: ' +
  2440. err +
  2441. '\ndate string = ' +
  2442. value +
  2443. '\ndate format = ' +
  2444. format
  2445. );
  2446. } else {
  2447. throw err;
  2448. }
  2449. }
  2450. return date;
  2451. };
  2452. /*
  2453. * override formatDate to set date with time to the input
  2454. */
  2455. $.datepicker._base_formatDate = $.datepicker._formatDate;
  2456. $.datepicker._formatDate = function ( inst, day, month, year ) {
  2457. var tp_inst = this._get( inst, 'timepicker' );
  2458. if ( tp_inst ) {
  2459. tp_inst._updateDateTime( inst );
  2460. return tp_inst.$input.val();
  2461. }
  2462. return this._base_formatDate( inst );
  2463. };
  2464. /*
  2465. * override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
  2466. */
  2467. $.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
  2468. $.datepicker._optionDatepicker = function ( target, name, value ) {
  2469. var inst = this._getInst( target ),
  2470. name_clone;
  2471. if ( ! inst ) {
  2472. return null;
  2473. }
  2474. var tp_inst = this._get( inst, 'timepicker' );
  2475. if ( tp_inst ) {
  2476. var min = null,
  2477. max = null,
  2478. onselect = null,
  2479. overrides = tp_inst._defaults.evnts,
  2480. fns = {},
  2481. prop,
  2482. ret,
  2483. oldVal,
  2484. $target;
  2485. if ( typeof name === 'string' ) {
  2486. // if min/max was set with the string
  2487. if ( name === 'minDate' || name === 'minDateTime' ) {
  2488. min = value;
  2489. } else if ( name === 'maxDate' || name === 'maxDateTime' ) {
  2490. max = value;
  2491. } else if ( name === 'onSelect' ) {
  2492. onselect = value;
  2493. } else if ( overrides.hasOwnProperty( name ) ) {
  2494. if ( typeof value === 'undefined' ) {
  2495. return overrides[ name ];
  2496. }
  2497. fns[ name ] = value;
  2498. name_clone = {}; //empty results in exiting function after overrides updated
  2499. }
  2500. } else if ( typeof name === 'object' ) {
  2501. //if min/max was set with the JSON
  2502. if ( name.minDate ) {
  2503. min = name.minDate;
  2504. } else if ( name.minDateTime ) {
  2505. min = name.minDateTime;
  2506. } else if ( name.maxDate ) {
  2507. max = name.maxDate;
  2508. } else if ( name.maxDateTime ) {
  2509. max = name.maxDateTime;
  2510. }
  2511. for ( prop in overrides ) {
  2512. if ( overrides.hasOwnProperty( prop ) && name[ prop ] ) {
  2513. fns[ prop ] = name[ prop ];
  2514. }
  2515. }
  2516. }
  2517. for ( prop in fns ) {
  2518. if ( fns.hasOwnProperty( prop ) ) {
  2519. overrides[ prop ] = fns[ prop ];
  2520. if ( ! name_clone ) {
  2521. name_clone = $.extend( {}, name );
  2522. }
  2523. delete name_clone[ prop ];
  2524. }
  2525. }
  2526. if ( name_clone && isEmptyObject( name_clone ) ) {
  2527. return;
  2528. }
  2529. if ( min ) {
  2530. //if min was set
  2531. if ( min === 0 ) {
  2532. min = new Date();
  2533. } else {
  2534. min = new Date( min );
  2535. }
  2536. tp_inst._defaults.minDate = min;
  2537. tp_inst._defaults.minDateTime = min;
  2538. } else if ( max ) {
  2539. //if max was set
  2540. if ( max === 0 ) {
  2541. max = new Date();
  2542. } else {
  2543. max = new Date( max );
  2544. }
  2545. tp_inst._defaults.maxDate = max;
  2546. tp_inst._defaults.maxDateTime = max;
  2547. } else if ( onselect ) {
  2548. tp_inst._defaults.onSelect = onselect;
  2549. }
  2550. // Datepicker will override our date when we call _base_optionDatepicker when
  2551. // calling minDate/maxDate, so we will first grab the value, call
  2552. // _base_optionDatepicker, then set our value back.
  2553. if ( min || max ) {
  2554. $target = $( target );
  2555. oldVal = $target.datetimepicker( 'getDate' );
  2556. ret = this._base_optionDatepicker.call(
  2557. $.datepicker,
  2558. target,
  2559. name_clone || name,
  2560. value
  2561. );
  2562. $target.datetimepicker( 'setDate', oldVal );
  2563. return ret;
  2564. }
  2565. }
  2566. if ( value === undefined ) {
  2567. return this._base_optionDatepicker.call(
  2568. $.datepicker,
  2569. target,
  2570. name
  2571. );
  2572. }
  2573. return this._base_optionDatepicker.call(
  2574. $.datepicker,
  2575. target,
  2576. name_clone || name,
  2577. value
  2578. );
  2579. };
  2580. /*
  2581. * jQuery isEmptyObject does not check hasOwnProperty - if someone has added to the object prototype,
  2582. * it will return false for all objects
  2583. */
  2584. var isEmptyObject = function ( obj ) {
  2585. var prop;
  2586. for ( prop in obj ) {
  2587. if ( obj.hasOwnProperty( prop ) ) {
  2588. return false;
  2589. }
  2590. }
  2591. return true;
  2592. };
  2593. /*
  2594. * jQuery extend now ignores nulls!
  2595. */
  2596. var extendRemove = function ( target, props ) {
  2597. $.extend( target, props );
  2598. for ( var name in props ) {
  2599. if ( props[ name ] === null || props[ name ] === undefined ) {
  2600. target[ name ] = props[ name ];
  2601. }
  2602. }
  2603. return target;
  2604. };
  2605. /*
  2606. * Determine by the time format which units are supported
  2607. * Returns an object of booleans for each unit
  2608. */
  2609. var detectSupport = function ( timeFormat ) {
  2610. var tf = timeFormat.replace( /'.*?'/g, '' ).toLowerCase(), // removes literals
  2611. isIn = function ( f, t ) {
  2612. // does the format contain the token?
  2613. return f.indexOf( t ) !== -1 ? true : false;
  2614. };
  2615. return {
  2616. hour: isIn( tf, 'h' ),
  2617. minute: isIn( tf, 'm' ),
  2618. second: isIn( tf, 's' ),
  2619. millisec: isIn( tf, 'l' ),
  2620. microsec: isIn( tf, 'c' ),
  2621. timezone: isIn( tf, 'z' ),
  2622. ampm: isIn( tf, 't' ) && isIn( timeFormat, 'h' ),
  2623. iso8601: isIn( timeFormat, 'Z' ),
  2624. };
  2625. };
  2626. /*
  2627. * Converts 24 hour format into 12 hour
  2628. * Returns 12 hour without leading 0
  2629. */
  2630. var convert24to12 = function ( hour ) {
  2631. hour %= 12;
  2632. if ( hour === 0 ) {
  2633. hour = 12;
  2634. }
  2635. return String( hour );
  2636. };
  2637. var computeEffectiveSetting = function ( settings, property ) {
  2638. return settings && settings[ property ]
  2639. ? settings[ property ]
  2640. : $.timepicker._defaults[ property ];
  2641. };
  2642. /*
  2643. * Splits datetime string into date and time substrings.
  2644. * Throws exception when date can't be parsed
  2645. * Returns {dateString: dateString, timeString: timeString}
  2646. */
  2647. var splitDateTime = function ( dateTimeString, timeSettings ) {
  2648. // The idea is to get the number separator occurrences in datetime and the time format requested (since time has
  2649. // fewer unknowns, mostly numbers and am/pm). We will use the time pattern to split.
  2650. var separator = computeEffectiveSetting( timeSettings, 'separator' ),
  2651. format = computeEffectiveSetting( timeSettings, 'timeFormat' ),
  2652. timeParts = format.split( separator ), // how many occurrences of separator may be in our format?
  2653. timePartsLen = timeParts.length,
  2654. allParts = dateTimeString.split( separator ),
  2655. allPartsLen = allParts.length;
  2656. if ( allPartsLen > 1 ) {
  2657. return {
  2658. dateString: allParts
  2659. .splice( 0, allPartsLen - timePartsLen )
  2660. .join( separator ),
  2661. timeString: allParts
  2662. .splice( 0, timePartsLen )
  2663. .join( separator ),
  2664. };
  2665. }
  2666. return {
  2667. dateString: dateTimeString,
  2668. timeString: '',
  2669. };
  2670. };
  2671. /*
  2672. * Internal function to parse datetime interval
  2673. * Returns: {date: Date, timeObj: Object}, where
  2674. * date - parsed date without time (type Date)
  2675. * timeObj = {hour: , minute: , second: , millisec: , microsec: } - parsed time. Optional
  2676. */
  2677. var parseDateTimeInternal = function (
  2678. dateFormat,
  2679. timeFormat,
  2680. dateTimeString,
  2681. dateSettings,
  2682. timeSettings
  2683. ) {
  2684. var date, parts, parsedTime;
  2685. parts = splitDateTime( dateTimeString, timeSettings );
  2686. date = $.datepicker._base_parseDate(
  2687. dateFormat,
  2688. parts.dateString,
  2689. dateSettings
  2690. );
  2691. if ( parts.timeString === '' ) {
  2692. return {
  2693. date: date,
  2694. };
  2695. }
  2696. parsedTime = $.datepicker.parseTime(
  2697. timeFormat,
  2698. parts.timeString,
  2699. timeSettings
  2700. );
  2701. if ( ! parsedTime ) {
  2702. throw 'Wrong time format';
  2703. }
  2704. return {
  2705. date: date,
  2706. timeObj: parsedTime,
  2707. };
  2708. };
  2709. /*
  2710. * Internal function to set timezone_select to the local timezone
  2711. */
  2712. var selectLocalTimezone = function ( tp_inst, date ) {
  2713. if ( tp_inst && tp_inst.timezone_select ) {
  2714. var now = date || new Date();
  2715. tp_inst.timezone_select.val( -now.getTimezoneOffset() );
  2716. }
  2717. };
  2718. /*
  2719. * Create a Singleton Instance
  2720. */
  2721. $.timepicker = new Timepicker();
  2722. /**
  2723. * Get the timezone offset as string from a date object (eg '+0530' for UTC+5.5)
  2724. * @param {number} tzMinutes if not a number, less than -720 (-1200), or greater than 840 (+1400) this value is returned
  2725. * @param {boolean} iso8601 if true formats in accordance to iso8601 "+12:45"
  2726. * @return {string}
  2727. */
  2728. $.timepicker.timezoneOffsetString = function ( tzMinutes, iso8601 ) {
  2729. if ( isNaN( tzMinutes ) || tzMinutes > 840 || tzMinutes < -720 ) {
  2730. return tzMinutes;
  2731. }
  2732. var off = tzMinutes,
  2733. minutes = off % 60,
  2734. hours = ( off - minutes ) / 60,
  2735. iso = iso8601 ? ':' : '',
  2736. tz =
  2737. ( off >= 0 ? '+' : '-' ) +
  2738. ( '0' + Math.abs( hours ) ).slice( -2 ) +
  2739. iso +
  2740. ( '0' + Math.abs( minutes ) ).slice( -2 );
  2741. if ( tz === '+00:00' ) {
  2742. return 'Z';
  2743. }
  2744. return tz;
  2745. };
  2746. /**
  2747. * Get the number in minutes that represents a timezone string
  2748. * @param {string} tzString formatted like "+0500", "-1245", "Z"
  2749. * @return {number} the offset minutes or the original string if it doesn't match expectations
  2750. */
  2751. $.timepicker.timezoneOffsetNumber = function ( tzString ) {
  2752. var normalized = tzString.toString().replace( ':', '' ); // excuse any iso8601, end up with "+1245"
  2753. if ( normalized.toUpperCase() === 'Z' ) {
  2754. // if iso8601 with Z, its 0 minute offset
  2755. return 0;
  2756. }
  2757. if ( ! /^(\-|\+)\d{4}$/.test( normalized ) ) {
  2758. // possibly a user defined tz, so just give it back
  2759. return parseInt( tzString, 10 );
  2760. }
  2761. return (
  2762. ( normalized.substr( 0, 1 ) === '-' ? -1 : 1 ) * // plus or minus
  2763. ( parseInt( normalized.substr( 1, 2 ), 10 ) * 60 + // hours (converted to minutes)
  2764. parseInt( normalized.substr( 3, 2 ), 10 ) )
  2765. ); // minutes
  2766. };
  2767. /**
  2768. * No way to set timezone in js Date, so we must adjust the minutes to compensate. (think setDate, getDate)
  2769. * @param {Date} date
  2770. * @param {string} fromTimezone formatted like "+0500", "-1245"
  2771. * @param {string} toTimezone formatted like "+0500", "-1245"
  2772. * @return {Date}
  2773. */
  2774. $.timepicker.timezoneAdjust = function ( date, fromTimezone, toTimezone ) {
  2775. var fromTz = $.timepicker.timezoneOffsetNumber( fromTimezone );
  2776. var toTz = $.timepicker.timezoneOffsetNumber( toTimezone );
  2777. if ( ! isNaN( toTz ) ) {
  2778. date.setMinutes( date.getMinutes() + -fromTz - -toTz );
  2779. }
  2780. return date;
  2781. };
  2782. /**
  2783. * Calls `timepicker()` on the `startTime` and `endTime` elements, and configures them to
  2784. * enforce date range limits.
  2785. * n.b. The input value must be correctly formatted (reformatting is not supported)
  2786. * @param {Element} startTime
  2787. * @param {Element} endTime
  2788. * @param {Object} options Options for the timepicker() call
  2789. * @return {jQuery}
  2790. */
  2791. $.timepicker.timeRange = function ( startTime, endTime, options ) {
  2792. return $.timepicker.handleRange(
  2793. 'timepicker',
  2794. startTime,
  2795. endTime,
  2796. options
  2797. );
  2798. };
  2799. /**
  2800. * Calls `datetimepicker` on the `startTime` and `endTime` elements, and configures them to
  2801. * enforce date range limits.
  2802. * @param {Element} startTime
  2803. * @param {Element} endTime
  2804. * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
  2805. * a boolean value that can be used to reformat the input values to the `dateFormat`.
  2806. * @param {string} method Can be used to specify the type of picker to be added
  2807. * @return {jQuery}
  2808. */
  2809. $.timepicker.datetimeRange = function ( startTime, endTime, options ) {
  2810. $.timepicker.handleRange(
  2811. 'datetimepicker',
  2812. startTime,
  2813. endTime,
  2814. options
  2815. );
  2816. };
  2817. /**
  2818. * Calls `datepicker` on the `startTime` and `endTime` elements, and configures them to
  2819. * enforce date range limits.
  2820. * @param {Element} startTime
  2821. * @param {Element} endTime
  2822. * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
  2823. * a boolean value that can be used to reformat the input values to the `dateFormat`.
  2824. * @return {jQuery}
  2825. */
  2826. $.timepicker.dateRange = function ( startTime, endTime, options ) {
  2827. $.timepicker.handleRange( 'datepicker', startTime, endTime, options );
  2828. };
  2829. /**
  2830. * Calls `method` on the `startTime` and `endTime` elements, and configures them to
  2831. * enforce date range limits.
  2832. * @param {string} method Can be used to specify the type of picker to be added
  2833. * @param {Element} startTime
  2834. * @param {Element} endTime
  2835. * @param {Object} options Options for the `timepicker()` call. Also supports `reformat`,
  2836. * a boolean value that can be used to reformat the input values to the `dateFormat`.
  2837. * @return {jQuery}
  2838. */
  2839. $.timepicker.handleRange = function (
  2840. method,
  2841. startTime,
  2842. endTime,
  2843. options
  2844. ) {
  2845. options = $.extend(
  2846. {},
  2847. {
  2848. minInterval: 0, // min allowed interval in milliseconds
  2849. maxInterval: 0, // max allowed interval in milliseconds
  2850. start: {}, // options for start picker
  2851. end: {}, // options for end picker
  2852. },
  2853. options
  2854. );
  2855. // for the mean time this fixes an issue with calling getDate with timepicker()
  2856. var timeOnly = false;
  2857. if ( method === 'timepicker' ) {
  2858. timeOnly = true;
  2859. method = 'datetimepicker';
  2860. }
  2861. function checkDates( changed, other ) {
  2862. var startdt = startTime[ method ]( 'getDate' ),
  2863. enddt = endTime[ method ]( 'getDate' ),
  2864. changeddt = changed[ method ]( 'getDate' );
  2865. if ( startdt !== null ) {
  2866. var minDate = new Date( startdt.getTime() ),
  2867. maxDate = new Date( startdt.getTime() );
  2868. minDate.setMilliseconds(
  2869. minDate.getMilliseconds() + options.minInterval
  2870. );
  2871. maxDate.setMilliseconds(
  2872. maxDate.getMilliseconds() + options.maxInterval
  2873. );
  2874. if ( options.minInterval > 0 && minDate > enddt ) {
  2875. // minInterval check
  2876. endTime[ method ]( 'setDate', minDate );
  2877. } else if ( options.maxInterval > 0 && maxDate < enddt ) {
  2878. // max interval check
  2879. endTime[ method ]( 'setDate', maxDate );
  2880. } else if ( startdt > enddt ) {
  2881. other[ method ]( 'setDate', changeddt );
  2882. }
  2883. }
  2884. }
  2885. function selected( changed, other, option ) {
  2886. if ( ! changed.val() ) {
  2887. return;
  2888. }
  2889. var date = changed[ method ].call( changed, 'getDate' );
  2890. if ( date !== null && options.minInterval > 0 ) {
  2891. if ( option === 'minDate' ) {
  2892. date.setMilliseconds(
  2893. date.getMilliseconds() + options.minInterval
  2894. );
  2895. }
  2896. if ( option === 'maxDate' ) {
  2897. date.setMilliseconds(
  2898. date.getMilliseconds() - options.minInterval
  2899. );
  2900. }
  2901. }
  2902. if ( date.getTime ) {
  2903. other[ method ].call( other, 'option', option, date );
  2904. }
  2905. }
  2906. $.fn[ method ].call(
  2907. startTime,
  2908. $.extend(
  2909. {
  2910. timeOnly: timeOnly,
  2911. onClose: function ( dateText, inst ) {
  2912. checkDates( $( this ), endTime );
  2913. },
  2914. onSelect: function ( selectedDateTime ) {
  2915. selected( $( this ), endTime, 'minDate' );
  2916. },
  2917. },
  2918. options,
  2919. options.start
  2920. )
  2921. );
  2922. $.fn[ method ].call(
  2923. endTime,
  2924. $.extend(
  2925. {
  2926. timeOnly: timeOnly,
  2927. onClose: function ( dateText, inst ) {
  2928. checkDates( $( this ), startTime );
  2929. },
  2930. onSelect: function ( selectedDateTime ) {
  2931. selected( $( this ), startTime, 'maxDate' );
  2932. },
  2933. },
  2934. options,
  2935. options.end
  2936. )
  2937. );
  2938. checkDates( startTime, endTime );
  2939. selected( startTime, endTime, 'minDate' );
  2940. selected( endTime, startTime, 'maxDate' );
  2941. return $( [ startTime.get( 0 ), endTime.get( 0 ) ] );
  2942. };
  2943. /**
  2944. * Log error or data to the console during error or debugging
  2945. * @param {Object} err pass any type object to log to the console during error or debugging
  2946. * @return {void}
  2947. */
  2948. $.timepicker.log = function () {
  2949. // Older IE (9, maybe 10) throw error on accessing `window.console.log.apply`, so check first.
  2950. if (
  2951. window.console &&
  2952. window.console.log &&
  2953. window.console.log.apply
  2954. ) {
  2955. window.console.log.apply(
  2956. window.console,
  2957. Array.prototype.slice.call( arguments )
  2958. );
  2959. }
  2960. };
  2961. /*
  2962. * Add util object to allow access to private methods for testability.
  2963. */
  2964. $.timepicker._util = {
  2965. _extendRemove: extendRemove,
  2966. _isEmptyObject: isEmptyObject,
  2967. _convert24to12: convert24to12,
  2968. _detectSupport: detectSupport,
  2969. _selectLocalTimezone: selectLocalTimezone,
  2970. _computeEffectiveSetting: computeEffectiveSetting,
  2971. _splitDateTime: splitDateTime,
  2972. _parseDateTimeInternal: parseDateTimeInternal,
  2973. };
  2974. /*
  2975. * Microsecond support
  2976. */
  2977. if ( ! Date.prototype.getMicroseconds ) {
  2978. Date.prototype.microseconds = 0;
  2979. Date.prototype.getMicroseconds = function () {
  2980. return this.microseconds;
  2981. };
  2982. Date.prototype.setMicroseconds = function ( m ) {
  2983. this.setMilliseconds(
  2984. this.getMilliseconds() + Math.floor( m / 1000 )
  2985. );
  2986. this.microseconds = m % 1000;
  2987. return this;
  2988. };
  2989. }
  2990. /*
  2991. * Keep up with the version
  2992. */
  2993. $.timepicker.version = '1.6.3';
  2994. } );