scheduler.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  1. /*
  2. * Fuel UX Scheduler
  3. * https://github.com/ExactTarget/fuelux
  4. *
  5. * Copyright (c) 2014 ExactTarget
  6. * Licensed under the BSD New license.
  7. */
  8. // -- BEGIN UMD WRAPPER PREFACE --
  9. // For more information on UMD visit:
  10. // https://github.com/umdjs/umd/blob/master/jqueryPlugin.js
  11. (function (factory) {
  12. if (typeof define === 'function' && define.amd) {
  13. // if AMD loader is available, register as an anonymous module.
  14. define(['jquery', 'fuelux/combobox', 'fuelux/datepicker', 'fuelux/radio', 'fuelux/selectlist', 'fuelux/spinbox'], factory);
  15. } else {
  16. // OR use browser globals if AMD is not present
  17. factory(jQuery);
  18. }
  19. }(function ($) {
  20. if (!$.fn.combobox || !$.fn.datepicker || !$.fn.radio || !$.fn.selectlist || !$.fn.spinbox) {
  21. throw new Error('Fuel UX scheduler control requires combobox, datepicker, radio, selectlist, and spinbox.');
  22. }
  23. // -- END UMD WRAPPER PREFACE --
  24. // -- BEGIN MODULE CODE HERE --
  25. var old = $.fn.scheduler;
  26. // SCHEDULER CONSTRUCTOR AND PROTOTYPE
  27. var Scheduler = function (element, options) {
  28. var self = this;
  29. this.$element = $(element);
  30. this.options = $.extend({}, $.fn.scheduler.defaults, options);
  31. // cache elements
  32. this.$startDate = this.$element.find('.start-datetime .start-date');
  33. this.$startTime = this.$element.find('.start-datetime .start-time');
  34. this.$timeZone = this.$element.find('.timezone-container .timezone');
  35. this.$repeatIntervalPanel = this.$element.find('.repeat-every-panel');
  36. this.$repeatIntervalSelect = this.$element.find('.repeat-options');
  37. this.$repeatIntervalSpinbox = this.$element.find('.repeat-every');
  38. this.$repeatIntervalTxt = this.$element.find('.repeat-every-text');
  39. this.$end = this.$element.find('.repeat-end');
  40. this.$endSelect = this.$end.find('.end-options');
  41. this.$endAfter = this.$end.find('.end-after');
  42. this.$endDate = this.$end.find('.end-on-date');
  43. // panels
  44. this.$recurrencePanels = this.$element.find('.repeat-panel');
  45. this.$repeatIntervalSelect.selectlist();
  46. //initialize sub-controls
  47. this.$element.find('.selectlist').selectlist();
  48. this.$startDate.datepicker(this.options.startDateOptions);
  49. this.$startTime.combobox();
  50. // init start time
  51. if (this.$startTime.find('input').val() === '') {
  52. this.$startTime.combobox('selectByIndex', 0);
  53. }
  54. // every 0 days/hours doesn't make sense, change if not set
  55. if (this.$repeatIntervalSpinbox.find('input').val() === '0') {
  56. this.$repeatIntervalSpinbox.spinbox({
  57. 'value': 1,
  58. 'min': 1
  59. });
  60. } else {
  61. this.$repeatIntervalSpinbox.spinbox({
  62. 'min': 1
  63. });
  64. }
  65. this.$endAfter.spinbox({
  66. 'value': 1,
  67. 'min': 1
  68. });
  69. this.$endDate.datepicker(this.options.endDateOptions);
  70. this.$element.find('.radio-custom').radio();
  71. // bind events: 'change' is a Bootstrap JS fired event
  72. this.$repeatIntervalSelect.on('changed.fu.selectlist', $.proxy(this.repeatIntervalSelectChanged, this));
  73. this.$endSelect.on('changed.fu.selectlist', $.proxy(this.endSelectChanged, this));
  74. this.$element.find('.repeat-days-of-the-week .btn-group .btn').on('change.fu.scheduler', function (e, data) {
  75. self.changed(e, data, true);
  76. });
  77. this.$element.find('.combobox').on('changed.fu.combobox', $.proxy(this.changed, this));
  78. this.$element.find('.datepicker').on('changed.fu.datepicker', $.proxy(this.changed, this));
  79. this.$element.find('.selectlist').on('changed.fu.selectlist', $.proxy(this.changed, this));
  80. this.$element.find('.spinbox').on('changed.fu.spinbox', $.proxy(this.changed, this));
  81. this.$element.find('.repeat-monthly .radio, .repeat-yearly .radio').on('change.fu.scheduler', $.proxy(this.changed, this));
  82. };
  83. Scheduler.prototype = {
  84. constructor: Scheduler,
  85. destroy: function () {
  86. var markup;
  87. // set input value attribute
  88. this.$element.find('input').each(function () {
  89. $(this).attr('value', $(this).val());
  90. });
  91. // empty elements to return to original markup and store
  92. this.$element.find('.datepicker .calendar').empty();
  93. markup = this.$element[0].outerHTML;
  94. // destroy components
  95. this.$element.find('.combobox').combobox('destroy');
  96. this.$element.find('.datepicker').datepicker('destroy');
  97. this.$element.find('.selectlist').selectlist('destroy');
  98. this.$element.find('.spinbox').spinbox('destroy');
  99. this.$element.find('[type=radio]').radio('destroy');
  100. this.$element.remove();
  101. // any external bindings
  102. // [none]
  103. return markup;
  104. },
  105. changed: function (e, data, propagate) {
  106. if (!propagate) {
  107. e.stopPropagation();
  108. }
  109. this.$element.trigger('changed.fu.scheduler', {
  110. data: (data !== undefined) ? data : $(e.currentTarget).data(),
  111. originalEvent: e,
  112. value: this.getValue()
  113. });
  114. },
  115. disable: function () {
  116. this.toggleState('disable');
  117. },
  118. enable: function () {
  119. this.toggleState('enable');
  120. },
  121. setUtcTime: function (d, t, offset) {
  122. var date = d.split('-');
  123. var time = t.split(':');
  124. function z(n) {
  125. return (n < 10 ? '0' : '') + n;
  126. }
  127. var utcDate = new Date(Date.UTC(date[0], (date[1] - 1), date[2], time[0], time[1], (time[2] ? time[2] : 0)));
  128. if (offset === 'Z') {
  129. utcDate.setUTCHours(utcDate.getUTCHours() + 0);
  130. } else {
  131. var re1 = '(.)';// Any Single Character 1
  132. var re2 = '.*?';// Non-greedy match on filler
  133. var re3 = '\\d';// Uninteresting: d
  134. var re4 = '.*?';// Non-greedy match on filler
  135. var re5 = '(\\d)';// Any Single Digit 1
  136. var p = new RegExp(re1 + re2 + re3 + re4 + re5, ["i"]);
  137. var m = p.exec(offset);
  138. if (m !== null) {
  139. var c1 = m[1];
  140. var d1 = m[2];
  141. var modifier = (c1 === '+') ? 1 : -1;
  142. utcDate.setUTCHours(utcDate.getUTCHours() + (modifier * parseInt(d1, 10)));
  143. }
  144. }
  145. var localDifference = utcDate.getTimezoneOffset();
  146. utcDate.setMinutes(localDifference);
  147. return utcDate;
  148. },
  149. // called when the end range changes
  150. // (Never, After, On date)
  151. endSelectChanged: function (e, data) {
  152. var selectedItem, val;
  153. if (!data) {
  154. selectedItem = this.$endSelect.selectlist('selectedItem');
  155. val = selectedItem.value;
  156. } else {
  157. val = data.value;
  158. }
  159. // hide all panels
  160. this.$endAfter.parent().addClass('hide');
  161. this.$endAfter.parent().attr('aria-hidden', 'true');
  162. this.$endDate.parent().addClass('hide');
  163. this.$endDate.parent().attr('aria-hidden', 'true');
  164. if (val === 'after') {
  165. this.$endAfter.parent().removeClass('hide');
  166. this.$endAfter.parent().attr('aria-hidden', 'false');
  167. } else if (val === 'date') {
  168. this.$endDate.parent().removeClass('hide');
  169. this.$endDate.parent().attr('aria-hidden', 'false');
  170. }
  171. },
  172. getValue: function () {
  173. // FREQ = frequency (hourly, daily, monthly...)
  174. // BYDAY = when picking days (MO,TU,WE,etc)
  175. // BYMONTH = when picking months (Jan,Feb,March) - note the values should be 1,2,3...
  176. // BYMONTHDAY = when picking days of the month (1,2,3...)
  177. // BYSETPOS = when picking First,Second,Third,Fourth,Last (1,2,3,4,-1)
  178. var interval = this.$repeatIntervalSpinbox.spinbox('value');
  179. var pattern = '';
  180. var repeat = this.$repeatIntervalSelect.selectlist('selectedItem').value;
  181. var startTime;
  182. if (this.$startTime.combobox('selectedItem').value) {
  183. startTime = this.$startTime.combobox('selectedItem').value;
  184. startTime = startTime.toLowerCase();
  185. } else {
  186. startTime = this.$startTime.combobox('selectedItem').text.toLowerCase();
  187. }
  188. var timeZone = this.$timeZone.selectlist('selectedItem');
  189. var getFormattedDate;
  190. getFormattedDate = function (dateObj, dash) {
  191. var fdate = '';
  192. var item;
  193. fdate += dateObj.getFullYear();
  194. fdate += dash;
  195. item = dateObj.getMonth() + 1;//because 0 indexing makes sense when dealing with months /sarcasm
  196. fdate += (item < 10) ? '0' + item : item;
  197. fdate += dash;
  198. item = dateObj.getDate();
  199. fdate += (item < 10) ? '0' + item : item;
  200. return fdate;
  201. };
  202. var day, days, hasAm, hasPm, month, pos, startDateTime, type;
  203. startDateTime = '' + getFormattedDate(this.$startDate.datepicker('getDate'), '-');
  204. startDateTime += 'T';
  205. hasAm = (startTime.search('am') >= 0);
  206. hasPm = (startTime.search('pm') >= 0);
  207. startTime = $.trim(startTime.replace(/am/g, '').replace(/pm/g, '')).split(':');
  208. startTime[0] = parseInt(startTime[0], 10);
  209. startTime[1] = parseInt(startTime[1], 10);
  210. if (hasAm && startTime[0] > 11) {
  211. startTime[0] = 0;
  212. } else if (hasPm && startTime[0] < 12) {
  213. startTime[0] += 12;
  214. }
  215. startDateTime += (startTime[0] < 10) ? '0' + startTime[0] : startTime[0];
  216. startDateTime += ':';
  217. startDateTime += (startTime[1] < 10) ? '0' + startTime[1] : startTime[1];
  218. startDateTime += (timeZone.offset === '+00:00') ? 'Z' : timeZone.offset;
  219. if (repeat === 'none') {
  220. pattern = 'FREQ=DAILY;INTERVAL=1;COUNT=1;';
  221. } else if (repeat === 'hourly') {
  222. pattern = 'FREQ=HOURLY;';
  223. pattern += 'INTERVAL=' + interval + ';';
  224. } else if (repeat === 'daily') {
  225. pattern += 'FREQ=DAILY;';
  226. pattern += 'INTERVAL=' + interval + ';';
  227. } else if (repeat === 'weekdays') {
  228. pattern += 'FREQ=DAILY;';
  229. pattern += 'BYDAY=MO,TU,WE,TH,FR;';
  230. pattern += 'INTERVAL=1;';
  231. } else if (repeat === 'weekly') {
  232. days = [];
  233. this.$element.find('.repeat-days-of-the-week .btn-group input:checked').each(function () {
  234. days.push($(this).data().value);
  235. });
  236. pattern += 'FREQ=WEEKLY;';
  237. pattern += 'BYDAY=' + days.join(',') + ';';
  238. pattern += 'INTERVAL=' + interval + ';';
  239. } else if (repeat === 'monthly') {
  240. pattern += 'FREQ=MONTHLY;';
  241. pattern += 'INTERVAL=' + interval + ';';
  242. type = this.$element.find('input[name=repeat-monthly]:checked').val();
  243. if (type === 'bymonthday') {
  244. day = parseInt(this.$element.find('.repeat-monthly-date .selectlist').selectlist('selectedItem').text, 10);
  245. pattern += 'BYMONTHDAY=' + day + ';';
  246. } else if (type === 'bysetpos') {
  247. days = this.$element.find('.month-days').selectlist('selectedItem').value;
  248. pos = this.$element.find('.month-day-pos').selectlist('selectedItem').value;
  249. pattern += 'BYDAY=' + days + ';';
  250. pattern += 'BYSETPOS=' + pos + ';';
  251. }
  252. } else if (repeat === 'yearly') {
  253. pattern += 'FREQ=YEARLY;';
  254. type = this.$element.find('input[name=repeat-yearly]:checked').val();
  255. if (type === 'bymonthday') {
  256. month = this.$element.find('.repeat-yearly-date .year-month').selectlist('selectedItem').value;
  257. day = this.$element.find('.year-month-day').selectlist('selectedItem').text;
  258. pattern += 'BYMONTH=' + month + ';';
  259. pattern += 'BYMONTHDAY=' + day + ';';
  260. } else if (type === 'bysetpos') {
  261. days = this.$element.find('.year-month-days').selectlist('selectedItem').value;
  262. pos = this.$element.find('.year-month-day-pos').selectlist('selectedItem').value;
  263. month = this.$element.find('.repeat-yearly-day .year-month').selectlist('selectedItem').value;
  264. pattern += 'BYDAY=' + days + ';';
  265. pattern += 'BYSETPOS=' + pos + ';';
  266. pattern += 'BYMONTH=' + month + ';';
  267. }
  268. }
  269. var end = this.$endSelect.selectlist('selectedItem').value;
  270. var duration = '';
  271. // if both UNTIL and COUNT are not specified, the recurrence will repeat forever
  272. // http://tools.ietf.org/html/rfc2445#section-4.3.10
  273. if (repeat !== 'none') {
  274. if (end === 'after') {
  275. duration = 'COUNT=' + this.$endAfter.spinbox('value') + ';';
  276. } else if (end === 'date') {
  277. duration = 'UNTIL=' + getFormattedDate(this.$endDate.datepicker('getDate'), '') + ';';
  278. }
  279. }
  280. pattern += duration;
  281. var data = {
  282. startDateTime: startDateTime,
  283. timeZone: {
  284. name: timeZone.name,
  285. offset: timeZone.offset
  286. },
  287. recurrencePattern: pattern
  288. };
  289. return data;
  290. },
  291. // called when the repeat interval changes
  292. // (None, Hourly, Daily, Weekdays, Weekly, Monthly, Yearly
  293. repeatIntervalSelectChanged: function (e, data) {
  294. var selectedItem, val, txt;
  295. if (!data) {
  296. selectedItem = this.$repeatIntervalSelect.selectlist('selectedItem');
  297. val = selectedItem.value;
  298. txt = selectedItem.text;
  299. } else {
  300. val = data.value;
  301. txt = data.text;
  302. }
  303. // set the text
  304. this.$repeatIntervalTxt.text(txt);
  305. switch (val.toLowerCase()) {
  306. case 'hourly':
  307. case 'daily':
  308. case 'weekly':
  309. case 'monthly':
  310. this.$repeatIntervalPanel.removeClass('hide');
  311. this.$repeatIntervalPanel.attr('aria-hidden', 'false');
  312. break;
  313. default:
  314. this.$repeatIntervalPanel.addClass('hide');
  315. this.$repeatIntervalPanel.attr('aria-hidden', 'true');
  316. break;
  317. }
  318. // hide all panels
  319. this.$recurrencePanels.addClass('hide');
  320. this.$recurrencePanels.attr('aria-hidden', 'true');
  321. // show panel for current selection
  322. this.$element.find('.repeat-' + val).removeClass('hide');
  323. this.$element.find('.repeat-' + val).attr('aria-hidden', 'false');
  324. // the end selection should only be shown when
  325. // the repeat interval is not "None (run once)"
  326. if (val === 'none') {
  327. this.$end.addClass('hide');
  328. this.$end.attr('aria-hidden', 'true');
  329. } else {
  330. this.$end.removeClass('hide');
  331. this.$end.attr('aria-hidden', 'false');
  332. }
  333. },
  334. setValue: function (options) {
  335. var hours, i, item, l, minutes, period, recur, temp, startDate, startTime, timeOffset;
  336. if (options.startDateTime) {
  337. temp = options.startDateTime.split('T');
  338. startDate = temp[0];
  339. if (temp[1]) {
  340. startTime = temp[1];
  341. temp[1] = temp[1].split(':');
  342. hours = parseInt(temp[1][0], 10);
  343. minutes = (temp[1][1]) ? parseInt(temp[1][1].split('+')[0].split('-')[0].split('Z')[0], 10) : 0;
  344. period = (hours < 12) ? 'AM' : 'PM';
  345. if (hours === 0) {
  346. hours = 12;
  347. } else if (hours > 12) {
  348. hours -= 12;
  349. }
  350. minutes = (minutes < 10) ? '0' + minutes : minutes;
  351. startTime = hours + ':' + minutes;
  352. temp = hours + ':' + minutes + ' ' + period;
  353. this.$startTime.find('input').val(temp);
  354. this.$startTime.combobox('selectByText', temp);
  355. } else {
  356. startTime = '00:00';
  357. }
  358. } else {
  359. startTime = '00:00';
  360. var currentDate = this.$startDate.datepicker('getDate');
  361. startDate = currentDate.getFullYear() + '-' + currentDate.getMonth() + '-' + currentDate.getDate();
  362. }
  363. item = 'li[data';
  364. if (options.timeZone) {
  365. if (typeof (options.timeZone) === 'string') {
  366. item += '-name="' + options.timeZone;
  367. } else {
  368. if (options.timeZone.name) {
  369. item += '-name="' + options.timeZone.name;
  370. } else {
  371. item += '-offset="' + options.timeZone.offset;
  372. }
  373. }
  374. item += '"]';
  375. timeOffset = options.timeZone.offset;
  376. this.$timeZone.selectlist('selectBySelector', item);
  377. } else if (options.startDateTime) {
  378. temp = options.startDateTime.split('T')[1];
  379. if (temp) {
  380. if (temp.search(/\+/) > -1) {
  381. temp = '+' + $.trim(temp.split('+')[1]);
  382. } else if (temp.search(/\-/) > -1) {
  383. temp = '-' + $.trim(temp.split('-')[1]);
  384. } else {
  385. temp = '+00:00';
  386. }
  387. } else {
  388. temp = '+00:00';
  389. }
  390. timeOffset = (temp === '+00:00') ? 'Z' : temp;
  391. item += '-offset="' + temp + '"]';
  392. this.$timeZone.selectlist('selectBySelector', item);
  393. } else {
  394. timeOffset = 'Z';
  395. }
  396. if (options.recurrencePattern) {
  397. recur = {};
  398. temp = options.recurrencePattern.toUpperCase().split(';');
  399. for (i = 0, l = temp.length; i < l; i++) {
  400. if (temp[i] !== '') {
  401. item = temp[i].split('=');
  402. recur[item[0]] = item[1];
  403. }
  404. }
  405. if (recur.FREQ === 'DAILY') {
  406. if (recur.BYDAY === 'MO,TU,WE,TH,FR') {
  407. item = 'weekdays';
  408. } else {
  409. if (recur.INTERVAL === '1' && recur.COUNT === '1') {
  410. item = 'none';
  411. } else {
  412. item = 'daily';
  413. }
  414. }
  415. } else if (recur.FREQ === 'HOURLY') {
  416. item = 'hourly';
  417. } else if (recur.FREQ === 'WEEKLY') {
  418. if (recur.BYDAY) {
  419. item = this.$element.find('.repeat-days-of-the-week .btn-group');
  420. item.find('label').removeClass('active');
  421. temp = recur.BYDAY.split(',');
  422. for (i = 0, l = temp.length; i < l; i++) {
  423. item.find('input[data-value="' + temp[i] + '"]').prop('checked',true).parent().addClass('active');
  424. }
  425. }
  426. item = 'weekly';
  427. } else if (recur.FREQ === 'MONTHLY') {
  428. this.$element.find('.repeat-monthly input').removeAttr('checked').removeClass('checked');
  429. this.$element.find('.repeat-monthly label.radio-custom').removeClass('checked');
  430. if (recur.BYMONTHDAY) {
  431. temp = this.$element.find('.repeat-monthly-date');
  432. temp.find('input').addClass('checked').prop('checked', true);
  433. temp.find('label.radio-custom').addClass('checked');
  434. temp.find('.selectlist').selectlist('selectByValue', recur.BYMONTHDAY);
  435. } else if (recur.BYDAY) {
  436. temp = this.$element.find('.repeat-monthly-day');
  437. temp.find('input').addClass('checked').prop('checked', true);
  438. temp.find('label.radio-custom').addClass('checked');
  439. if (recur.BYSETPOS) {
  440. temp.find('.month-day-pos').selectlist('selectByValue', recur.BYSETPOS);
  441. }
  442. temp.find('.month-days').selectlist('selectByValue', recur.BYDAY);
  443. }
  444. item = 'monthly';
  445. } else if (recur.FREQ === 'YEARLY') {
  446. this.$element.find('.repeat-yearly input').removeAttr('checked').removeClass('checked');
  447. this.$element.find('.repeat-yearly label.radio-custom').removeClass('checked');
  448. if (recur.BYMONTHDAY) {
  449. temp = this.$element.find('.repeat-yearly-date');
  450. temp.find('input').addClass('checked').prop('checked', true);
  451. temp.find('label.radio-custom').addClass('checked');
  452. if (recur.BYMONTH) {
  453. temp.find('.year-month').selectlist('selectByValue', recur.BYMONTH);
  454. }
  455. temp.find('.year-month-day').selectlist('selectByValue', recur.BYMONTHDAY);
  456. } else if (recur.BYSETPOS) {
  457. temp = this.$element.find('.repeat-yearly-day');
  458. temp.find('input').addClass('checked').prop('checked', true);
  459. temp.find('label.radio-custom').addClass('checked');
  460. temp.find('.year-month-day-pos').selectlist('selectByValue', recur.BYSETPOS);
  461. if (recur.BYDAY) {
  462. temp.find('.year-month-days').selectlist('selectByValue', recur.BYDAY);
  463. }
  464. if (recur.BYMONTH) {
  465. temp.find('.year-month').selectlist('selectByValue', recur.BYMONTH);
  466. }
  467. }
  468. item = 'yearly';
  469. } else {
  470. item = 'none';
  471. }
  472. if (recur.COUNT) {
  473. this.$endAfter.spinbox('value', parseInt(recur.COUNT, 10));
  474. this.$endSelect.selectlist('selectByValue', 'after');
  475. } else if (recur.UNTIL) {
  476. temp = recur.UNTIL;
  477. if (temp.length === 8) {
  478. temp = temp.split('');
  479. temp.splice(4, 0, '-');
  480. temp.splice(7, 0, '-');
  481. temp = temp.join('');
  482. }
  483. var timeZone = this.$timeZone.selectlist('selectedItem');
  484. var timezoneOffset = (timeZone.offset === '+00:00') ? 'Z' : timeZone.offset;
  485. startDate = temp;
  486. var utcEndHours = this.setUtcTime(startDate, startTime, timezoneOffset);
  487. this.$endDate.datepicker('setDate', utcEndHours);
  488. this.$endSelect.selectlist('selectByValue', 'date');
  489. }
  490. this.endSelectChanged();
  491. if (recur.INTERVAL) {
  492. this.$repeatIntervalSpinbox.spinbox('value', parseInt(recur.INTERVAL, 10));
  493. }
  494. this.$repeatIntervalSelect.selectlist('selectByValue', item);
  495. this.repeatIntervalSelectChanged();
  496. }
  497. var utcStartHours = this.setUtcTime(startDate, startTime, timeOffset);
  498. this.$startDate.datepicker('setDate', utcStartHours);
  499. },
  500. toggleState: function (action) {
  501. this.$element.find('.combobox').combobox(action);
  502. this.$element.find('.datepicker').datepicker(action);
  503. this.$element.find('.selectlist').selectlist(action);
  504. this.$element.find('.spinbox').spinbox(action);
  505. this.$element.find('[type=radio]').radio(action);
  506. if (action === 'disable') {
  507. action = 'addClass';
  508. } else {
  509. action = 'removeClass';
  510. }
  511. this.$element.find('.repeat-days-of-the-week .btn-group')[action]('disabled');
  512. },
  513. value: function (options) {
  514. if (options) {
  515. return this.setValue(options);
  516. } else {
  517. return this.getValue();
  518. }
  519. }
  520. };
  521. // SCHEDULER PLUGIN DEFINITION
  522. $.fn.scheduler = function (option) {
  523. var args = Array.prototype.slice.call(arguments, 1);
  524. var methodReturn;
  525. var $set = this.each(function () {
  526. var $this = $(this);
  527. var data = $this.data('fu.scheduler');
  528. var options = typeof option === 'object' && option;
  529. if (!data) {
  530. $this.data('fu.scheduler', (data = new Scheduler(this, options)));
  531. }
  532. if (typeof option === 'string') {
  533. methodReturn = data[option].apply(data, args);
  534. }
  535. });
  536. return (methodReturn === undefined) ? $set : methodReturn;
  537. };
  538. $.fn.scheduler.defaults = {};
  539. $.fn.scheduler.Constructor = Scheduler;
  540. $.fn.scheduler.noConflict = function () {
  541. $.fn.scheduler = old;
  542. return this;
  543. };
  544. // DATA-API
  545. $(document).on('mousedown.fu.scheduler.data-api', '[data-initialize=scheduler]', function (e) {
  546. var $control = $(e.target).closest('.scheduler');
  547. if (!$control.data('fu.scheduler')) {
  548. $control.scheduler($control.data());
  549. }
  550. });
  551. // Must be domReady for AMD compatibility
  552. $(function () {
  553. $('[data-initialize=scheduler]').each(function () {
  554. var $this = $(this);
  555. if ($this.data('scheduler')) return;
  556. $this.scheduler($this.data());
  557. });
  558. });
  559. // -- BEGIN UMD WRAPPER AFTERWORD --
  560. }));
  561. // -- END UMD WRAPPER AFTERWORD --