/ajax/libs/later/1.2.0/later.js

https://gitlab.com/Mirros/cdnjs · JavaScript · 1480 lines · 1464 code · 16 blank · 0 comment · 295 complexity · 5c30f2c601c53e7db912e2d1fd1df1a0 MD5 · raw file

  1. later = function() {
  2. "use strict";
  3. var later = {
  4. version: "1.2.0"
  5. };
  6. if (!Array.prototype.indexOf) {
  7. Array.prototype.indexOf = function(searchElement) {
  8. "use strict";
  9. if (this == null) {
  10. throw new TypeError();
  11. }
  12. var t = Object(this);
  13. var len = t.length >>> 0;
  14. if (len === 0) {
  15. return -1;
  16. }
  17. var n = 0;
  18. if (arguments.length > 1) {
  19. n = Number(arguments[1]);
  20. if (n != n) {
  21. n = 0;
  22. } else if (n != 0 && n != Infinity && n != -Infinity) {
  23. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  24. }
  25. }
  26. if (n >= len) {
  27. return -1;
  28. }
  29. var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
  30. for (;k < len; k++) {
  31. if (k in t && t[k] === searchElement) {
  32. return k;
  33. }
  34. }
  35. return -1;
  36. };
  37. }
  38. if (!String.prototype.trim) {
  39. String.prototype.trim = function() {
  40. return this.replace(/^\s+|\s+$/g, "");
  41. };
  42. }
  43. later.array = {};
  44. later.array.sort = function(arr, zeroIsLast) {
  45. arr.sort(function(a, b) {
  46. return +a - +b;
  47. });
  48. if (zeroIsLast && arr[0] === 0) {
  49. arr.push(arr.shift());
  50. }
  51. };
  52. later.array.next = function(val, values, extent) {
  53. var cur, zeroIsLargest = extent[0] !== 0, nextIdx = 0;
  54. for (var i = values.length - 1; i > -1; --i) {
  55. cur = values[i];
  56. if (cur === val) {
  57. return cur;
  58. }
  59. if (cur > val || cur === 0 && zeroIsLargest && extent[1] > val) {
  60. nextIdx = i;
  61. continue;
  62. }
  63. break;
  64. }
  65. return values[nextIdx];
  66. };
  67. later.array.nextInvalid = function(val, values, extent) {
  68. var min = extent[0], max = extent[1], len = values.length, zeroVal = values[len - 1] === 0 && min !== 0 ? max : 0, next = val, i = values.indexOf(val), start = next;
  69. while (next === (values[i] || zeroVal)) {
  70. next++;
  71. if (next > max) {
  72. next = min;
  73. }
  74. i++;
  75. if (i === len) {
  76. i = 0;
  77. }
  78. if (next === start) {
  79. return undefined;
  80. }
  81. }
  82. return next;
  83. };
  84. later.array.prev = function(val, values, extent) {
  85. var cur, len = values.length, zeroIsLargest = extent[0] !== 0, prevIdx = len - 1;
  86. for (var i = 0; i < len; i++) {
  87. cur = values[i];
  88. if (cur === val) {
  89. return cur;
  90. }
  91. if (cur < val || cur === 0 && zeroIsLargest && extent[1] < val) {
  92. prevIdx = i;
  93. continue;
  94. }
  95. break;
  96. }
  97. return values[prevIdx];
  98. };
  99. later.array.prevInvalid = function(val, values, extent) {
  100. var min = extent[0], max = extent[1], len = values.length, zeroVal = values[len - 1] === 0 && min !== 0 ? max : 0, next = val, i = values.indexOf(val), start = next;
  101. while (next === (values[i] || zeroVal)) {
  102. next--;
  103. if (next < min) {
  104. next = max;
  105. }
  106. i--;
  107. if (i === -1) {
  108. i = len - 1;
  109. }
  110. if (next === start) {
  111. return undefined;
  112. }
  113. }
  114. return next;
  115. };
  116. later.day = later.D = {
  117. name: "day",
  118. range: 86400,
  119. val: function(d) {
  120. return d.D || (d.D = later.date.getDate.call(d));
  121. },
  122. isValid: function(d, val) {
  123. return later.D.val(d) === (val || later.D.extent(d)[1]);
  124. },
  125. extent: function(d) {
  126. if (d.DExtent) return d.DExtent;
  127. var month = later.M.val(d), max = later.DAYS_IN_MONTH[month - 1];
  128. if (month === 2 && later.dy.extent(d)[1] === 366) {
  129. max = max + 1;
  130. }
  131. return d.DExtent = [ 1, max ];
  132. },
  133. start: function(d) {
  134. return d.DStart || (d.DStart = later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d)));
  135. },
  136. end: function(d) {
  137. return d.DEnd || (d.DEnd = later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d)));
  138. },
  139. next: function(d, val) {
  140. val = val > later.D.extent(d)[1] ? 1 : val;
  141. var month = later.date.nextRollover(d, val, later.D, later.M), DMax = later.D.extent(month)[1];
  142. val = val > DMax ? 1 : val || DMax;
  143. return later.date.next(later.Y.val(month), later.M.val(month), val);
  144. },
  145. prev: function(d, val) {
  146. var month = later.date.prevRollover(d, val, later.D, later.M), DMax = later.D.extent(month)[1];
  147. return later.date.prev(later.Y.val(month), later.M.val(month), val > DMax ? DMax : val || DMax);
  148. }
  149. };
  150. later.dayOfWeekCount = later.dc = {
  151. name: "day of week count",
  152. range: 604800,
  153. val: function(d) {
  154. return d.dc || (d.dc = Math.floor((later.D.val(d) - 1) / 7) + 1);
  155. },
  156. isValid: function(d, val) {
  157. return later.dc.val(d) === val || val === 0 && later.D.val(d) > later.D.extent(d)[1] - 7;
  158. },
  159. extent: function(d) {
  160. return d.dcExtent || (d.dcExtent = [ 1, Math.ceil(later.D.extent(d)[1] / 7) ]);
  161. },
  162. start: function(d) {
  163. return d.dcStart || (d.dcStart = later.date.next(later.Y.val(d), later.M.val(d), Math.max(1, (later.dc.val(d) - 1) * 7 + 1 || 1)));
  164. },
  165. end: function(d) {
  166. return d.dcEnd || (d.dcEnd = later.date.prev(later.Y.val(d), later.M.val(d), Math.min(later.dc.val(d) * 7, later.D.extent(d)[1])));
  167. },
  168. next: function(d, val) {
  169. val = val > later.dc.extent(d)[1] ? 1 : val;
  170. var month = later.date.nextRollover(d, val, later.dc, later.M), dcMax = later.dc.extent(month)[1];
  171. val = val > dcMax ? 1 : val;
  172. var next = later.date.next(later.Y.val(month), later.M.val(month), val === 0 ? later.D.extent(month)[1] - 6 : 1 + 7 * (val - 1));
  173. if (next.getTime() <= d.getTime()) {
  174. month = later.M.next(d, later.M.val(d) + 1);
  175. return later.date.next(later.Y.val(month), later.M.val(month), val === 0 ? later.D.extent(month)[1] - 6 : 1 + 7 * (val - 1));
  176. }
  177. return next;
  178. },
  179. prev: function(d, val) {
  180. var month = later.date.prevRollover(d, val, later.dc, later.M), dcMax = later.dc.extent(month)[1];
  181. val = val > dcMax ? dcMax : val || dcMax;
  182. return later.dc.end(later.date.prev(later.Y.val(month), later.M.val(month), 1 + 7 * (val - 1)));
  183. }
  184. };
  185. later.dayOfWeek = later.dw = later.d = {
  186. name: "day of week",
  187. range: 86400,
  188. val: function(d) {
  189. return d.dw || (d.dw = later.date.getDay.call(d) + 1);
  190. },
  191. isValid: function(d, val) {
  192. return later.dw.val(d) === (val || 7);
  193. },
  194. extent: function() {
  195. return [ 1, 7 ];
  196. },
  197. start: function(d) {
  198. return later.D.start(d);
  199. },
  200. end: function(d) {
  201. return later.D.end(d);
  202. },
  203. next: function(d, val) {
  204. val = val > 7 ? 1 : val || 7;
  205. return later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d) + (val - later.dw.val(d)) + (val <= later.dw.val(d) ? 7 : 0));
  206. },
  207. prev: function(d, val) {
  208. val = val > 7 ? 7 : val || 7;
  209. return later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d) + (val - later.dw.val(d)) + (val >= later.dw.val(d) ? -7 : 0));
  210. }
  211. };
  212. later.dayOfYear = later.dy = {
  213. name: "day of year",
  214. range: 86400,
  215. val: function(d) {
  216. return d.dy || (d.dy = Math.ceil(1 + (later.D.start(d).getTime() - later.Y.start(d).getTime()) / later.DAY));
  217. },
  218. isValid: function(d, val) {
  219. return later.dy.val(d) === (val || later.dy.extent(d)[1]);
  220. },
  221. extent: function(d) {
  222. var year = later.Y.val(d);
  223. return d.dyExtent || (d.dyExtent = [ 1, year % 4 ? 365 : 366 ]);
  224. },
  225. start: function(d) {
  226. return later.D.start(d);
  227. },
  228. end: function(d) {
  229. return later.D.end(d);
  230. },
  231. next: function(d, val) {
  232. val = val > later.dy.extent(d)[1] ? 1 : val;
  233. var year = later.date.nextRollover(d, val, later.dy, later.Y), dyMax = later.dy.extent(year)[1];
  234. val = val > dyMax ? 1 : val || dyMax;
  235. return later.date.next(later.Y.val(year), later.M.val(year), val);
  236. },
  237. prev: function(d, val) {
  238. var year = later.date.prevRollover(d, val, later.dy, later.Y), dyMax = later.dy.extent(year)[1];
  239. val = val > dyMax ? dyMax : val || dyMax;
  240. return later.date.prev(later.Y.val(year), later.M.val(year), val);
  241. }
  242. };
  243. later.hour = later.h = {
  244. name: "hour",
  245. range: 3600,
  246. val: function(d) {
  247. return d.h || (d.h = later.date.getHour.call(d));
  248. },
  249. isValid: function(d, val) {
  250. return later.h.val(d) === val;
  251. },
  252. extent: function() {
  253. return [ 0, 23 ];
  254. },
  255. start: function(d) {
  256. return d.hStart || (d.hStart = later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d)));
  257. },
  258. end: function(d) {
  259. return d.hEnd || (d.hEnd = later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d)));
  260. },
  261. next: function(d, val) {
  262. val = val > 23 ? 0 : val;
  263. var next = later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d) + (val <= later.h.val(d) ? 1 : 0), val);
  264. if (!later.date.isUTC && next.getTime() <= d.getTime()) {
  265. next = later.date.next(later.Y.val(next), later.M.val(next), later.D.val(next), val + 1);
  266. }
  267. return next;
  268. },
  269. prev: function(d, val) {
  270. val = val > 23 ? 23 : val;
  271. return later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d) + (val >= later.h.val(d) ? -1 : 0), val);
  272. }
  273. };
  274. later.minute = later.m = {
  275. name: "minute",
  276. range: 60,
  277. val: function(d) {
  278. return d.m || (d.m = later.date.getMin.call(d));
  279. },
  280. isValid: function(d, val) {
  281. return later.m.val(d) === val;
  282. },
  283. extent: function(d) {
  284. return [ 0, 59 ];
  285. },
  286. start: function(d) {
  287. return d.mStart || (d.mStart = later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d), later.m.val(d)));
  288. },
  289. end: function(d) {
  290. return d.mEnd || (d.mEnd = later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d), later.m.val(d)));
  291. },
  292. next: function(d, val) {
  293. var m = later.m.val(d), s = later.s.val(d), inc = val > 59 ? 60 - m : val <= m ? 60 - m + val : val - m, next = new Date(d.getTime() + inc * later.MIN - s * later.SEC);
  294. if (!later.date.isUTC && next.getTime() <= d.getTime()) {
  295. next = new Date(d.getTime() + (inc + 120) * later.MIN - s * later.SEC);
  296. }
  297. return next;
  298. },
  299. prev: function(d, val) {
  300. val = val > 59 ? 59 : val;
  301. return later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d) + (val >= later.m.val(d) ? -1 : 0), val);
  302. }
  303. };
  304. later.month = later.M = {
  305. name: "month",
  306. range: 2629740,
  307. val: function(d) {
  308. return d.M || (d.M = later.date.getMonth.call(d) + 1);
  309. },
  310. isValid: function(d, val) {
  311. return later.M.val(d) === (val || 12);
  312. },
  313. extent: function() {
  314. return [ 1, 12 ];
  315. },
  316. start: function(d) {
  317. return d.MStart || (d.MStart = later.date.next(later.Y.val(d), later.M.val(d)));
  318. },
  319. end: function(d) {
  320. return d.MEnd || (d.MEnd = later.date.prev(later.Y.val(d), later.M.val(d)));
  321. },
  322. next: function(d, val) {
  323. val = val > 12 ? 1 : val || 12;
  324. return later.date.next(later.Y.val(d) + (val > later.M.val(d) ? 0 : 1), val);
  325. },
  326. prev: function(d, val) {
  327. val = val > 12 ? 12 : val || 12;
  328. return later.date.prev(later.Y.val(d) - (val >= later.M.val(d) ? 1 : 0), val);
  329. }
  330. };
  331. later.second = later.s = {
  332. name: "second",
  333. range: 1,
  334. val: function(d) {
  335. return d.s || (d.s = later.date.getSec.call(d));
  336. },
  337. isValid: function(d, val) {
  338. return later.s.val(d) === val;
  339. },
  340. extent: function() {
  341. return [ 0, 59 ];
  342. },
  343. start: function(d) {
  344. return d;
  345. },
  346. end: function(d) {
  347. return d;
  348. },
  349. next: function(d, val) {
  350. var s = later.s.val(d), inc = val > 59 ? 60 - s : val <= s ? 60 - s + val : val - s, next = new Date(d.getTime() + inc * later.SEC);
  351. if (!later.date.isUTC && next.getTime() <= d.getTime()) {
  352. next = new Date(d.getTime() + (inc + 7200) * later.SEC);
  353. }
  354. return next;
  355. },
  356. prev: function(d, val, cache) {
  357. val = val > 59 ? 59 : val;
  358. return later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d), later.h.val(d), later.m.val(d) + (val >= later.s.val(d) ? -1 : 0), val);
  359. }
  360. };
  361. later.time = later.t = {
  362. name: "time",
  363. range: 1,
  364. val: function(d) {
  365. return d.t || (d.t = later.h.val(d) * 3600 + later.m.val(d) * 60 + later.s.val(d));
  366. },
  367. isValid: function(d, val) {
  368. return later.t.val(d) === val;
  369. },
  370. extent: function() {
  371. return [ 0, 86399 ];
  372. },
  373. start: function(d) {
  374. return d;
  375. },
  376. end: function(d) {
  377. return d;
  378. },
  379. next: function(d, val) {
  380. val = val > 86399 ? 0 : val;
  381. var next = later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d) + (val <= later.t.val(d) ? 1 : 0), 0, 0, val);
  382. if (!later.date.isUTC && next.getTime() < d.getTime()) {
  383. next = later.date.next(later.Y.val(next), later.M.val(next), later.D.val(next), later.h.val(next), later.m.val(next), val + 7200);
  384. }
  385. return next;
  386. },
  387. prev: function(d, val) {
  388. val = val > 86399 ? 86399 : val;
  389. return later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d) + (val >= later.t.val(d) ? -1 : 0), 0, 0, val);
  390. }
  391. };
  392. later.weekOfMonth = later.wm = {
  393. name: "week of month",
  394. range: 604800,
  395. val: function(d) {
  396. return d.wm || (d.wm = (later.D.val(d) + (later.dw.val(later.M.start(d)) - 1) + (7 - later.dw.val(d))) / 7);
  397. },
  398. isValid: function(d, val) {
  399. return later.wm.val(d) === (val || later.wm.extent(d)[1]);
  400. },
  401. extent: function(d) {
  402. return d.wmExtent || (d.wmExtent = [ 1, (later.D.extent(d)[1] + (later.dw.val(later.M.start(d)) - 1) + (7 - later.dw.val(later.M.end(d)))) / 7 ]);
  403. },
  404. start: function(d) {
  405. return d.wmStart || (d.wmStart = later.date.next(later.Y.val(d), later.M.val(d), Math.max(later.D.val(d) - later.dw.val(d) + 1, 1)));
  406. },
  407. end: function(d) {
  408. return d.wmEnd || (d.wmEnd = later.date.prev(later.Y.val(d), later.M.val(d), Math.min(later.D.val(d) + (7 - later.dw.val(d)), later.D.extent(d)[1])));
  409. },
  410. next: function(d, val) {
  411. val = val > later.wm.extent(d)[1] ? 1 : val;
  412. var month = later.date.nextRollover(d, val, later.wm, later.M), wmMax = later.wm.extent(month)[1];
  413. val = val > wmMax ? 1 : val || wmMax;
  414. return later.date.next(later.Y.val(month), later.M.val(month), Math.max(1, (val - 1) * 7 - (later.dw.val(month) - 2)));
  415. },
  416. prev: function(d, val) {
  417. var month = later.date.prevRollover(d, val, later.wm, later.M), wmMax = later.wm.extent(month)[1];
  418. val = val > wmMax ? wmMax : val || wmMax;
  419. return later.wm.end(later.date.next(later.Y.val(month), later.M.val(month), Math.max(1, (val - 1) * 7 - (later.dw.val(month) - 2))));
  420. }
  421. };
  422. later.weekOfYear = later.wy = {
  423. name: "week of year (ISO)",
  424. range: 604800,
  425. val: function(d) {
  426. if (d.wy) return d.wy;
  427. var wThur = later.dw.next(later.wy.start(d), 5), YThur = later.dw.next(later.Y.prev(wThur, later.Y.val(wThur) - 1), 5);
  428. return d.wy = 1 + Math.ceil((wThur.getTime() - YThur.getTime()) / later.WEEK);
  429. },
  430. isValid: function(d, val) {
  431. return later.wy.val(d) === (val || later.wy.extent(d)[1]);
  432. },
  433. extent: function(d) {
  434. if (d.wyExtent) return d.wyExtent;
  435. var year = later.dw.next(later.wy.start(d), 5), dwFirst = later.dw.val(later.Y.start(year)), dwLast = later.dw.val(later.Y.end(year));
  436. return d.wyExtent = [ 1, dwFirst === 5 || dwLast === 5 ? 53 : 52 ];
  437. },
  438. start: function(d) {
  439. return d.wyStart || (d.wyStart = later.date.next(later.Y.val(d), later.M.val(d), later.D.val(d) - (later.dw.val(d) > 1 ? later.dw.val(d) - 2 : 6)));
  440. },
  441. end: function(d) {
  442. return d.wyEnd || (d.wyEnd = later.date.prev(later.Y.val(d), later.M.val(d), later.D.val(d) + (later.dw.val(d) > 1 ? 8 - later.dw.val(d) : 0)));
  443. },
  444. next: function(d, val) {
  445. val = val > later.wy.extent(d)[1] ? 1 : val;
  446. var wyThur = later.dw.next(later.wy.start(d), 5), year = later.date.nextRollover(wyThur, val, later.wy, later.Y);
  447. if (later.wy.val(year) !== 1) {
  448. year = later.dw.next(year, 2);
  449. }
  450. var wyMax = later.wy.extent(year)[1], wyStart = later.wy.start(year);
  451. val = val > wyMax ? 1 : val || wyMax;
  452. return later.date.next(later.Y.val(wyStart), later.M.val(wyStart), later.D.val(wyStart) + 7 * (val - 1));
  453. },
  454. prev: function(d, val) {
  455. var wyThur = later.dw.next(later.wy.start(d), 5), year = later.date.prevRollover(wyThur, val, later.wy, later.Y);
  456. if (later.wy.val(year) !== 1) {
  457. year = later.dw.next(year, 2);
  458. }
  459. var wyMax = later.wy.extent(year)[1], wyEnd = later.wy.end(year);
  460. val = val > wyMax ? wyMax : val || wyMax;
  461. return later.wy.end(later.date.next(later.Y.val(wyEnd), later.M.val(wyEnd), later.D.val(wyEnd) + 7 * (val - 1)));
  462. }
  463. };
  464. later.year = later.Y = {
  465. name: "year",
  466. range: 31556900,
  467. val: function(d) {
  468. return d.Y || (d.Y = later.date.getYear.call(d));
  469. },
  470. isValid: function(d, val) {
  471. return later.Y.val(d) === val;
  472. },
  473. extent: function() {
  474. return [ 1970, 2099 ];
  475. },
  476. start: function(d) {
  477. return d.YStart || (d.YStart = later.date.next(later.Y.val(d)));
  478. },
  479. end: function(d) {
  480. return d.YEnd || (d.YEnd = later.date.prev(later.Y.val(d)));
  481. },
  482. next: function(d, val) {
  483. return val > later.Y.val(d) && val <= later.Y.extent()[1] ? later.date.next(val) : later.NEVER;
  484. },
  485. prev: function(d, val) {
  486. return val < later.Y.val(d) && val >= later.Y.extent()[0] ? later.date.prev(val) : later.NEVER;
  487. }
  488. };
  489. later.fullDate = later.fd = {
  490. name: "full date",
  491. range: 1,
  492. val: function(d) {
  493. return d.fd || (d.fd = d.getTime());
  494. },
  495. isValid: function(d, val) {
  496. return later.fd.val(d) === val;
  497. },
  498. extent: function() {
  499. return [ 0, 3250368e7 ];
  500. },
  501. start: function(d) {
  502. return d;
  503. },
  504. end: function(d) {
  505. return d;
  506. },
  507. next: function(d, val) {
  508. return later.fd.val(d) < val ? new Date(val) : later.NEVER;
  509. },
  510. prev: function(d, val) {
  511. return later.fd.val(d) > val ? new Date(val) : later.NEVER;
  512. }
  513. };
  514. later.modifier = {};
  515. later.modifier.after = later.modifier.a = function(constraint, values) {
  516. var value = values[0];
  517. return {
  518. name: "after " + constraint.name,
  519. range: (constraint.extent(new Date())[1] - value) * constraint.range,
  520. val: constraint.val,
  521. isValid: function(d, val) {
  522. return this.val(d) >= value;
  523. },
  524. extent: constraint.extent,
  525. start: constraint.start,
  526. end: constraint.end,
  527. next: function(startDate, val) {
  528. if (val != value) val = constraint.extent(startDate)[0];
  529. return constraint.next(startDate, val);
  530. },
  531. prev: function(startDate, val) {
  532. val = val === value ? constraint.extent(startDate)[1] : value - 1;
  533. return constraint.prev(startDate, val);
  534. }
  535. };
  536. };
  537. later.modifier.before = later.modifier.b = function(constraint, values) {
  538. var value = values[values.length - 1];
  539. return {
  540. name: "before " + constraint.name,
  541. range: constraint.range * (value - 1),
  542. val: constraint.val,
  543. isValid: function(d, val) {
  544. return this.val(d) < value;
  545. },
  546. extent: constraint.extent,
  547. start: constraint.start,
  548. end: constraint.end,
  549. next: function(startDate, val) {
  550. val = val === value ? constraint.extent(startDate)[0] : value;
  551. return constraint.next(startDate, val);
  552. },
  553. prev: function(startDate, val) {
  554. val = val === value ? value - 1 : constraint.extent(startDate)[1];
  555. return constraint.prev(startDate, val);
  556. }
  557. };
  558. };
  559. later.compile = function(schedDef) {
  560. var constraints = [], constraintsLen = 0, tickConstraint;
  561. for (var key in schedDef) {
  562. var nameParts = key.split("_"), name = nameParts[0], mod = nameParts[1], vals = schedDef[key], constraint = mod ? later.modifier[mod](later[name], vals) : later[name];
  563. constraints.push({
  564. constraint: constraint,
  565. vals: vals
  566. });
  567. constraintsLen++;
  568. }
  569. constraints.sort(function(a, b) {
  570. var ra = a.constraint.range, rb = b.constraint.range;
  571. return rb < ra ? -1 : rb > ra ? 1 : 0;
  572. });
  573. tickConstraint = constraints[constraintsLen - 1].constraint;
  574. function compareFn(dir) {
  575. return dir === "next" ? function(a, b) {
  576. return a.getTime() > b.getTime();
  577. } : function(a, b) {
  578. return b.getTime() > a.getTime();
  579. };
  580. }
  581. return {
  582. start: function(dir, startDate) {
  583. var next = startDate, nextVal = later.array[dir], maxAttempts = 1e3, done;
  584. while (maxAttempts-- && !done && next) {
  585. done = true;
  586. for (var i = 0; i < constraintsLen; i++) {
  587. var constraint = constraints[i].constraint, curVal = constraint.val(next), extent = constraint.extent(next), newVal = nextVal(curVal, constraints[i].vals, extent);
  588. if (!constraint.isValid(next, newVal)) {
  589. next = constraint[dir](next, newVal);
  590. done = false;
  591. break;
  592. }
  593. }
  594. }
  595. if (next !== later.NEVER) {
  596. next = dir === "next" ? tickConstraint.start(next) : tickConstraint.end(next);
  597. }
  598. return next;
  599. },
  600. end: function(dir, startDate) {
  601. var result, nextVal = later.array[dir + "Invalid"], compare = compareFn(dir);
  602. for (var i = constraintsLen - 1; i >= 0; i--) {
  603. var constraint = constraints[i].constraint, curVal = constraint.val(startDate), extent = constraint.extent(startDate), newVal = nextVal(curVal, constraints[i].vals, extent), next;
  604. if (newVal !== undefined) {
  605. next = constraint[dir](startDate, newVal);
  606. if (next && (!result || compare(result, next))) {
  607. result = next;
  608. }
  609. }
  610. }
  611. return result;
  612. },
  613. tick: function(dir, date) {
  614. return new Date(dir === "next" ? tickConstraint.end(date).getTime() + later.SEC : tickConstraint.start(date).getTime() - later.SEC);
  615. },
  616. tickStart: function(date) {
  617. return tickConstraint.start(date);
  618. }
  619. };
  620. };
  621. later.schedule = function(sched) {
  622. if (!sched) throw new Error("Missing schedule definition.");
  623. if (!sched.schedules) throw new Error("Definition must include at least one schedule.");
  624. var schedules = [], schedulesLen = sched.schedules.length, exceptions = [], exceptionsLen = sched.exceptions ? sched.exceptions.length : 0;
  625. for (var i = 0; i < schedulesLen; i++) {
  626. schedules.push(later.compile(sched.schedules[i]));
  627. }
  628. for (var j = 0; j < exceptionsLen; j++) {
  629. exceptions.push(later.compile(sched.exceptions[j]));
  630. }
  631. function getInstances(dir, count, startDate, endDate, isRange) {
  632. var compare = compareFn(dir), loopCount = count, maxAttempts = 1e3, schedStarts = [], exceptStarts = [], next, end, results = [], isForward = dir === "next", lastResult, rStart = isForward ? 0 : 1, rEnd = isForward ? 1 : 0;
  633. startDate = startDate ? new Date(startDate) : new Date();
  634. if (!startDate || !startDate.getTime()) throw new Error("Invalid start date.");
  635. setNextStarts(dir, schedules, schedStarts, startDate);
  636. setRangeStarts(dir, exceptions, exceptStarts, startDate);
  637. while (maxAttempts-- && loopCount && (next = findNext(schedStarts, compare))) {
  638. if (endDate && compare(next, endDate)) {
  639. break;
  640. }
  641. if (exceptionsLen) {
  642. updateRangeStarts(dir, exceptions, exceptStarts, next);
  643. if (end = calcRangeOverlap(dir, exceptStarts, next)) {
  644. updateNextStarts(dir, schedules, schedStarts, end);
  645. continue;
  646. }
  647. }
  648. if (isRange) {
  649. var maxEndDate = calcMaxEndDate(exceptStarts, compare);
  650. end = calcEnd(dir, schedules, schedStarts, next, maxEndDate);
  651. var r = isForward ? [ new Date(Math.max(startDate, next)), end ? new Date(endDate ? Math.min(end, endDate) : end) : undefined ] : [ end ? new Date(endDate ? Math.max(endDate, end.getTime() + later.SEC) : end.getTime() + later.SEC) : undefined, new Date(Math.min(startDate, next.getTime() + later.SEC)) ];
  652. if (lastResult && r[rStart].getTime() === lastResult[rEnd].getTime()) {
  653. lastResult[rEnd] = r[rEnd];
  654. loopCount++;
  655. } else {
  656. lastResult = r;
  657. results.push(lastResult);
  658. }
  659. if (!end) break;
  660. updateNextStarts(dir, schedules, schedStarts, end);
  661. } else {
  662. results.push(isForward ? new Date(Math.max(startDate, next)) : getStart(schedules, schedStarts, next, endDate));
  663. tickStarts(dir, schedules, schedStarts, next);
  664. }
  665. loopCount--;
  666. }
  667. for (var i = 0, len = results.length; i < len; i++) {
  668. var result = results[i];
  669. results[i] = Object.prototype.toString.call(result) === "[object Array]" ? [ cleanDate(result[0]), cleanDate(result[1]) ] : cleanDate(result);
  670. }
  671. return results.length === 0 ? later.NEVER : count === 1 ? results[0] : results;
  672. }
  673. function cleanDate(d) {
  674. if (d instanceof Date && !isNaN(d.valueOf())) {
  675. return new Date(d);
  676. }
  677. return undefined;
  678. }
  679. function setNextStarts(dir, schedArr, startsArr, startDate) {
  680. for (var i = 0, len = schedArr.length; i < len; i++) {
  681. startsArr[i] = schedArr[i].start(dir, startDate);
  682. }
  683. }
  684. function updateNextStarts(dir, schedArr, startsArr, startDate) {
  685. var compare = compareFn(dir);
  686. for (var i = 0, len = schedArr.length; i < len; i++) {
  687. if (startsArr[i] && !compare(startsArr[i], startDate)) {
  688. startsArr[i] = schedArr[i].start(dir, startDate);
  689. }
  690. }
  691. }
  692. function setRangeStarts(dir, schedArr, rangesArr, startDate) {
  693. var compare = compareFn(dir);
  694. for (var i = 0, len = schedArr.length; i < len; i++) {
  695. var nextStart = schedArr[i].start(dir, startDate);
  696. if (!nextStart) {
  697. rangesArr[i] = later.NEVER;
  698. } else {
  699. rangesArr[i] = [ nextStart, schedArr[i].end(dir, nextStart) ];
  700. }
  701. }
  702. }
  703. function updateRangeStarts(dir, schedArr, rangesArr, startDate) {
  704. var compare = compareFn(dir);
  705. for (var i = 0, len = schedArr.length; i < len; i++) {
  706. if (rangesArr[i] && !compare(rangesArr[i][0], startDate)) {
  707. var nextStart = schedArr[i].start(dir, startDate);
  708. if (!nextStart) {
  709. rangesArr[i] = later.NEVER;
  710. } else {
  711. rangesArr[i] = [ nextStart, schedArr[i].end(dir, nextStart) ];
  712. }
  713. }
  714. }
  715. }
  716. function tickStarts(dir, schedArr, startsArr, startDate) {
  717. for (var i = 0, len = schedArr.length; i < len; i++) {
  718. if (startsArr[i] && startsArr[i].getTime() === startDate.getTime()) {
  719. startsArr[i] = schedArr[i].start(dir, schedArr[i].tick(dir, startDate));
  720. }
  721. }
  722. }
  723. function getStart(schedArr, startsArr, startDate, minEndDate) {
  724. var result;
  725. for (var i = 0, len = startsArr.length; i < len; i++) {
  726. if (startsArr[i] && startsArr[i].getTime() === startDate.getTime()) {
  727. var start = schedArr[i].tickStart(startDate);
  728. if (minEndDate && start < minEndDate) {
  729. return minEndDate;
  730. }
  731. if (!result || start > result) {
  732. result = start;
  733. }
  734. }
  735. }
  736. return result;
  737. }
  738. function calcRangeOverlap(dir, rangesArr, startDate) {
  739. var compare = compareFn(dir), result;
  740. for (var i = 0, len = rangesArr.length; i < len; i++) {
  741. var range = rangesArr[i];
  742. if (range && !compare(range[0], startDate) && (!range[1] || compare(range[1], startDate))) {
  743. if (!result || compare(range[1], result)) {
  744. result = range[1];
  745. }
  746. }
  747. }
  748. return result;
  749. }
  750. function calcMaxEndDate(exceptsArr, compare) {
  751. var result;
  752. for (var i = 0, len = exceptsArr.length; i < len; i++) {
  753. if (exceptsArr[i] && (!result || compare(result, exceptsArr[i][0]))) {
  754. result = exceptsArr[i][0];
  755. }
  756. }
  757. return result;
  758. }
  759. function calcEnd(dir, schedArr, startsArr, startDate, maxEndDate) {
  760. var compare = compareFn(dir), result;
  761. for (var i = 0, len = schedArr.length; i < len; i++) {
  762. var start = startsArr[i];
  763. if (start && start.getTime() === startDate.getTime()) {
  764. var end = schedArr[i].end(dir, start);
  765. if (maxEndDate && (!end || compare(end, maxEndDate))) {
  766. return maxEndDate;
  767. }
  768. if (!result || compare(end, result)) {
  769. result = end;
  770. }
  771. }
  772. }
  773. return result;
  774. }
  775. function compareFn(dir) {
  776. return dir === "next" ? function(a, b) {
  777. return !b || a.getTime() > b.getTime();
  778. } : function(a, b) {
  779. return !a || b.getTime() > a.getTime();
  780. };
  781. }
  782. function findNext(arr, compare) {
  783. var next = arr[0];
  784. for (var i = 1, len = arr.length; i < len; i++) {
  785. if (arr[i] && compare(next, arr[i])) {
  786. next = arr[i];
  787. }
  788. }
  789. return next;
  790. }
  791. return {
  792. isValid: function(d) {
  793. return getInstances("next", 1, d, d) !== later.NEVER;
  794. },
  795. next: function(count, startDate, endDate) {
  796. return getInstances("next", count || 1, startDate, endDate);
  797. },
  798. prev: function(count, startDate, endDate) {
  799. return getInstances("prev", count || 1, startDate, endDate);
  800. },
  801. nextRange: function(count, startDate, endDate) {
  802. return getInstances("next", count || 1, startDate, endDate, true);
  803. },
  804. prevRange: function(count, startDate, endDate) {
  805. return getInstances("prev", count || 1, startDate, endDate, true);
  806. }
  807. };
  808. };
  809. later.setTimeout = function(fn, sched) {
  810. var s = later.schedule(sched), t;
  811. if (fn) {
  812. scheduleTimeout();
  813. }
  814. function scheduleTimeout() {
  815. var now = Date.now(), next = s.next(2, now);
  816. if (!next[0]) {
  817. t = undefined;
  818. return;
  819. }
  820. var diff = next[0].getTime() - now;
  821. if (diff < 1e3) {
  822. diff = next[1] ? next[1].getTime() - now : 1e3;
  823. }
  824. if (diff < 2147483647) {
  825. t = setTimeout(fn, diff);
  826. } else {
  827. t = setTimeout(scheduleTimeout, 2147483647);
  828. }
  829. }
  830. return {
  831. isDone: function() {
  832. return !t;
  833. },
  834. clear: function() {
  835. clearTimeout(t);
  836. }
  837. };
  838. };
  839. later.setInterval = function(fn, sched) {
  840. if (!fn) {
  841. return;
  842. }
  843. var t = later.setTimeout(scheduleTimeout, sched), done = t.isDone();
  844. function scheduleTimeout() {
  845. if (!done) {
  846. fn();
  847. t = later.setTimeout(scheduleTimeout, sched);
  848. }
  849. }
  850. return {
  851. isDone: function() {
  852. return t.isDone();
  853. },
  854. clear: function() {
  855. done = true;
  856. t.clear();
  857. }
  858. };
  859. };
  860. later.date = {};
  861. later.date.timezone = function(useLocalTime) {
  862. later.date.build = useLocalTime ? function(Y, M, D, h, m, s) {
  863. return new Date(Y, M, D, h, m, s);
  864. } : function(Y, M, D, h, m, s) {
  865. return new Date(Date.UTC(Y, M, D, h, m, s));
  866. };
  867. var get = useLocalTime ? "get" : "getUTC", d = Date.prototype;
  868. later.date.getYear = d[get + "FullYear"];
  869. later.date.getMonth = d[get + "Month"];
  870. later.date.getDate = d[get + "Date"];
  871. later.date.getDay = d[get + "Day"];
  872. later.date.getHour = d[get + "Hours"];
  873. later.date.getMin = d[get + "Minutes"];
  874. later.date.getSec = d[get + "Seconds"];
  875. later.date.isUTC = !useLocalTime;
  876. };
  877. later.date.UTC = function() {
  878. later.date.timezone(false);
  879. };
  880. later.date.localTime = function() {
  881. later.date.timezone(true);
  882. };
  883. later.date.UTC();
  884. later.SEC = 1e3;
  885. later.MIN = later.SEC * 60;
  886. later.HOUR = later.MIN * 60;
  887. later.DAY = later.HOUR * 24;
  888. later.WEEK = later.DAY * 7;
  889. later.DAYS_IN_MONTH = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ];
  890. later.NEVER = 0;
  891. later.date.next = function(Y, M, D, h, m, s) {
  892. return later.date.build(Y, M !== undefined ? M - 1 : 0, D !== undefined ? D : 1, h || 0, m || 0, s || 0);
  893. };
  894. later.date.nextRollover = function(d, val, constraint, period) {
  895. var cur = constraint.val(d), max = constraint.extent(d)[1];
  896. return (val || max) <= cur || val > max ? new Date(period.end(d).getTime() + later.SEC) : period.start(d);
  897. };
  898. later.date.prev = function(Y, M, D, h, m, s) {
  899. var len = arguments.length;
  900. M = len < 2 ? 11 : M - 1;
  901. D = len < 3 ? later.D.extent(later.date.next(Y, M + 1))[1] : D;
  902. h = len < 4 ? 23 : h;
  903. m = len < 5 ? 59 : m;
  904. s = len < 6 ? 59 : s;
  905. return later.date.build(Y, M, D, h, m, s);
  906. };
  907. later.date.prevRollover = function(d, val, constraint, period) {
  908. var cur = constraint.val(d);
  909. return val >= cur || !val ? period.start(period.prev(d, period.val(d) - 1)) : period.start(d);
  910. };
  911. later.parse = {};
  912. later.parse.cron = function(expr, hasSeconds) {
  913. var NAMES = {
  914. JAN: 1,
  915. FEB: 2,
  916. MAR: 3,
  917. APR: 4,
  918. MAY: 5,
  919. JUN: 6,
  920. JUL: 7,
  921. AUG: 8,
  922. SEP: 9,
  923. OCT: 10,
  924. NOV: 11,
  925. DEC: 12,
  926. SUN: 1,
  927. MON: 2,
  928. TUE: 3,
  929. WED: 4,
  930. THU: 5,
  931. FRI: 6,
  932. SAT: 7
  933. };
  934. var REPLACEMENTS = {
  935. "* * * * * *": "0/1 * * * * *",
  936. "@YEARLY": "0 0 1 1 *",
  937. "@ANNUALLY": "0 0 1 1 *",
  938. "@MONTHLY": "0 0 1 * *",
  939. "@WEEKLY": "0 0 * * 0",
  940. "@DAILY": "0 0 * * *",
  941. "@HOURLY": "0 * * * *"
  942. };
  943. var FIELDS = {
  944. s: [ 0, 0, 59 ],
  945. m: [ 1, 0, 59 ],
  946. h: [ 2, 0, 23 ],
  947. D: [ 3, 1, 31 ],
  948. M: [ 4, 1, 12 ],
  949. Y: [ 6, 1970, 2099 ],
  950. d: [ 5, 1, 7, 1 ]
  951. };
  952. function getValue(value, offset, max) {
  953. return isNaN(value) ? NAMES[value] || null : Math.min(+value + (offset || 0), max || 9999);
  954. }
  955. function cloneSchedule(sched) {
  956. var clone = {}, field;
  957. for (field in sched) {
  958. if (field !== "dc" && field !== "d") {
  959. clone[field] = sched[field].slice(0);
  960. }
  961. }
  962. return clone;
  963. }
  964. function add(sched, name, min, max, inc) {
  965. var i = min;
  966. if (!sched[name]) {
  967. sched[name] = [];
  968. }
  969. while (i <= max) {
  970. if (sched[name].indexOf(i) < 0) {
  971. sched[name].push(i);
  972. }
  973. i += inc || 1;
  974. }
  975. sched[name].sort(function(a, b) {
  976. return a - b;
  977. });
  978. }
  979. function addHash(schedules, curSched, value, hash) {
  980. if (curSched.d && !curSched.dc || curSched.dc && curSched.dc.indexOf(hash) < 0) {
  981. schedules.push(cloneSchedule(curSched));
  982. curSched = schedules[schedules.length - 1];
  983. }
  984. add(curSched, "d", value, value);
  985. add(curSched, "dc", hash, hash);
  986. }
  987. function addWeekday(s, curSched, value) {
  988. var except1 = {}, except2 = {};
  989. if (value === 1) {
  990. add(curSched, "D", 1, 3);
  991. add(curSched, "d", NAMES.MON, NAMES.FRI);
  992. add(except1, "D", 2, 2);
  993. add(except1, "d", NAMES.TUE, NAMES.FRI);
  994. add(except2, "D", 3, 3);
  995. add(except2, "d", NAMES.TUE, NAMES.FRI);
  996. } else {
  997. add(curSched, "D", value - 1, value + 1);
  998. add(curSched, "d", NAMES.MON, NAMES.FRI);
  999. add(except1, "D", value - 1, value - 1);
  1000. add(except1, "d", NAMES.MON, NAMES.THU);
  1001. add(except2, "D", value + 1, value + 1);
  1002. add(except2, "d", NAMES.TUE, NAMES.FRI);
  1003. }
  1004. s.exceptions.push(except1);
  1005. s.exceptions.push(except2);
  1006. }
  1007. function addRange(item, curSched, name, min, max, offset) {
  1008. var incSplit = item.split("/"), inc = +incSplit[1], range = incSplit[0];
  1009. if (range !== "*" && range !== "0") {
  1010. var rangeSplit = range.split("-");
  1011. min = getValue(rangeSplit[0], offset, max);
  1012. max = getValue(rangeSplit[1], offset, max) || max;
  1013. }
  1014. add(curSched, name, min, max, inc);
  1015. }
  1016. function parse(item, s, name, min, max, offset) {
  1017. var value, split, schedules = s.schedules, curSched = schedules[schedules.length - 1];
  1018. if (item === "L") {
  1019. item = min - 1;
  1020. }
  1021. if ((value = getValue(item, offset, max)) !== null) {
  1022. add(curSched, name, value, value);
  1023. } else if ((value = getValue(item.replace("W", ""), offset, max)) !== null) {
  1024. addWeekday(s, curSched, value);
  1025. } else if ((value = getValue(item.replace("L", ""), offset, max)) !== null) {
  1026. addHash(schedules, curSched, value, min - 1);
  1027. } else if ((split = item.split("#")).length === 2) {
  1028. value = getValue(split[0], offset, max);
  1029. addHash(schedules, curSched, value, getValue(split[1]));
  1030. } else {
  1031. addRange(item, curSched, name, min, max, offset);
  1032. }
  1033. }
  1034. function isHash(item) {
  1035. return item.indexOf("#") > -1 || item.indexOf("L") > 0;
  1036. }
  1037. function itemSorter(a, b) {
  1038. return isHash(a) && !isHash(b) ? 1 : a - b;
  1039. }
  1040. function parseExpr(expr) {
  1041. var schedule = {
  1042. schedules: [ {} ],
  1043. exceptions: []
  1044. }, components = expr.replace(/(\s)+/g, " ").split(" "), field, f, component, items;
  1045. for (field in FIELDS) {
  1046. f = FIELDS[field];
  1047. component = components[f[0]];
  1048. if (component && component !== "*" && component !== "?") {
  1049. items = component.split(",").sort(itemSorter);
  1050. var i, length = items.length;
  1051. for (i = 0; i < length; i++) {
  1052. parse(items[i], schedule, field, f[1], f[2], f[3]);
  1053. }
  1054. }
  1055. }
  1056. return schedule;
  1057. }
  1058. function prepareExpr(expr) {
  1059. var prepared = expr.toUpperCase();
  1060. return REPLACEMENTS[prepared] || prepared;
  1061. }
  1062. var e = prepareExpr(expr);
  1063. return parseExpr(hasSeconds ? e : "0 " + e);
  1064. };
  1065. later.parse.recur = function() {
  1066. var schedules = [], exceptions = [], cur, curArr = schedules, curName, values, every, modifier, applyMin, applyMax, i, last;
  1067. function add(name, min, max) {
  1068. name = modifier ? name + "_" + modifier : name;
  1069. if (!cur) {
  1070. curArr.push({});
  1071. cur = curArr[0];
  1072. }
  1073. if (!cur[name]) {
  1074. cur[name] = [];
  1075. }
  1076. curName = cur[name];
  1077. if (every) {
  1078. values = [];
  1079. for (i = min; i <= max; i += every) {
  1080. values.push(i);
  1081. }
  1082. last = {
  1083. n: name,
  1084. x: every,
  1085. c: curName.length,
  1086. m: max
  1087. };
  1088. }
  1089. values = applyMin ? [ min ] : applyMax ? [ max ] : values;
  1090. var length = values.length;
  1091. for (i = 0; i < length; i += 1) {
  1092. var val = values[i];
  1093. if (curName.indexOf(val) < 0) {
  1094. curName.push(val);
  1095. }
  1096. }
  1097. values = every = modifier = applyMin = applyMax = 0;
  1098. }
  1099. return {
  1100. schedules: schedules,
  1101. exceptions: exceptions,
  1102. on: function() {
  1103. values = arguments[0] instanceof Array ? arguments[0] : arguments;
  1104. return this;
  1105. },
  1106. every: function(x) {
  1107. every = x || 1;
  1108. return this;
  1109. },
  1110. after: function(x) {
  1111. modifier = "a";
  1112. values = [ x ];
  1113. return this;
  1114. },
  1115. before: function(x) {
  1116. modifier = "b";
  1117. values = [ x ];
  1118. return this;
  1119. },
  1120. first: function() {
  1121. applyMin = 1;
  1122. return this;
  1123. },
  1124. last: function() {
  1125. applyMax = 1;
  1126. return this;
  1127. },
  1128. time: function() {
  1129. for (var i = 0, len = values.length; i < len; i++) {
  1130. var split = values[i].split(":");
  1131. if (split.length < 3) split.push(0);
  1132. values[i] = +split[0] * 3600 + +split[1] * 60 + +split[2];
  1133. }
  1134. add("t");
  1135. return this;
  1136. },
  1137. second: function() {
  1138. add("s", 0, 59);
  1139. return this;
  1140. },
  1141. minute: function() {
  1142. add("m", 0, 59);
  1143. return this;
  1144. },
  1145. hour: function() {
  1146. add("h", 0, 23);
  1147. return this;
  1148. },
  1149. dayOfMonth: function() {
  1150. add("D", 1, applyMax ? 0 : 31);
  1151. return this;
  1152. },
  1153. dayOfWeek: function() {
  1154. add("d", 1, 7);
  1155. return this;
  1156. },
  1157. onWeekend: function() {
  1158. values = [ 1, 7 ];
  1159. return this.dayOfWeek();
  1160. },
  1161. onWeekday: function() {
  1162. values = [ 2, 3, 4, 5, 6 ];
  1163. return this.dayOfWeek();
  1164. },
  1165. dayOfWeekCount: function() {
  1166. add("dc", 1, applyMax ? 0 : 5);
  1167. return this;
  1168. },
  1169. dayOfYear: function() {
  1170. add("dy", 1, applyMax ? 0 : 366);
  1171. return this;
  1172. },
  1173. weekOfMonth: function() {
  1174. add("wm", 1, applyMax ? 0 : 5);
  1175. return this;
  1176. },
  1177. weekOfYear: function() {
  1178. add("wy", 1, applyMax ? 0 : 53);
  1179. return this;
  1180. },
  1181. month: function() {
  1182. add("M", 1, 12);
  1183. return this;
  1184. },
  1185. year: function() {
  1186. add("Y", 1970, 2450);
  1187. return this;
  1188. },
  1189. fullDate: function() {
  1190. for (var i = 0, len = values.length; i < len; i++) {
  1191. values[i] = values[i].getTime();
  1192. }
  1193. add("fd");
  1194. return this;
  1195. },
  1196. customModifier: function(id, vals) {
  1197. var custom = later.modifier[id];
  1198. if (!custom) throw new Error("Custom modifier " + id + " not recognized!");
  1199. modifier = id;
  1200. values = arguments[1] instanceof Array ? arguments[1] : [ arguments[1] ];
  1201. return this;
  1202. },
  1203. customPeriod: function(id) {
  1204. var custom = later[id];
  1205. if (!custom) throw new Error("Custom time period " + id + " not recognized!");
  1206. add(id, custom.extent(new Date())[0], custom.extent(new Date())[1]);
  1207. return this;
  1208. },
  1209. startingOn: function(start) {
  1210. return this.between(start, last.m);
  1211. },
  1212. between: function(start, end) {
  1213. cur[last.n] = cur[last.n].splice(0, last.c);
  1214. every = last.x;
  1215. add(last.n, start, end);
  1216. return this;
  1217. },
  1218. and: function() {
  1219. cur = curArr[curArr.push({}) - 1];
  1220. return this;
  1221. },
  1222. except: function() {
  1223. curArr = exceptions;
  1224. cur = null;
  1225. return this;
  1226. }
  1227. };
  1228. };
  1229. later.parse.text = function(str) {
  1230. var recur = later.parse.recur, pos = 0, input = "", error;
  1231. var TOKENTYPES = {
  1232. eof: /^$/,
  1233. rank: /^((\d\d\d\d)|([2-5]?1(st)?|[2-5]?2(nd)?|[2-5]?3(rd)?|(0|[1-5]?[4-9]|[1-5]0|1[1-3])(th)?))\b/,
  1234. time: /^((([0]?[1-9]|1[0-2]):[0-5]\d(\s)?(am|pm))|(([0]?\d|1\d|2[0-3]):[0-5]\d))\b/,
  1235. dayName: /^((sun|mon|tue(s)?|wed(nes)?|thu(r(s)?)?|fri|sat(ur)?)(day)?)\b/,
  1236. monthName: /^(jan(uary)?|feb(ruary)?|ma((r(ch)?)?|y)|apr(il)?|ju(ly|ne)|aug(ust)?|oct(ober)?|(sept|nov|dec)(ember)?)\b/,
  1237. yearIndex: /^(\d\d\d\d)\b/,
  1238. every: /^every\b/,
  1239. after: /^after\b/,
  1240. before: /^before\b/,
  1241. second: /^(s|sec(ond)?(s)?)\b/,
  1242. minute: /^(m|min(ute)?(s)?)\b/,
  1243. hour: /^(h|hour(s)?)\b/,
  1244. day: /^(day(s)?( of the month)?)\b/,
  1245. dayInstance: /^day instance\b/,
  1246. dayOfWeek: /^day(s)? of the week\b/,
  1247. dayOfYear: /^day(s)? of the year\b/,
  1248. weekOfYear: /^week(s)?( of the year)?\b/,
  1249. weekOfMonth: /^week(s)? of the month\b/,
  1250. weekday: /^weekday\b/,
  1251. weekend: /^weekend\b/,
  1252. month: /^month(s)?\b/,
  1253. year: /^year(s)?\b/,
  1254. between: /^between (the)?\b/,
  1255. start: /^(start(ing)? (at|on( the)?)?)\b/,
  1256. at: /^(at|@)\b/,
  1257. and: /^(,|and\b)/,
  1258. except: /^(except\b)/,
  1259. also: /(also)\b/,
  1260. first: /^(first)\b/,
  1261. last: /^last\b/,
  1262. "in": /^in\b/,
  1263. of: /^of\b/,
  1264. onthe: /^on the\b/,
  1265. on: /^on\b/,
  1266. through: /(-|^(to|through)\b)/
  1267. };
  1268. var NAMES = {
  1269. jan: 1,
  1270. feb: 2,
  1271. mar: 3,
  1272. apr: 4,
  1273. may: 5,
  1274. jun: 6,
  1275. jul: 7,
  1276. aug: 8,
  1277. sep: 9,
  1278. oct: 10,
  1279. nov: 11,
  1280. dec: 12,
  1281. sun: 1,
  1282. mon: 2,
  1283. tue: 3,
  1284. wed: 4,
  1285. thu: 5,
  1286. fri: 6,
  1287. sat: 7,
  1288. "1st": 1,
  1289. fir: 1,
  1290. "2nd": 2,
  1291. sec: 2,
  1292. "3rd": 3,
  1293. thi: 3,
  1294. "4th": 4,
  1295. "for": 4
  1296. };
  1297. function t(start, end, text, type) {
  1298. return {
  1299. startPos: start,
  1300. endPos: end,
  1301. text: text,
  1302. type: type
  1303. };
  1304. }
  1305. function peek(expected) {
  1306. var scanTokens = expected instanceof Array ? expected : [ expected ], whiteSpace = /\s+/, token, curInput, m, scanToken, start, len;
  1307. scanTokens.push(whiteSpace);
  1308. start = pos;
  1309. while (!token || token.type === whiteSpace) {
  1310. len = -1;
  1311. curInput = input.substring(start);
  1312. token = t(start, start, input.split(whiteSpace)[0]);
  1313. var i, length = scanTokens.length;
  1314. for (i = 0; i < length; i++) {
  1315. scanToken = scanTokens[i];
  1316. m = scanToken.exec(curInput);
  1317. if (m && m.index === 0 && m[0].length > len) {
  1318. len = m[0].length;
  1319. token = t(start, start + len, curInput.substring(0, len), scanToken);
  1320. }
  1321. }
  1322. if (token.type === whiteSpace) {
  1323. start = token.endPos;
  1324. }
  1325. }
  1326. return token;
  1327. }
  1328. function scan(expectedToken) {
  1329. var token = peek(expectedToken);
  1330. pos = token.endPos;
  1331. return token;
  1332. }
  1333. function parseThroughExpr(tokenType) {
  1334. var start = +parseTokenValue(tokenType), end = checkAndParse(TOKENTYPES.through) ? +parseTokenValue(tokenType) : start, nums = [];
  1335. for (var i = start; i <= end; i++) {
  1336. nums.push(i);
  1337. }
  1338. return nums;
  1339. }
  1340. function parseRanges(tokenType) {
  1341. var nums = parseThroughExpr(tokenType);
  1342. while (checkAndParse(TOKENTYPES.and)) {
  1343. nums = nums.concat(parseThroughExpr(tokenType));
  1344. }
  1345. return nums;
  1346. }
  1347. function parseEvery(r) {
  1348. var num, period, start, end;
  1349. if (checkAndParse(TOKENTYPES.weekend)) {
  1350. r.on(NAMES.sun, NAMES.sat).dayOfWeek();
  1351. } else if (checkAndParse(TOKENTYPES.weekday)) {
  1352. r.on(NAMES.mon, NAMES.tue, NAMES.wed, NAMES.thu, NAMES.fri).dayOfWeek();
  1353. } else {
  1354. num = parseTokenValue(TOKENTYPES.rank);
  1355. r.every(num);
  1356. period = parseTimePeriod(r);
  1357. if (checkAndParse(TOKENTYPES.start)) {
  1358. num = parseTokenValue(TOKENTYPES.rank);
  1359. r.startingOn(num);
  1360. parseToken(period.type);
  1361. } else if (checkAndParse(TOKENTYPES.between)) {
  1362. start = parseTokenValue(TOKENTYPES.rank);
  1363. if (checkAndParse(TOKENTYPES.and)) {
  1364. end = parseTokenValue(TOKENTYPES.rank);
  1365. r.between(start, end);
  1366. }
  1367. }
  1368. }
  1369. }
  1370. function parseOnThe(r) {
  1371. if (checkAndParse(TOKENTYPES.first)) {
  1372. r.first();
  1373. } else if (checkAndParse(TOKENTYPES.last)) {
  1374. r.last();
  1375. } else {
  1376. r.on(parseRanges(TOKENTYPES.rank));
  1377. }
  1378. parseTimePeriod(r);
  1379. }
  1380. function parseScheduleExpr(str) {
  1381. pos = 0;
  1382. input = str;
  1383. error = -1;
  1384. var r = recur();
  1385. while (pos < input.length && error < 0) {
  1386. var token = parseToken([ TOKENTYPES.every, TOKENTYPES.after, TOKENTYPES.before, TOKENTYPES.onthe, TOKENTYPES.on, TOKENTYPES.of, TOKENTYPES["in"], TOKENTYPES.at, TOKENTYPES.and, TOKENTYPES.except, TOKENTYPES.also ]);
  1387. switch (token.type) {
  1388. case TOKENTYPES.every:
  1389. parseEvery(r);
  1390. break;
  1391. case TOKENTYPES.after:
  1392. if (peek(TOKENTYPES.time).type !== undefined) {
  1393. r.after(parseTokenValue(TOKENTYPES.time));
  1394. r.time();
  1395. } else {
  1396. r.after(parseTokenValue(TOKENTYPES.rank));
  1397. parseTimePeriod(r);
  1398. }
  1399. break;
  1400. case TOKENTYPES.before:
  1401. if (peek(TOKENTYPES.time).type !== undefined) {
  1402. r.before(parseTokenValue(TOKENTYPES.time));
  1403. r.time();
  1404. } else {
  1405. r.before(parseTokenValue(TOKENTYPES.rank));
  1406. parseTimePeriod(r);
  1407. }
  1408. break;
  1409. case TOKENTYPES.onthe:
  1410. parseOnThe(r);
  1411. break;
  1412. case TOKENTYPES.on:
  1413. r.on(parseRanges(TOKENTYPES.dayName)).dayOfWeek();
  1414. break;
  1415. case TOKENTYPES.of:
  1416. r.on(parseRanges(TOKENTYPES.monthName)).month();
  1417. break;
  1418. case TOKENTYPES["in"]:
  1419. r.on(parseRanges(TOKENTYPES.yearIndex)).year();
  1420. break;
  1421. case TOKENTYPES.at:
  1422. r.on(parseTokenValue(TOKENTYPES.time)).time();
  1423. while (checkAndParse(TOKENTYPES.and)) {
  1424. r.on(parseTokenValue(TOKENTYPES.time)).time();
  1425. }
  1426. break;
  1427. case TOKENTYPES.and:
  1428. break;
  1429. case TOKENTYPES.also:
  1430. r.and();
  1431. break;
  1432. case TOKENTYPES.except:
  1433. r.except();
  1434. break;
  1435. default:
  1436. error = pos;
  1437. }
  1438. }
  1439. return {
  1440. schedules: r.schedules,
  1441. exceptions: r.exceptions,
  1442. error: error
  1443. };
  1444. }
  1445. function parseTimePeriod(r) {
  1446. var timePeriod = parseToken([ TOKENTYPES.second, TOKENTYPES.minute, TOKENTYPES.hour, TOKENTYPES.dayOfYear, TOKENTYPES.dayOfWeek, TOKENTYPES.dayInstance, TOKENTYPES.day, TOKENTYPES.month, TOKENTYPES.year, TOKENTYPES.weekOfMonth, TOKENTYPES.weekOfYear ]);
  1447. switch (timePeriod.type) {
  1448. case TOKENTYPES.second:
  1449. r.second();
  1450. break;
  1451. case TOKENTYPES.minute:
  1452. r.minute();
  1453. break;
  1454. case TOKENTYPES.hour:
  1455. r.hour();
  1456. break;
  1457. case TOKENTYPES.dayOfYear:
  1458. r.dayOfYear();
  1459. break;
  1460. case TOKENTYPES.dayOfWeek:
  1461. r.dayOfWeek();
  1462. break;
  1463. case TOKENTYPES.dayInstance:
  1464. r.dayOfWeekCo