angular-bootstrap-calendar.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. 'use strict';
  2. /**
  3. * @ngdoc overview
  4. * @name angularBootstrapCalendarApp
  5. * @description
  6. * # angularBootstrapCalendarApp
  7. *
  8. * Main module of the application.
  9. */
  10. angular
  11. .module('mwl.calendar', [
  12. 'ui.bootstrap'
  13. ]);
  14. 'use strict';
  15. /**
  16. * @ngdoc service
  17. * @name angularBootstrapCalendarApp.moment
  18. * @description
  19. * # moment
  20. * Constant in the angularBootstrapCalendarApp.
  21. */
  22. angular.module('mwl.calendar')
  23. .constant('moment', window.moment);
  24. 'use strict';
  25. /**
  26. * @ngdoc service
  27. * @name angularBootstrapCalendarApp.calendarHelper
  28. * @description
  29. * # calendarHelper
  30. * Service in the angularBootstrapCalendarApp.
  31. */
  32. angular.module('mwl.calendar')
  33. .service('calendarHelper', ["$filter", "moment", function calendarHelper($filter, moment) {
  34. var self = this;
  35. function isISOWeekBasedOnLocale() {
  36. return moment().startOf('week').day() === 1;
  37. }
  38. function isISOWeek(userValue) {
  39. //If a manual override has been set in the directive, use that
  40. if (angular.isDefined(userValue)) return userValue;
  41. //Otherwise fallback to the locale
  42. return isISOWeekBasedOnLocale();
  43. }
  44. this.getMonthNames = function(short) {
  45. var format = short ? 'MMM' : 'MMMM';
  46. var months = [];
  47. for (var i = 0; i <= 11; i++) {
  48. months.push($filter('date')(new Date(2014, i), format));
  49. }
  50. return months;
  51. };
  52. this.getWeekDayNames = function(short, useISOWeek) {
  53. var format = short ? 'EEE' : 'EEEE';
  54. var weekdays = [];
  55. var startDay = isISOWeek(useISOWeek) ? 22 : 21;
  56. for (var i = 0; i <= 6; i++) {
  57. weekdays.push($filter('date')(new Date(2014, 8, startDay + i), format));
  58. }
  59. return weekdays;
  60. };
  61. this.eventIsInPeriod = function(eventStart, eventEnd, periodStart, periodEnd) {
  62. return (
  63. moment(eventStart).isAfter(moment(periodStart)) &&
  64. moment(eventStart).isBefore(moment(periodEnd))
  65. ) || (
  66. moment(eventEnd).isAfter(moment(periodStart)) &&
  67. moment(eventEnd).isBefore(moment(periodEnd))
  68. ) || (
  69. moment(eventStart).isBefore(moment(periodStart)) &&
  70. moment(eventEnd).isAfter(moment(periodEnd))
  71. ) || (
  72. moment(eventStart).isSame(moment(periodStart))
  73. ) || (
  74. moment(eventEnd).isSame(moment(periodEnd))
  75. );
  76. };
  77. this.getYearView = function(events, currentDay) {
  78. var grid = [];
  79. var months = self.getMonthNames();
  80. for (var i = 0; i < 3; i++) {
  81. var row = [];
  82. for (var j = 0; j < 4; j++) {
  83. var monthIndex = 12 - months.length;
  84. var startPeriod = new Date(moment(currentDay).format('YYYY'), monthIndex, 1);
  85. var endPeriod = moment(startPeriod).add(1, 'month').subtract(1, 'second').toDate();
  86. row.push({
  87. label: months.shift(),
  88. monthIndex: monthIndex,
  89. isToday: moment(startPeriod).startOf('month').isSame(moment().startOf('month')),
  90. events: events.filter(function(event) {
  91. return self.eventIsInPeriod(event.starts_at, event.ends_at, startPeriod, endPeriod);
  92. }),
  93. date: moment(startPeriod).startOf('month')
  94. });
  95. }
  96. grid.push(row);
  97. }
  98. return grid;
  99. };
  100. this.getMonthView = function(events, currentDay, useISOWeek) {
  101. var dateOffset = isISOWeek(useISOWeek) ? 1 : 0;
  102. function getWeekDayIndex() {
  103. var day = startOfMonth.day() - dateOffset;
  104. if (day < 0) day = 6;
  105. return day;
  106. }
  107. var startOfMonth = moment(currentDay).startOf('month');
  108. var numberOfDaysInMonth = moment(currentDay).endOf('month').date();
  109. var grid = [];
  110. var buildRow = new Array(7);
  111. var eventsWithIds = events.map(function(event, index) {
  112. event.$id = index;
  113. return event;
  114. });
  115. for (var i = 1; i <= numberOfDaysInMonth; i++) {
  116. if (i == 1) {
  117. var weekdayIndex = getWeekDayIndex(startOfMonth);
  118. var prefillMonth = startOfMonth.clone();
  119. while (weekdayIndex > 0) {
  120. weekdayIndex--;
  121. prefillMonth = prefillMonth.subtract(1, 'day');
  122. buildRow[weekdayIndex] = {
  123. label: prefillMonth.date(),
  124. date: prefillMonth.clone(),
  125. inMonth: false,
  126. events: []
  127. };
  128. }
  129. }
  130. buildRow[getWeekDayIndex(startOfMonth)] = {
  131. label: startOfMonth.date(),
  132. inMonth: true,
  133. isToday: moment().startOf('day').isSame(startOfMonth),
  134. date: startOfMonth.clone(),
  135. events: eventsWithIds.filter(function(event) {
  136. return self.eventIsInPeriod(event.starts_at, event.ends_at, startOfMonth.clone().startOf('day'), startOfMonth.clone().endOf('day'));
  137. })
  138. };
  139. if (i == numberOfDaysInMonth) {
  140. var weekdayIndex = getWeekDayIndex(startOfMonth);
  141. var postfillMonth = startOfMonth.clone();
  142. while (weekdayIndex < 6) {
  143. weekdayIndex++;
  144. postfillMonth = postfillMonth.add(1, 'day');
  145. buildRow[weekdayIndex] = {
  146. label: postfillMonth.date(),
  147. date: postfillMonth.clone(),
  148. inMonth: false,
  149. events: []
  150. };
  151. }
  152. }
  153. if (getWeekDayIndex(startOfMonth) === 6 || i == numberOfDaysInMonth) {
  154. grid.push(buildRow);
  155. buildRow = new Array(7);
  156. }
  157. startOfMonth = startOfMonth.add(1, 'day');
  158. }
  159. return grid;
  160. };
  161. this.getWeekView = function(events, currentDay, useISOWeek) {
  162. var dateOffset = isISOWeek(useISOWeek) ? 1 : 0;
  163. var columns = new Array(7);
  164. var weekDays = self.getWeekDayNames(false, useISOWeek);
  165. var currentWeekDayIndex = currentDay.getDay();
  166. var beginningOfWeek, endOfWeek;
  167. for (var i = currentWeekDayIndex; i >= 0; i--) {
  168. var date = moment(currentDay).subtract(currentWeekDayIndex - i, 'days').add(dateOffset, 'day').toDate();
  169. columns[i] = {
  170. weekDay: weekDays[i],
  171. day: $filter('date')(date, 'd'),
  172. date: $filter('date')(date, 'd MMM'),
  173. isToday: moment(date).startOf('day').isSame(moment().startOf('day'))
  174. };
  175. if (i == 0) {
  176. beginningOfWeek = date;
  177. } else if (i == 6) {
  178. endOfWeek = date;
  179. }
  180. }
  181. for (var i = currentWeekDayIndex + 1; i < 7; i++) {
  182. var date = moment(currentDay).add(i - currentWeekDayIndex, 'days').add(dateOffset, 'day').toDate();
  183. columns[i] = {
  184. weekDay: weekDays[i],
  185. day: $filter('date')(date, 'd'),
  186. date: $filter('date')(date, 'd MMM'),
  187. isToday: moment(date).startOf('day').isSame(moment().startOf('day'))
  188. };
  189. if (i == 0) {
  190. beginningOfWeek = date;
  191. } else if (i == 6) {
  192. endOfWeek = date;
  193. }
  194. }
  195. endOfWeek = moment(endOfWeek).endOf('day').toDate();
  196. beginningOfWeek = moment(beginningOfWeek).startOf('day').toDate();
  197. var eventsSorted = events.filter(function(event) {
  198. return self.eventIsInPeriod(event.starts_at, event.ends_at, beginningOfWeek, endOfWeek);
  199. }).map(function(event) {
  200. var eventStart = moment(event.starts_at).startOf('day');
  201. var eventEnd = moment(event.ends_at).startOf('day');
  202. var weekViewStart = moment(beginningOfWeek).startOf('day');
  203. var weekViewEnd = moment(endOfWeek).startOf('day');
  204. var offset, span;
  205. if (eventStart.isBefore(weekViewStart) || eventStart.isSame(weekViewStart)) {
  206. offset = 0;
  207. } else {
  208. offset = eventStart.diff(weekViewStart, 'days');
  209. }
  210. if (eventEnd.isAfter(weekViewEnd)) {
  211. eventEnd = weekViewEnd;
  212. }
  213. if (eventStart.isBefore(weekViewStart)) {
  214. eventStart = weekViewStart;
  215. }
  216. span = moment(eventEnd).diff(eventStart, 'days') + 1;
  217. event.daySpan = span;
  218. event.dayOffset = offset;
  219. return event;
  220. });
  221. return {columns: columns, events: eventsSorted};
  222. };
  223. this.getDayView = function(events, currentDay, dayStartHour, dayEndHour) {
  224. var calendarStart = moment(currentDay).startOf('day').add(dayStartHour, 'hours');
  225. var calendarEnd = moment(currentDay).startOf('day').add(dayEndHour, 'hours');
  226. var calendarHeight = (dayEndHour - dayStartHour + 1) * 60;
  227. var buckets = [];
  228. return events.filter(function(event) {
  229. return self.eventIsInPeriod(event.starts_at, event.ends_at, moment(currentDay).startOf('day').toDate(), moment(currentDay).endOf('day').toDate());
  230. }).map(function(event) {
  231. if (moment(event.starts_at).isBefore(calendarStart)) {
  232. event.top = 0;
  233. } else {
  234. event.top = moment(event.starts_at).startOf('minute').diff(calendarStart.startOf('minute'), 'minutes') - 2;
  235. }
  236. if (moment(event.ends_at).isAfter(calendarEnd)) {
  237. event.height = calendarHeight - event.top;
  238. } else {
  239. var diffStart = event.starts_at;
  240. if (moment(event.starts_at).isBefore(calendarStart)) {
  241. diffStart = calendarStart.toDate();
  242. }
  243. event.height = moment(event.ends_at).diff(diffStart, 'minutes');
  244. }
  245. if (event.top - event.height > calendarHeight) {
  246. event.height = 0;
  247. }
  248. event.left = 0;
  249. return event;
  250. }).filter(function(event) {
  251. return event.height > 0;
  252. }).map(function(event) {
  253. var cannotFitInABucket = true;
  254. buckets.forEach(function(bucket, bucketIndex) {
  255. var canFitInThisBucket = true;
  256. bucket.forEach(function(bucketItem) {
  257. if (self.eventIsInPeriod(event.starts_at, event.ends_at, bucketItem.starts_at, bucketItem.ends_at) || self.eventIsInPeriod(bucketItem.starts_at, bucketItem.ends_at, event.starts_at, event.ends_at)) {
  258. canFitInThisBucket = false;
  259. }
  260. });
  261. if (canFitInThisBucket && cannotFitInABucket) {
  262. cannotFitInABucket = false;
  263. event.left = bucketIndex * 150;
  264. buckets[bucketIndex].push(event);
  265. }
  266. });
  267. if (cannotFitInABucket) {
  268. event.left = buckets.length * 150;
  269. buckets.push([event]);
  270. }
  271. return event;
  272. });
  273. };
  274. this.toggleEventBreakdown = function(view, rowIndex, cellIndex) {
  275. var openEvents = [];
  276. function closeAllOpenItems() {
  277. view = view.map(function(row) {
  278. row.isOpened = false;
  279. return row.map(function(cell) {
  280. cell.isOpened = false;
  281. return cell;
  282. });
  283. });
  284. }
  285. if (view[rowIndex][cellIndex].events.length > 0) {
  286. var isCellOpened = view[rowIndex][cellIndex].isOpened;
  287. closeAllOpenItems();
  288. view[rowIndex][cellIndex].isOpened = !isCellOpened;
  289. view[rowIndex].isOpened = !isCellOpened;
  290. openEvents = view[rowIndex][cellIndex].events;
  291. } else {
  292. closeAllOpenItems();
  293. }
  294. return {view: view, openEvents: openEvents};
  295. };
  296. }]);
  297. 'use strict';
  298. angular.module('mwl.calendar')
  299. .filter('truncateEventTitle', function() {
  300. return function(string, length, boxHeight) {
  301. if (!string) return '';
  302. //Only truncate if if actually needs truncating
  303. if (string.length >= length && string.length / 20 > boxHeight / 30) {
  304. return string.substr(0, length) + '...';
  305. } else {
  306. return string;
  307. }
  308. };
  309. });
  310. 'use strict';
  311. /**
  312. * @ngdoc directive
  313. * @name angularBootstrapCalendarApp.directive:mwlCalendarYear
  314. * @description
  315. * # mwlCalendarYear
  316. */
  317. angular.module('mwl.calendar')
  318. .directive('mwlCalendarYear', ["$sce", "$timeout", "calendarHelper", "moment", function($sce, $timeout, calendarHelper, moment) {
  319. return {
  320. templateUrl: 'templates/year.html',
  321. restrict: 'EA',
  322. require: '^mwlCalendar',
  323. scope: {
  324. events: '=calendarEvents',
  325. currentDay: '=calendarCurrentDay',
  326. eventClick: '=calendarEventClick',
  327. eventEditClick: '=calendarEditEventClick',
  328. eventDeleteClick: '=calendarDeleteEventClick',
  329. editEventHtml: '=calendarEditEventHtml',
  330. deleteEventHtml: '=calendarDeleteEventHtml',
  331. autoOpen: '=calendarAutoOpen',
  332. timespanClick: '=calendarTimespanClick'
  333. },
  334. link: function postLink(scope, element, attrs, calendarCtrl) {
  335. var firstRun = false;
  336. scope.$sce = $sce;
  337. calendarCtrl.titleFunctions.year = function(currentDay) {
  338. return moment(currentDay).format('YYYY');
  339. };
  340. function updateView() {
  341. scope.view = calendarHelper.getYearView(scope.events, scope.currentDay);
  342. //Auto open the calendar to the current day if set
  343. if (scope.autoOpen && !firstRun) {
  344. scope.view.forEach(function(row, rowIndex) {
  345. row.forEach(function(year, cellIndex) {
  346. if (year.label == moment(scope.currentDay).format('MMMM')) {
  347. scope.monthClicked(rowIndex, cellIndex, true);
  348. $timeout(function() {
  349. firstRun = false;
  350. });
  351. }
  352. });
  353. });
  354. }
  355. }
  356. scope.$watch('currentDay', updateView);
  357. scope.$watch('events', updateView, true);
  358. scope.monthClicked = function(yearIndex, monthIndex, firstRun) {
  359. if (!firstRun) {
  360. scope.timespanClick({$date: scope.view[yearIndex][monthIndex].date.startOf('month').toDate()});
  361. }
  362. var handler = calendarHelper.toggleEventBreakdown(scope.view, yearIndex, monthIndex);
  363. scope.view = handler.view;
  364. scope.openEvents = handler.openEvents;
  365. };
  366. scope.drillDown = function(month) {
  367. calendarCtrl.changeView('month', moment(scope.currentDay).clone().month(month).toDate());
  368. };
  369. }
  370. };
  371. }]);
  372. 'use strict';
  373. /**
  374. * @ngdoc directive
  375. * @name angularBootstrapCalendarApp.directive:mwlCalendarWeek
  376. * @description
  377. * # mwlCalendarWeek
  378. */
  379. angular.module('mwl.calendar')
  380. .directive('mwlCalendarWeek', ["moment", "calendarHelper", function(moment, calendarHelper) {
  381. return {
  382. templateUrl: 'templates/week.html',
  383. restrict: 'EA',
  384. require: '^mwlCalendar',
  385. scope: {
  386. events: '=calendarEvents',
  387. currentDay: '=calendarCurrentDay',
  388. eventClick: '=calendarEventClick',
  389. useIsoWeek: '=calendarUseIsoWeek',
  390. weekTitleLabel: '@calendarWeekTitleLabel'
  391. },
  392. link: function postLink(scope, element, attrs, calendarCtrl) {
  393. var titleLabel = scope.weekTitleLabel || 'Week {week} of {year}';
  394. calendarCtrl.titleFunctions.week = function(currentDay) {
  395. return titleLabel.replace('{week}', moment(currentDay).week()).replace('{year}', moment(currentDay).format('YYYY'));
  396. };
  397. function updateView() {
  398. scope.view = calendarHelper.getWeekView(scope.events, scope.currentDay, scope.useIsoWeek);
  399. }
  400. scope.drillDown = function(day) {
  401. calendarCtrl.changeView('day', moment(scope.currentDay).clone().date(day).toDate());
  402. };
  403. scope.$watch('currentDay', updateView);
  404. scope.$watch('events', updateView, true);
  405. }
  406. };
  407. }]);
  408. 'use strict';
  409. /**
  410. * @ngdoc directive
  411. * @name angularBootstrapCalendarApp.directive:mwlCalendarMonth
  412. * @description
  413. * # mwlCalendarMonth
  414. */
  415. angular.module('mwl.calendar')
  416. .directive('mwlCalendarMonth', ["$sce", "$timeout", "$filter", "moment", "calendarHelper", function ($sce, $timeout, $filter, moment, calendarHelper) {
  417. return {
  418. templateUrl: 'templates/month.html',
  419. restrict: 'EA',
  420. require: '^mwlCalendar',
  421. scope: {
  422. events: '=calendarEvents',
  423. currentDay: '=calendarCurrentDay',
  424. eventClick: '=calendarEventClick',
  425. eventEditClick: '=calendarEditEventClick',
  426. eventDeleteClick: '=calendarDeleteEventClick',
  427. editEventHtml: '=calendarEditEventHtml',
  428. deleteEventHtml: '=calendarDeleteEventHtml',
  429. autoOpen: '=calendarAutoOpen',
  430. useIsoWeek: '=calendarUseIsoWeek',
  431. timespanClick: '=calendarTimespanClick'
  432. },
  433. link: function postLink(scope, element, attrs, calendarCtrl) {
  434. var firstRun = false;
  435. scope.$sce = $sce;
  436. calendarCtrl.titleFunctions.month = function(currentDay) {
  437. return $filter('date')(currentDay, 'MMMM yyyy');
  438. };
  439. function updateView() {
  440. scope.view = calendarHelper.getMonthView(scope.events, scope.currentDay, scope.useIsoWeek);
  441. //Auto open the calendar to the current day if set
  442. if (scope.autoOpen && !firstRun) {
  443. scope.view.forEach(function(week, rowIndex) {
  444. week.forEach(function(day, cellIndex) {
  445. if (day.inMonth && moment(scope.currentDay).startOf('day').isSame(day.date.startOf('day'))) {
  446. scope.dayClicked(rowIndex, cellIndex, true);
  447. $timeout(function() {
  448. firstRun = false;
  449. });
  450. }
  451. });
  452. });
  453. }
  454. }
  455. scope.$watch('currentDay', updateView);
  456. scope.$watch('events', updateView, true);
  457. scope.weekDays = calendarHelper.getWeekDayNames(false, scope.useIsoWeek);
  458. scope.dayClicked = function(rowIndex, cellIndex, firstRun) {
  459. if (!firstRun) {
  460. scope.timespanClick({$date: scope.view[rowIndex][cellIndex].date.startOf('day').toDate()});
  461. }
  462. var handler = calendarHelper.toggleEventBreakdown(scope.view, rowIndex, cellIndex);
  463. scope.view = handler.view;
  464. scope.openEvents = handler.openEvents;
  465. };
  466. scope.drillDown = function(day) {
  467. calendarCtrl.changeView('day', moment(scope.currentDay).clone().date(day).toDate());
  468. };
  469. scope.highlightEvent = function(event, shouldAddClass) {
  470. scope.view = scope.view.map(function(week) {
  471. week.isOpened = false;
  472. return week.map(function(day) {
  473. delete day.highlightClass;
  474. day.isOpened = false;
  475. if (shouldAddClass) {
  476. var dayContainsEvent = day.events.filter(function(e) {
  477. return e.$id == event.$id;
  478. }).length > 0;
  479. if (dayContainsEvent) {
  480. day.highlightClass = 'day-highlight dh-event-' + event.type;
  481. }
  482. }
  483. return day;
  484. });
  485. });
  486. };
  487. }
  488. };
  489. }]);
  490. 'use strict';
  491. /**
  492. * @ngdoc directive
  493. * @name angularBootstrapCalendarApp.directive:mwlCalendarDay
  494. * @description
  495. * # mwlCalendarDay
  496. */
  497. angular.module('mwl.calendar')
  498. .directive('mwlCalendarDay', ["$filter", "moment", "calendarHelper", function($filter, moment, calendarHelper) {
  499. return {
  500. templateUrl: 'templates/day.html',
  501. restrict: 'EA',
  502. require: '^mwlCalendar',
  503. scope: {
  504. events: '=calendarEvents',
  505. currentDay: '=calendarCurrentDay',
  506. eventClick: '=calendarEventClick',
  507. eventLabel: '@calendarEventLabel',
  508. timeLabel: '@calendarTimeLabel',
  509. dayViewStart:'@calendarDayViewStart',
  510. dayViewEnd:'@calendarDayViewEnd'
  511. },
  512. link: function postLink(scope, element, attrs, calendarCtrl) {
  513. var dayViewStart = moment(scope.dayViewStart || '00:00', 'HH:mm');
  514. var dayViewEnd = moment(scope.dayViewEnd || '23:00', 'HH:mm');
  515. scope.days = [];
  516. var dayCounter = moment(dayViewStart);
  517. for (var i = 0; i <= dayViewEnd.diff(dayViewStart, 'hours'); i++) {
  518. scope.days.push({
  519. label: dayCounter.format('ha')
  520. });
  521. dayCounter.add(1, 'hour');
  522. }
  523. calendarCtrl.titleFunctions.day = function(currentDay) {
  524. return $filter('date')(currentDay, 'EEEE d MMMM, yyyy');
  525. };
  526. function updateView() {
  527. scope.view = calendarHelper.getDayView(scope.events, scope.currentDay, dayViewStart.hours(), dayViewEnd.hours());
  528. }
  529. scope.$watch('currentDay', updateView);
  530. scope.$watch('events', updateView, true);
  531. }
  532. };
  533. }]);
  534. 'use strict';
  535. /**
  536. * @ngdoc directive
  537. * @name angularBootstrapCalendarApp.directive:mwlCalendar
  538. * @description
  539. * # mwlCalendar
  540. */
  541. angular.module('mwl.calendar')
  542. .directive('mwlCalendar', function () {
  543. return {
  544. templateUrl: 'templates/main.html',
  545. restrict: 'EA',
  546. scope: {
  547. events: '=calendarEvents',
  548. view: '=calendarView',
  549. currentDay: '=calendarCurrentDay',
  550. control: '=calendarControl',
  551. eventClick: '&calendarEventClick',
  552. eventEditClick: '&calendarEditEventClick',
  553. eventDeleteClick: '&calendarDeleteEventClick',
  554. editEventHtml: '=calendarEditEventHtml',
  555. deleteEventHtml: '=calendarDeleteEventHtml',
  556. autoOpen: '=calendarAutoOpen',
  557. useIsoWeek: '=calendarUseIsoWeek',
  558. eventLabel: '@calendarEventLabel',
  559. timeLabel: '@calendarTimeLabel',
  560. dayViewStart:'@calendarDayViewStart',
  561. dayViewEnd:'@calendarDayViewEnd',
  562. weekTitleLabel: '@calendarWeekTitleLabel',
  563. timespanClick: '&calendarTimespanClick'
  564. },
  565. controller: ["$scope", "$timeout", "$locale", "moment", function($scope, $timeout, $locale, moment) {
  566. var self = this;
  567. this.titleFunctions = {};
  568. this.changeView = function(view, newDay) {
  569. $scope.view = view;
  570. $scope.currentDay = newDay;
  571. };
  572. $scope.control = $scope.control || {};
  573. $scope.control.prev = function() {
  574. $scope.currentDay = moment($scope.currentDay).subtract(1, $scope.view).toDate();
  575. };
  576. $scope.control.next = function() {
  577. $scope.currentDay = moment($scope.currentDay).add(1, $scope.view).toDate();
  578. };
  579. $scope.control.getTitle = function() {
  580. if (!self.titleFunctions[$scope.view]) {
  581. return '';
  582. }
  583. return self.titleFunctions[$scope.view]($scope.currentDay);
  584. };
  585. //Auto update the calendar when the locale changes
  586. var firstRunWatcher = true;
  587. var unbindWatcher = $scope.$watch(function() {
  588. return moment.locale() + $locale.id;
  589. }, function() {
  590. if (firstRunWatcher) { //dont run the first time the calendar is initialised
  591. firstRunWatcher = false;
  592. return;
  593. }
  594. var originalView = angular.copy($scope.view);
  595. $scope.view = 'redraw';
  596. $timeout(function() { //bit of a hacky way to redraw the calendar, should be refactored at some point
  597. $scope.view = originalView;
  598. });
  599. });
  600. //Remove the watcher when the calendar is destroyed
  601. var unbindDestroyListener = $scope.$on('$destroy', function() {
  602. unbindDestroyListener();
  603. unbindWatcher();
  604. });
  605. }]
  606. };
  607. });