Created
August 16, 2016 12:28
-
-
Save georgehrke/182bb08b75afc4d5a729e9d552a19316 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From 7b0532958a8d862cc5139a11bba58001f2c5945a Mon Sep 17 00:00:00 2001 | |
From: Georg Ehrke <[email protected]> | |
Date: Sat, 13 Feb 2016 00:07:30 +0100 | |
Subject: [PATCH] add repeating events to editor | |
--- | |
css/eventdialog.css | 43 +- | |
js/.jshintrc | 1 + | |
js/app/controllers/calcontroller.js | 33 +- | |
.../controllers/eventspopovereditorcontroller.js | 2 + | |
.../controllers/eventssidebareditorcontroller.js | 295 +++++++++++--- | |
js/app/filters/daysfilter.js | 30 ++ | |
js/app/filters/hoursfilter.js | 30 ++ | |
js/app/filters/minutesfilter.js | 30 ++ | |
js/app/filters/monthsfilter.js | 30 ++ | |
js/app/filters/periodsfilter.js | 30 ++ | |
js/app/filters/secondsfilter.js | 30 ++ | |
js/app/filters/timesfilter.js | 30 ++ | |
js/app/filters/weeksfilter.js | 30 ++ | |
js/app/filters/yearsfilter.js | 30 ++ | |
js/app/service/localizationservice.js | 61 +++ | |
js/app/service/objectConverter.js | 38 +- | |
js/public/app.js | 451 ++++++++++++++++----- | |
templates/part.eventsrepeat.php | 134 +++++- | |
templates/part.eventssidebareditor.php | 4 + | |
19 files changed, 1110 insertions(+), 222 deletions(-) | |
create mode 100644 js/app/filters/daysfilter.js | |
create mode 100644 js/app/filters/hoursfilter.js | |
create mode 100644 js/app/filters/minutesfilter.js | |
create mode 100644 js/app/filters/monthsfilter.js | |
create mode 100644 js/app/filters/periodsfilter.js | |
create mode 100644 js/app/filters/secondsfilter.js | |
create mode 100644 js/app/filters/timesfilter.js | |
create mode 100644 js/app/filters/weeksfilter.js | |
create mode 100644 js/app/filters/yearsfilter.js | |
create mode 100644 js/app/service/localizationservice.js | |
diff --git a/css/eventdialog.css b/css/eventdialog.css | |
index b935c03..f4d3988 100644 | |
--- a/css/eventdialog.css | |
+++ b/css/eventdialog.css | |
@@ -178,7 +178,7 @@ button.delete:hover, button.delete:focus { | |
} | |
.advanced .pull-half { | |
- width: 48%; | |
+ width: 48% !important; | |
} | |
@@ -228,3 +228,44 @@ button.delete:hover, button.delete:focus { | |
.dropdown-menu li a:hover { | |
background: #eee; | |
} | |
+ | |
+.advanced--fieldset table { | |
+ width: 100%; | |
+} | |
+ | |
+.advanced--fieldset table td { | |
+ text-align: center; | |
+} | |
+ | |
+.advanced--fieldset table td.four-rows { | |
+ width: 25%; | |
+} | |
+ | |
+.advanced--fieldset table td.seven-rows { | |
+ width: 14%; | |
+} | |
+ | |
+.advanced--fieldset table label { | |
+ display: block; | |
+ width: 100%; | |
+ background-color: rgba(240,240,240,.9); | |
+ padding: 0.5em 0 0.5em 0; | |
+} | |
+ | |
+.repeat_checkboxtable_checkbox:checked + .repeat_checkboxtable_label { | |
+ background-color: rgba(190,190,190,.9); | |
+} | |
+ | |
+.advanced--fieldset table input { | |
+ display: none; | |
+} | |
+ | |
+.advanced--fieldset input[type="number"] { | |
+ width: 3em; | |
+} | |
+ | |
+.advanced--fieldset label.inline-label { | |
+ padding: 7px 6px 5px 0; | |
+ display: block; | |
+} | |
+ | |
diff --git a/js/.jshintrc b/js/.jshintrc | |
index dd19c68..3a98f4d 100644 | |
--- a/js/.jshintrc | |
+++ b/js/.jshintrc | |
@@ -34,6 +34,7 @@ | |
"inject": true, | |
"module": true, | |
"t": true, | |
+ "n": true, | |
"it": true, | |
"exports": true, | |
"escapeHTML": true, | |
diff --git a/js/app/controllers/calcontroller.js b/js/app/controllers/calcontroller.js | |
index e04e479..3a8faf2 100644 | |
--- a/js/app/controllers/calcontroller.js | |
+++ b/js/app/controllers/calcontroller.js | |
@@ -26,8 +26,8 @@ | |
* Description: The fullcalendar controller. | |
*/ | |
-app.controller('CalController', ['$scope', '$rootScope', '$window', 'CalendarService', 'VEventService', 'SettingsService', 'TimezoneService', 'VEvent', 'is', 'uiCalendarConfig', '$uibModal', | |
- function ($scope, $rootScope, $window, CalendarService, VEventService, SettingsService, TimezoneService, VEvent, is, uiCalendarConfig, $uibModal) { | |
+app.controller('CalController', ['$scope', '$rootScope', '$window', 'CalendarService', 'VEventService', 'SettingsService', 'TimezoneService', 'VEvent', 'is', 'uiCalendarConfig', '$uibModal', 'LocalizationService', | |
+ function ($scope, $rootScope, $window, CalendarService, VEventService, SettingsService, TimezoneService, VEvent, is, uiCalendarConfig, $uibModal, LocalizationService) { | |
'use strict'; | |
is.loading = true; | |
@@ -334,39 +334,20 @@ app.controller('CalController', ['$scope', '$rootScope', '$window', 'CalendarSer | |
/** | |
* Calendar UI Configuration. | |
*/ | |
- var i; | |
- | |
- var monthNames = []; | |
- var monthNamesShort = []; | |
- for (i = 0; i < 12; i++) { | |
- monthNames.push(moment.localeData().months(moment([0, i]), '')); | |
- monthNamesShort.push(moment.localeData().monthsShort(moment([0, i]), '')); | |
- } | |
- | |
- var dayNames = []; | |
- var dayNamesShort = []; | |
- var momentWeekHelper = moment().startOf('week'); | |
- momentWeekHelper.subtract(momentWeekHelper.format('d')); | |
- for (i = 0; i < 7; i++) { | |
- dayNames.push(moment.localeData().weekdays(momentWeekHelper)); | |
- dayNamesShort.push(moment.localeData().weekdaysShort(momentWeekHelper)); | |
- momentWeekHelper.add(1, 'days'); | |
- } | |
- | |
$scope.uiConfig = { | |
calendar: { | |
height: w.height() - angular.element('#header').height(), | |
editable: true, | |
selectable: true, | |
lang: moment.locale(), | |
- monthNames: monthNames, | |
- monthNamesShort: monthNamesShort, | |
- dayNames: dayNames, | |
- dayNamesShort: dayNamesShort, | |
+ monthNames: LocalizationService.monthNames(), | |
+ monthNamesShort: LocalizationService.shortMonthNames(), | |
+ dayNames: LocalizationService.weekdayNames(), | |
+ dayNamesShort: LocalizationService.shortWeekdayNames(), | |
timezone: $scope.defaulttimezone, | |
defaultView: angular.element('#fullcalendar').attr('data-defaultView'), | |
header: false, | |
- firstDay: moment().startOf('week').format('d'), | |
+ firstDay: LocalizationService.firstDayOfWeek(), | |
select: $scope.newEvent, | |
eventLimit: true, | |
eventClick: function(fcEvent, jsEvent, view) { | |
diff --git a/js/app/controllers/eventspopovereditorcontroller.js b/js/app/controllers/eventspopovereditorcontroller.js | |
index cccda92..d8a7512 100644 | |
--- a/js/app/controllers/eventspopovereditorcontroller.js | |
+++ b/js/app/controllers/eventspopovereditorcontroller.js | |
@@ -42,6 +42,8 @@ app.controller('EventsPopoverEditorController', ['$scope', 'TimezoneService', 'e | |
$scope.showTimezone = true; | |
} | |
+ console.log($scope.properties); | |
+ | |
$scope.close = function(action) { | |
$scope.properties.dtstart.value = moment(angular.element('#from').datepicker('getDate')); | |
$scope.properties.dtend.value = moment(angular.element('#to').datepicker('getDate')); | |
diff --git a/js/app/controllers/eventssidebareditorcontroller.js b/js/app/controllers/eventssidebareditorcontroller.js | |
index 09ab5a2..b5a1ba9 100644 | |
--- a/js/app/controllers/eventssidebareditorcontroller.js | |
+++ b/js/app/controllers/eventssidebareditorcontroller.js | |
@@ -26,8 +26,8 @@ | |
* Description: Takes care of anything inside the Events Modal. | |
*/ | |
-app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'AutoCompletionService', 'eventEditorHelper', '$window', '$uibModalInstance', 'vevent', 'recurrenceId', 'isNew', 'properties', 'emailAddress', | |
- function($scope, TimezoneService, AutoCompletionService, eventEditorHelper, $window, $uibModalInstance, vevent, recurrenceId, isNew, properties, emailAddress) { | |
+app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'AutoCompletionService', 'eventEditorHelper', '$window', '$uibModalInstance', 'LocalizationService', 'vevent', 'recurrenceId', 'isNew', 'properties', 'emailAddress', | |
+ function($scope, TimezoneService, AutoCompletionService, eventEditorHelper, $window, $uibModalInstance, LocalizationService, vevent, recurrenceId, isNew, properties, emailAddress) { | |
'use strict'; | |
$scope.properties = properties; | |
@@ -38,6 +38,9 @@ app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'A | |
$scope.selected = 1; | |
$scope.timezones = []; | |
$scope.emailAddress = emailAddress; | |
+ $scope.rruleUnsupported = false; | |
+ | |
+ console.log($scope.properties); | |
$scope.previousDtStartDate = null; | |
$scope.previousDtStartHour = null; | |
@@ -241,13 +244,106 @@ app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'A | |
$scope.previousDtStartMinute = angular.element('#advanced_fromtime').timepicker('getMinute'); | |
$scope.tabopener(1); | |
+ | |
+ if ($scope.properties.rrule.freq !== 'NONE') { | |
+ var partIds; | |
+ if (typeof $scope.properties.rrule.parameters !== 'undefined') { | |
+ partIds = Object.getOwnPropertyNames($scope.properties.rrule.parameters); | |
+ } else { | |
+ partIds = []; | |
+ } | |
+ | |
+ var unsupportedFREQs = ['SECONDLY', 'MINUTELY', 'HOURLY']; | |
+ if (unsupportedFREQs.indexOf($scope.properties.rrule.freq) !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ } | |
+ | |
+ var unsupportedParts = ['BYSECOND', 'BYMINUTE', 'BYHOUR', 'BYYEARDAY', 'BYWEEKNO']; | |
+ angular.forEach(unsupportedParts, function(unsupportedPart) { | |
+ if (partIds.indexOf(unsupportedPart) !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ } | |
+ }); | |
+ | |
+ if ($scope.rruleUnsupported) { | |
+ return; | |
+ } | |
+ | |
+ if (typeof $scope.properties.rrule.interval === 'number') { | |
+ $scope.repeat.interval = $scope.properties.rrule.interval; | |
+ } else { | |
+ $scope.repeat.interval = 1; | |
+ } | |
+ | |
+ $scope.repeat.freq = $scope.properties.rrule.freq; | |
+ if (partIds.length === 0 && $scope.repeat.interval === 1) { | |
+ $scope.repeat.simple = $scope.properties.rrule.freq; | |
+ } else { | |
+ $scope.repeat.simple = 'CUSTOM'; | |
+ | |
+ $scope._parseCustomRepeatRule(partIds); | |
+ } | |
+ } | |
}); | |
- $scope.tabs = [{ | |
- title: t('Calendar', 'Attendees'), value: 1 | |
- }, { | |
- title: t('Calendar', 'Reminders'), value: 2 | |
- }]; | |
+ $scope._parseCustomRepeatRule = function(partIds) { | |
+ if ($scope.repeat.freq === 'DAILY' && partIds.length > 0) { | |
+ $scope.rruleUnsupported = true; | |
+ } else if ($scope.repeat.freq === 'WEEKLY') { | |
+ if (partIds.length === 0) { | |
+ $scope.repeat.weekly.weekdays = { | |
+ SU: true, | |
+ MO: true, | |
+ TU: true, | |
+ WE: true, | |
+ TH: true, | |
+ FR: true, | |
+ SA: true | |
+ }; | |
+ } else if(partIds.length === 1 && partIds.indexOf('BYDAY') !== -1 || partIds.length === 2 && partIds.indexOf('BYDAY') !== -1 && partIds.indexOf('WKST') !== -1) { | |
+ angular.forEach($scope.properties.rrule.parameters.BYDAY, function (day) { | |
+ $scope.repeat.weekly.weekdays[day] = true; | |
+ }); | |
+ } else { | |
+ $scope.rruleUnsupported = true; | |
+ } | |
+ } else if ($scope.repeat.freq === 'MONTHLY') { | |
+ if (partIds.indexOf('BYMONTH') !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ return; | |
+ } | |
+ if (partIds.indexOf('BYDAY') !== -1 && partIds.indexOf('BYMONTHDAY') !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ return; | |
+ } | |
+ if (partIds.indexOf('BYDAY') === -1 && partIds.indexOf('BYSETPOS') !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ return; | |
+ } | |
+ | |
+ console.log(partIds); | |
+ | |
+ } else if ($scope.repeat.freq === 'YEARLY') { | |
+ if (partIds.indexOf('BYMONTHDAY') !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ return; | |
+ } | |
+ | |
+ if (partIds.indexOf('BYMONTH')) { | |
+ angular.forEach($scope.properties.rrule.parameters.BYMONTH, function (month) { | |
+ $scope.repeat.yearly.months[month] = true; | |
+ }); | |
+ | |
+ } | |
+ | |
+ } | |
+ }; | |
+ | |
+ $scope.tabs = [ | |
+ {title: t('Calendar', 'Attendees'), value: 1}, | |
+ {title: t('Calendar', 'Reminders'), value: 2}, | |
+ {title: t('Calendar', 'Repeating'), value: 3} | |
+ ]; | |
$scope.tabopener = function (val) { | |
$scope.selected = val; | |
@@ -274,74 +370,147 @@ app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'A | |
$scope.properties.location.value = item.label; | |
}; | |
- $scope.repeater = [ | |
- { val: 'doesnotrepeat' , displayname: t('Calendar', 'Does not repeat')}, | |
- { val: 'daily' , displayname: t('Calendar', 'Daily')}, | |
- { val: 'weekly' , displayname: t('Calendar', 'Weekly')}, | |
- { val: 'weekday' , displayname: t('Calendar', 'Every Weekday')}, | |
- { val: 'biweekly' , displayname: t('Calendar', 'Bi-weekly')}, | |
- { val: 'monthly' , displayname: t('Calendar', 'Monthly')}, | |
- { val: 'yearly' , displayname: t('Calendar', 'Yearly')}, | |
+ $scope.repeat = { | |
+ simple: 'NONE', | |
+ interval: 1, | |
+ freq: 'DAILY', | |
+ end: 'NEVER', | |
+ count: 1, | |
+ weekly: { | |
+ weekdays: {} | |
+ }, | |
+ monthly: { | |
+ monthdays: {}, | |
+ radio: 'on-days', | |
+ onthe_ordinal: 1, | |
+ onthe_day: 'DAY' | |
+ }, | |
+ yearly: { | |
+ months: {}, | |
+ onthe_ordinal: 1, | |
+ onthe_day: 'DAY' | |
+ }, | |
+ //We will not support all crazy RRULEs in the first version | |
+ //when we can't deal with the RRULE, we'll show a warning in the editor | |
+ //instead of breaking the RRULE | |
+ unsupported: false | |
+ }; | |
+ $scope.repeat_options_simple = [ | |
+ {val: 'NONE', displayname: t('Calendar', 'None')}, | |
+ {val: 'DAILY', displayname: t('Calendar', 'Every day')}, | |
+ {val: 'WEEKLY', displayname: t('Calendar', 'Every week')}, | |
+ {val: 'MONTHLY', displayname: t('Calendar', 'Every month')}, | |
+ {val: 'YEARLY', displayname: t('Calendar', 'Every year')}, | |
+ {val: 'CUSTOM', displayname: t('calendar', 'Custom')} | |
]; | |
- $scope.repeatmodel = $scope.repeater[0].val; | |
- $scope.ender = [ | |
- { val: 'never', displayname: t('Calendar','never')}, | |
- { val: 'count', displayname: t('Calendar','by occurances')}, | |
- { val: 'date', displayname: t('Calendar','by date')}, | |
+ // This is not localized on purpose, because we'll pipe it thru a filter | |
+ $scope.repeat_options = [ | |
+ {val: 'DAILY', displayname: 'days'}, | |
+ {val: 'WEEKLY', displayname: 'weeks'}, | |
+ {val: 'MONTHLY', displayname: 'months'}, | |
+ {val: 'YEARLY', displayname: 'years'} | |
]; | |
- $scope.monthdays = [ | |
- { val: 'monthday', displayname: t('Calendar','by monthday')}, | |
- { val: 'weekday', displayname: t('Calendar','by weekday')} | |
+ $scope.selected_repeat_end = 'NEVER'; | |
+ $scope.repeat_end = [ | |
+ {val: 'NEVER', displayname: t('Calendar', 'never')}, | |
+ {val: 'COUNT', displayname: t('Calendar', 'after')}, | |
+ {val: 'UNTIL', displayname: t('Calendar', 'on date')} | |
]; | |
- $scope.monthdaymodel = $scope.monthdays[0].val; | |
- $scope.years = [ | |
- { val: 'bydate', displayname: t('Calendar','by events date')}, | |
- { val: 'byyearday', displayname: t('Calendar','by yearday(s)')}, | |
- { val: 'byweekno', displayname: t('Calendar','by week no(s)')}, | |
- { val: 'bydaymonth', displayname: t('Calendar','by day and month')} | |
- ]; | |
+ $scope.repeat_weekdays = []; | |
+ $scope.repeat_short_weekdays = []; | |
+ var weekdayNames = LocalizationService.weekdayNames(); | |
+ var shortWeekdayNames = LocalizationService.shortWeekdayNames(); | |
+ var firstDayOfWeek = LocalizationService.firstDayOfWeek(); | |
+ var icalDays = ['SU', 'MO', 'TU', 'WE' , 'TH', 'FR', 'SA']; | |
+ for (var i=0; i < 7; i++) { | |
+ $scope.repeat_weekdays.push({ | |
+ val: icalDays[(i + firstDayOfWeek) % 7], | |
+ displayname: weekdayNames[(i + firstDayOfWeek) % 7] | |
+ }); | |
+ $scope.repeat_short_weekdays.push({ | |
+ val: icalDays[(i + firstDayOfWeek) % 7], | |
+ displayname: shortWeekdayNames[(i + firstDayOfWeek) % 7] | |
+ }); | |
+ } | |
+ | |
+ $scope.repeat_weekdays.push({ | |
+ val: 'DAY', | |
+ displayname: t('Calendar', 'day') | |
+ }); | |
+ $scope.repeat_weekdays.push({ | |
+ val: 'DAY_OF_WEEK', | |
+ displayname: t('Calendar', 'day of week') | |
+ }); | |
+ $scope.repeat_weekdays.push({ | |
+ val: 'DAY_OF_WEEKEND', | |
+ displayname: t('Calendar', 'day of weekend') | |
+ }); | |
- $scope.weeks = [ | |
- { val: 'mon', displayname: t('Calendar','Monday')}, | |
- { val: 'tue', displayname: t('Calendar','Tuesday')}, | |
- { val: 'wed', displayname: t('Calendar','Wednesday')}, | |
- { val: 'thu', displayname: t('Calendar','Thursday')}, | |
- { val: 'fri', displayname: t('Calendar','Friday')}, | |
- { val: 'sat', displayname: t('Calendar','Saturday')}, | |
- { val: 'sun', displayname: t('Calendar','Sunday')} | |
+ $scope.repeat_ordinal = [ | |
+ {val: 0, displayname: t('calendar', 'each')}, | |
+ {val: 1, displayname: t('calendar', 'first')}, | |
+ {val: 2, displayname: t('calendar', 'second')}, | |
+ {val: 3, displayname: t('calendar', 'third')}, | |
+ {val: 4, displayname: t('calendar', 'fourth')}, | |
+ {val: 5, displayname: t('calendar', 'fifth')}, | |
+ {val: -1, displayname: t('calendar', 'last')} | |
]; | |
- $scope.changerepeater = function (repeat) { | |
- if (repeat.val === 'monthly') { | |
- $scope.monthday = false; | |
- $scope.yearly = true; | |
- $scope.weekly = true; | |
- } else if (repeat.val === 'yearly') { | |
- $scope.yearly = false; | |
- $scope.monthday = true; | |
- $scope.weekly = true; | |
- } else if (repeat.val === 'weekly') { | |
- $scope.weekly = false; | |
- $scope.monthday = true; | |
- $scope.yearly = true; | |
- } else { | |
- $scope.weekly = true; | |
- $scope.monthday = true; | |
- $scope.yearly = true; | |
+ $scope.repeat_month_groups = []; | |
+ var shortMonthNames = LocalizationService.shortMonthNames(); | |
+ for (var j=0; j < 12; j++) { | |
+ var group = Math.floor(j/6); | |
+ var index = j % 6; | |
+ | |
+ $scope.repeat_month_groups[group] = $scope.repeat_month_groups[group] || []; | |
+ $scope.repeat_month_groups[group][index] = { | |
+ val: j + 1, | |
+ displayname: shortMonthNames[j] | |
+ }; | |
+ } | |
+ | |
+ $scope.repeat_keep_one_checkbox_active = function(group, key) { | |
+ var isTrue = false; | |
+ angular.forEach(group, function(value) { | |
+ if (value) { | |
+ isTrue = true; | |
+ } | |
+ }); | |
+ | |
+ if (!isTrue) { | |
+ group[key] = true; | |
} | |
}; | |
- // First Day Dropdown | |
- $scope.recurrenceSelect = [ | |
- { val: t('calendar', 'Daily'), id: '0' }, | |
- { val: t('calendar', 'Weekly'), id: '1' }, | |
- { val: t('calendar', 'Monthly'), id: '2' }, | |
- { val: t('calendar', 'Yearly'), id: '3' }, | |
- { val: t('calendar', 'Other'), id: '4' } | |
- ]; | |
+ $scope.repeat_did_prefill_already = { | |
+ DAILY: false, | |
+ WEEKLY: false, | |
+ MONTHLY: false, | |
+ YEARLY: false | |
+ }; | |
+ $scope.repeat_change_freq = function(freq) { | |
+ if ($scope.repeat_did_prefill_already[freq]) { | |
+ //Don't prefill more than once | |
+ return; | |
+ } | |
+ | |
+ $scope.repeat_did_prefill_already[freq] = true; | |
+ var date = angular.element('#advanced_from').datepicker('getDate'); | |
+ if (freq === 'WEEKLY') { | |
+ var days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; | |
+ $scope.repeat.weekly.weekdays[days[date.getDay()]] = true; | |
+ } else if (freq === 'MONTHLY') { | |
+ $scope.repeat.monthly.monthdays[date.getDate()] = true; | |
+ } else if (freq === 'YEARLY') { | |
+ $scope.repeat.yearly.months[date.getMonth() + 1] = true; | |
+ } | |
+ }; | |
+ | |
+ | |
+ | |
$scope.cutstats = [ | |
{ displayname: t('Calendar', 'Individual'), val : 'INDIVIDUAL' }, | |
diff --git a/js/app/filters/daysfilter.js b/js/app/filters/daysfilter.js | |
new file mode 100644 | |
index 0000000..7e85666 | |
--- /dev/null | |
+++ b/js/app/filters/daysfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('daysFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'day', 'days', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/hoursfilter.js b/js/app/filters/hoursfilter.js | |
new file mode 100644 | |
index 0000000..5a3bcb8 | |
--- /dev/null | |
+++ b/js/app/filters/hoursfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('hoursFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'hour', 'hours', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/minutesfilter.js b/js/app/filters/minutesfilter.js | |
new file mode 100644 | |
index 0000000..6354c3c | |
--- /dev/null | |
+++ b/js/app/filters/minutesfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('minutesFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'minute', 'minutes', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/monthsfilter.js b/js/app/filters/monthsfilter.js | |
new file mode 100644 | |
index 0000000..b6b8b61 | |
--- /dev/null | |
+++ b/js/app/filters/monthsfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('monthsFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'month', 'months', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/periodsfilter.js b/js/app/filters/periodsfilter.js | |
new file mode 100644 | |
index 0000000..51ce351 | |
--- /dev/null | |
+++ b/js/app/filters/periodsfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('periodsFilter', ['$filter', function($filter) { | |
+ 'use strict'; | |
+ | |
+ return function(label, count) { | |
+ return $filter(label + 'Filter')(count); | |
+ }; | |
+}]); | |
diff --git a/js/app/filters/secondsfilter.js b/js/app/filters/secondsfilter.js | |
new file mode 100644 | |
index 0000000..c9b94b4 | |
--- /dev/null | |
+++ b/js/app/filters/secondsfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('secondsFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'second', 'seconds', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/timesfilter.js b/js/app/filters/timesfilter.js | |
new file mode 100644 | |
index 0000000..f05047a | |
--- /dev/null | |
+++ b/js/app/filters/timesfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('timesFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'time', 'times', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/weeksfilter.js b/js/app/filters/weeksfilter.js | |
new file mode 100644 | |
index 0000000..88742d9 | |
--- /dev/null | |
+++ b/js/app/filters/weeksfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('weeksFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'week', 'weeks', count); | |
+ }; | |
+}); | |
diff --git a/js/app/filters/yearsfilter.js b/js/app/filters/yearsfilter.js | |
new file mode 100644 | |
index 0000000..ca62c5e | |
--- /dev/null | |
+++ b/js/app/filters/yearsfilter.js | |
@@ -0,0 +1,30 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.filter('yearsFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'year', 'years', count); | |
+ }; | |
+}); | |
diff --git a/js/app/service/localizationservice.js b/js/app/service/localizationservice.js | |
new file mode 100644 | |
index 0000000..ce618ad | |
--- /dev/null | |
+++ b/js/app/service/localizationservice.js | |
@@ -0,0 +1,61 @@ | |
+/** | |
+ * ownCloud - Calendar App | |
+ * | |
+ * @author Raghu Nayyar | |
+ * @author Georg Ehrke | |
+ * @copyright 2016 Raghu Nayyar <[email protected]> | |
+ * @copyright 2016 Georg Ehrke <[email protected]> | |
+ * | |
+ * This library is free software; you can redistribute it and/or | |
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE | |
+ * License as published by the Free Software Foundation; either | |
+ * version 3 of the License, or any later version. | |
+ * | |
+ * This library is distributed in the hope that it will be useful, | |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details. | |
+ * | |
+ * You should have received a copy of the GNU Affero General Public | |
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>. | |
+ * | |
+ */ | |
+ | |
+app.service('LocalizationService', function() { | |
+ 'use strict'; | |
+ | |
+ var monthNames = []; | |
+ var monthNamesShort = []; | |
+ for (var i = 0; i < 12; i++) { | |
+ monthNames.push(moment.localeData().months(moment([0, i]), '')); | |
+ monthNamesShort.push(moment.localeData().monthsShort(moment([0, i]), '')); | |
+ } | |
+ | |
+ var dayNames = []; | |
+ var dayNamesShort = []; | |
+ var momentWeekHelper = moment().startOf('week'); | |
+ momentWeekHelper.subtract(momentWeekHelper.format('d')); | |
+ for (var j = 0; j < 7; j++) { | |
+ dayNames.push(moment.localeData().weekdays(momentWeekHelper)); | |
+ dayNamesShort.push(moment.localeData().weekdaysShort(momentWeekHelper)); | |
+ momentWeekHelper.add(1, 'days'); | |
+ } | |
+ | |
+ return { | |
+ monthNames: function() { | |
+ return monthNames; | |
+ }, | |
+ shortMonthNames: function() { | |
+ return monthNamesShort; | |
+ }, | |
+ weekdayNames: function() { | |
+ return dayNames; | |
+ }, | |
+ shortWeekdayNames: function() { | |
+ return dayNamesShort; | |
+ }, | |
+ firstDayOfWeek: function() { | |
+ return parseInt(moment().startOf('week').format('d')); | |
+ } | |
+ }; | |
+}); | |
\ No newline at end of file | |
diff --git a/js/app/service/objectConverter.js b/js/app/service/objectConverter.js | |
index 9eba44f..93aed1c 100644 | |
--- a/js/app/service/objectConverter.js | |
+++ b/js/app/service/objectConverter.js | |
@@ -401,12 +401,27 @@ app.factory('objectConverter', function () { | |
}, | |
repeating: function(data, vevent) { | |
var iCalEvent = new ICAL.Event(vevent); | |
- | |
data.repeating = iCalEvent.isRecurring(); | |
- simpleParser.dates(data, vevent, 'rdate'); | |
- simpleParser.string(data, vevent, 'rrule'); | |
- simpleParser.dates(data, vevent, 'exdate'); | |
+ var rrule = vevent.getFirstPropertyValue('rrule'); | |
+ if (rrule) { | |
+ data.rrule = { | |
+ count: rrule.count, | |
+ freq: rrule.freq, | |
+ interval: rrule.interval, | |
+ parameters: rrule.parts, | |
+ until: null | |
+ }; | |
+ | |
+ // TODO - handle until properly | |
+ //if (rrule.until) { | |
+ // simpleParser.date(data.rrule, rrule, 'until'); | |
+ //} | |
+ } else { | |
+ data.rrule = { | |
+ freq: 'NONE' | |
+ }; | |
+ } | |
} | |
}; | |
@@ -514,16 +529,17 @@ app.factory('objectConverter', function () { | |
repeating: function(vevent, oldSimpleData, newSimpleData) { | |
// We won't support exrule, because it's deprecated and barely used in the wild | |
if (newSimpleData.repeating === false) { | |
- delete vevent.rdate; | |
- delete vevent.rrule; | |
- delete vevent.exdate; | |
+ vevent.removeAllProperties('rdate'); | |
+ vevent.removeAllProperties('rrule'); | |
+ vevent.removeAllProperties('exdate'); | |
return; | |
} | |
- simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'rdate'); | |
- simpleReader.string(vevent, oldSimpleData, newSimpleData, 'rrule'); | |
- simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'exdate'); | |
+ //TODO - parse rrule | |
+ //simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'rdate'); | |
+ //simpleReader.string(vevent, oldSimpleData, newSimpleData, 'rrule'); | |
+ //simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'exdate'); | |
} | |
}; | |
@@ -581,7 +597,7 @@ app.factory('objectConverter', function () { | |
parameters = simpleProperties[key].parameters; | |
if (oldSimpleData[key] !== newSimpleData[key]) { | |
if (newSimpleData === null) { | |
- delete vevent[key]; | |
+ vevent.removeAllProperties(key); | |
} else { | |
reader(vevent, oldSimpleData, newSimpleData, key, parameters); | |
} | |
diff --git a/js/public/app.js b/js/public/app.js | |
index 70dd455..a155222 100644 | |
--- a/js/public/app.js | |
+++ b/js/public/app.js | |
@@ -46,8 +46,8 @@ app.run(['$rootScope', '$window', | |
* Description: The fullcalendar controller. | |
*/ | |
-app.controller('CalController', ['$scope', '$rootScope', '$window', 'CalendarService', 'VEventService', 'SettingsService', 'TimezoneService', 'VEvent', 'is', 'uiCalendarConfig', '$uibModal', | |
- function ($scope, $rootScope, $window, CalendarService, VEventService, SettingsService, TimezoneService, VEvent, is, uiCalendarConfig, $uibModal) { | |
+app.controller('CalController', ['$scope', '$rootScope', '$window', 'CalendarService', 'VEventService', 'SettingsService', 'TimezoneService', 'VEvent', 'is', 'uiCalendarConfig', '$uibModal', 'LocalizationService', | |
+ function ($scope, $rootScope, $window, CalendarService, VEventService, SettingsService, TimezoneService, VEvent, is, uiCalendarConfig, $uibModal, LocalizationService) { | |
'use strict'; | |
is.loading = true; | |
@@ -354,39 +354,20 @@ app.controller('CalController', ['$scope', '$rootScope', '$window', 'CalendarSer | |
/** | |
* Calendar UI Configuration. | |
*/ | |
- var i; | |
- | |
- var monthNames = []; | |
- var monthNamesShort = []; | |
- for (i = 0; i < 12; i++) { | |
- monthNames.push(moment.localeData().months(moment([0, i]), '')); | |
- monthNamesShort.push(moment.localeData().monthsShort(moment([0, i]), '')); | |
- } | |
- | |
- var dayNames = []; | |
- var dayNamesShort = []; | |
- var momentWeekHelper = moment().startOf('week'); | |
- momentWeekHelper.subtract(momentWeekHelper.format('d')); | |
- for (i = 0; i < 7; i++) { | |
- dayNames.push(moment.localeData().weekdays(momentWeekHelper)); | |
- dayNamesShort.push(moment.localeData().weekdaysShort(momentWeekHelper)); | |
- momentWeekHelper.add(1, 'days'); | |
- } | |
- | |
$scope.uiConfig = { | |
calendar: { | |
height: w.height() - angular.element('#header').height(), | |
editable: true, | |
selectable: true, | |
lang: moment.locale(), | |
- monthNames: monthNames, | |
- monthNamesShort: monthNamesShort, | |
- dayNames: dayNames, | |
- dayNamesShort: dayNamesShort, | |
+ monthNames: LocalizationService.monthNames(), | |
+ monthNamesShort: LocalizationService.shortMonthNames(), | |
+ dayNames: LocalizationService.weekdayNames(), | |
+ dayNamesShort: LocalizationService.shortWeekdayNames(), | |
timezone: $scope.defaulttimezone, | |
defaultView: angular.element('#fullcalendar').attr('data-defaultView'), | |
header: false, | |
- firstDay: moment().startOf('week').format('d'), | |
+ firstDay: LocalizationService.firstDayOfWeek(), | |
select: $scope.newEvent, | |
eventLimit: true, | |
eventClick: function(fcEvent, jsEvent, view) { | |
@@ -834,6 +815,8 @@ app.controller('EventsPopoverEditorController', ['$scope', 'TimezoneService', 'e | |
$scope.showTimezone = true; | |
} | |
+ console.log($scope.properties); | |
+ | |
$scope.close = function(action) { | |
$scope.properties.dtstart.value = moment(angular.element('#from').datepicker('getDate')); | |
$scope.properties.dtend.value = moment(angular.element('#to').datepicker('getDate')); | |
@@ -973,8 +956,8 @@ app.controller('EventsPopoverEditorController', ['$scope', 'TimezoneService', 'e | |
* Description: Takes care of anything inside the Events Modal. | |
*/ | |
-app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'AutoCompletionService', 'eventEditorHelper', '$window', '$uibModalInstance', 'vevent', 'recurrenceId', 'isNew', 'properties', 'emailAddress', | |
- function($scope, TimezoneService, AutoCompletionService, eventEditorHelper, $window, $uibModalInstance, vevent, recurrenceId, isNew, properties, emailAddress) { | |
+app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'AutoCompletionService', 'eventEditorHelper', '$window', '$uibModalInstance', 'LocalizationService', 'vevent', 'recurrenceId', 'isNew', 'properties', 'emailAddress', | |
+ function($scope, TimezoneService, AutoCompletionService, eventEditorHelper, $window, $uibModalInstance, LocalizationService, vevent, recurrenceId, isNew, properties, emailAddress) { | |
'use strict'; | |
$scope.properties = properties; | |
@@ -985,6 +968,9 @@ app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'A | |
$scope.selected = 1; | |
$scope.timezones = []; | |
$scope.emailAddress = emailAddress; | |
+ $scope.rruleUnsupported = false; | |
+ | |
+ console.log($scope.properties); | |
$scope.previousDtStartDate = null; | |
$scope.previousDtStartHour = null; | |
@@ -1188,13 +1174,79 @@ app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'A | |
$scope.previousDtStartMinute = angular.element('#advanced_fromtime').timepicker('getMinute'); | |
$scope.tabopener(1); | |
+ | |
+ if ($scope.properties.rrule.freq !== 'NONE') { | |
+ var partIds; | |
+ if (typeof $scope.properties.rrule.parameters !== 'undefined') { | |
+ partIds = Object.getOwnPropertyNames($scope.properties.rrule.parameters); | |
+ } else { | |
+ partIds = []; | |
+ } | |
+ | |
+ var unsupportedFREQs = ['SECONDLY', 'MINUTELY', 'HOURLY']; | |
+ if (unsupportedFREQs.indexOf($scope.properties.rrule.freq) !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ } | |
+ | |
+ var unsupportedParts = ['BYSECOND', 'BYMINUTE', 'BYHOUR', 'BYYEARDAY', 'BYWEEKNO']; | |
+ angular.forEach(unsupportedParts, function(unsupportedPart) { | |
+ if (partIds.indexOf(unsupportedPart) !== -1) { | |
+ $scope.rruleUnsupported = true; | |
+ } | |
+ }); | |
+ | |
+ if ($scope.rruleUnsupported) { | |
+ return; | |
+ } | |
+ | |
+ if (typeof $scope.properties.rrule.interval === 'number') { | |
+ $scope.repeat.interval = $scope.properties.rrule.interval; | |
+ } else { | |
+ $scope.repeat.interval = 1; | |
+ } | |
+ | |
+ $scope.repeat.freq = $scope.properties.rrule.freq; | |
+ if (partIds.length === 0 && $scope.repeat.interval === 1) { | |
+ $scope.repeat.simple = $scope.properties.rrule.freq; | |
+ } else { | |
+ $scope.repeat.simple = 'CUSTOM'; | |
+ | |
+ if ($scope.repeat.freq === 'DAILY' && partIds.length > 0) { | |
+ $scope.rruleUnsupported = true; | |
+ } else if ($scope.repeat.freq === 'WEEKLY') { | |
+ if (partIds.length === 0) { | |
+ $scope.repeat.weekly.weekdays = { | |
+ SU: true, | |
+ MO: true, | |
+ TU: true, | |
+ WE: true, | |
+ TH: true, | |
+ FR: true, | |
+ SA: true | |
+ }; | |
+ } else if(partIds.length === 1 && partIds.indexOf('BYDAY') !== -1 || partIds.length === 2 && partIds.indexOf('BYDAY') !== -1 && partIds.indexOf('WKST') !== -1) { | |
+ angular.forEach($scope.properties.rrule.parameters.BYDAY, function (day) { | |
+ $scope.repeat.weekly.weekdays[day] = true; | |
+ }); | |
+ } else { | |
+ $scope.rruleUnsupported = true; | |
+ } | |
+ } else if ($scope.repeat.freq === 'MONTHLY') { | |
+ console.log(partIds); | |
+ | |
+ } else if ($scope.repeat.freq === 'YEARLY') { | |
+ console.log(partIds); | |
+ | |
+ } | |
+ } | |
+ } | |
}); | |
- $scope.tabs = [{ | |
- title: t('Calendar', 'Attendees'), value: 1 | |
- }, { | |
- title: t('Calendar', 'Reminders'), value: 2 | |
- }]; | |
+ $scope.tabs = [ | |
+ {title: t('Calendar', 'Attendees'), value: 1}, | |
+ {title: t('Calendar', 'Reminders'), value: 2}, | |
+ {title: t('Calendar', 'Repeating'), value: 3} | |
+ ]; | |
$scope.tabopener = function (val) { | |
$scope.selected = val; | |
@@ -1221,74 +1273,147 @@ app.controller('EventsSidebarEditorController', ['$scope', 'TimezoneService', 'A | |
$scope.properties.location.value = item.label; | |
}; | |
- $scope.repeater = [ | |
- { val: 'doesnotrepeat' , displayname: t('Calendar', 'Does not repeat')}, | |
- { val: 'daily' , displayname: t('Calendar', 'Daily')}, | |
- { val: 'weekly' , displayname: t('Calendar', 'Weekly')}, | |
- { val: 'weekday' , displayname: t('Calendar', 'Every Weekday')}, | |
- { val: 'biweekly' , displayname: t('Calendar', 'Bi-weekly')}, | |
- { val: 'monthly' , displayname: t('Calendar', 'Monthly')}, | |
- { val: 'yearly' , displayname: t('Calendar', 'Yearly')}, | |
+ $scope.repeat = { | |
+ simple: 'NONE', | |
+ interval: 1, | |
+ freq: 'DAILY', | |
+ end: 'NEVER', | |
+ count: 1, | |
+ weekly: { | |
+ weekdays: {} | |
+ }, | |
+ monthly: { | |
+ monthdays: {}, | |
+ radio: 'on-days', | |
+ onthe_ordinal: 1, | |
+ onthe_day: 'DAY' | |
+ }, | |
+ yearly: { | |
+ months: {}, | |
+ onthe_ordinal: 1, | |
+ onthe_day: 'DAY' | |
+ }, | |
+ //We will not support all crazy RRULEs in the first version | |
+ //when we can't deal with the RRULE, we'll show a warning in the editor | |
+ //instead of breaking the RRULE | |
+ unsupported: false | |
+ }; | |
+ $scope.repeat_options_simple = [ | |
+ {val: 'NONE', displayname: t('Calendar', 'None')}, | |
+ {val: 'DAILY', displayname: t('Calendar', 'Every day')}, | |
+ {val: 'WEEKLY', displayname: t('Calendar', 'Every week')}, | |
+ {val: 'MONTHLY', displayname: t('Calendar', 'Every month')}, | |
+ {val: 'YEARLY', displayname: t('Calendar', 'Every year')}, | |
+ {val: 'CUSTOM', displayname: t('calendar', 'Custom')} | |
]; | |
- $scope.repeatmodel = $scope.repeater[0].val; | |
- $scope.ender = [ | |
- { val: 'never', displayname: t('Calendar','never')}, | |
- { val: 'count', displayname: t('Calendar','by occurances')}, | |
- { val: 'date', displayname: t('Calendar','by date')}, | |
+ // This is not localized on purpose, because we'll pipe it thru a filter | |
+ $scope.repeat_options = [ | |
+ {val: 'DAILY', displayname: 'days'}, | |
+ {val: 'WEEKLY', displayname: 'weeks'}, | |
+ {val: 'MONTHLY', displayname: 'months'}, | |
+ {val: 'YEARLY', displayname: 'years'} | |
]; | |
- $scope.monthdays = [ | |
- { val: 'monthday', displayname: t('Calendar','by monthday')}, | |
- { val: 'weekday', displayname: t('Calendar','by weekday')} | |
+ $scope.selected_repeat_end = 'NEVER'; | |
+ $scope.repeat_end = [ | |
+ {val: 'NEVER', displayname: t('Calendar', 'never')}, | |
+ {val: 'COUNT', displayname: t('Calendar', 'after')}, | |
+ {val: 'UNTIL', displayname: t('Calendar', 'on date')} | |
]; | |
- $scope.monthdaymodel = $scope.monthdays[0].val; | |
- $scope.years = [ | |
- { val: 'bydate', displayname: t('Calendar','by events date')}, | |
- { val: 'byyearday', displayname: t('Calendar','by yearday(s)')}, | |
- { val: 'byweekno', displayname: t('Calendar','by week no(s)')}, | |
- { val: 'bydaymonth', displayname: t('Calendar','by day and month')} | |
- ]; | |
+ $scope.repeat_weekdays = []; | |
+ $scope.repeat_short_weekdays = []; | |
+ var weekdayNames = LocalizationService.weekdayNames(); | |
+ var shortWeekdayNames = LocalizationService.shortWeekdayNames(); | |
+ var firstDayOfWeek = LocalizationService.firstDayOfWeek(); | |
+ var icalDays = ['SU', 'MO', 'TU', 'WE' , 'TH', 'FR', 'SA']; | |
+ for (var i=0; i < 7; i++) { | |
+ $scope.repeat_weekdays.push({ | |
+ val: icalDays[(i + firstDayOfWeek) % 7], | |
+ displayname: weekdayNames[(i + firstDayOfWeek) % 7] | |
+ }); | |
+ $scope.repeat_short_weekdays.push({ | |
+ val: icalDays[(i + firstDayOfWeek) % 7], | |
+ displayname: shortWeekdayNames[(i + firstDayOfWeek) % 7] | |
+ }); | |
+ } | |
- $scope.weeks = [ | |
- { val: 'mon', displayname: t('Calendar','Monday')}, | |
- { val: 'tue', displayname: t('Calendar','Tuesday')}, | |
- { val: 'wed', displayname: t('Calendar','Wednesday')}, | |
- { val: 'thu', displayname: t('Calendar','Thursday')}, | |
- { val: 'fri', displayname: t('Calendar','Friday')}, | |
- { val: 'sat', displayname: t('Calendar','Saturday')}, | |
- { val: 'sun', displayname: t('Calendar','Sunday')} | |
+ $scope.repeat_weekdays.push({ | |
+ val: 'DAY', | |
+ displayname: t('Calendar', 'day') | |
+ }); | |
+ $scope.repeat_weekdays.push({ | |
+ val: 'DAY_OF_WEEK', | |
+ displayname: t('Calendar', 'day of week') | |
+ }); | |
+ $scope.repeat_weekdays.push({ | |
+ val: 'DAY_OF_WEEKEND', | |
+ displayname: t('Calendar', 'day of weekend') | |
+ }); | |
+ | |
+ $scope.repeat_ordinal = [ | |
+ {val: 0, displayname: t('calendar', 'each')}, | |
+ {val: 1, displayname: t('calendar', 'first')}, | |
+ {val: 2, displayname: t('calendar', 'second')}, | |
+ {val: 3, displayname: t('calendar', 'third')}, | |
+ {val: 4, displayname: t('calendar', 'fourth')}, | |
+ {val: 5, displayname: t('calendar', 'fifth')}, | |
+ {val: -1, displayname: t('calendar', 'last')} | |
]; | |
- $scope.changerepeater = function (repeat) { | |
- if (repeat.val === 'monthly') { | |
- $scope.monthday = false; | |
- $scope.yearly = true; | |
- $scope.weekly = true; | |
- } else if (repeat.val === 'yearly') { | |
- $scope.yearly = false; | |
- $scope.monthday = true; | |
- $scope.weekly = true; | |
- } else if (repeat.val === 'weekly') { | |
- $scope.weekly = false; | |
- $scope.monthday = true; | |
- $scope.yearly = true; | |
- } else { | |
- $scope.weekly = true; | |
- $scope.monthday = true; | |
- $scope.yearly = true; | |
+ $scope.repeat_month_groups = []; | |
+ var shortMonthNames = LocalizationService.shortMonthNames(); | |
+ for (var j=0; j < 12; j++) { | |
+ var group = Math.floor(j/6); | |
+ var index = j % 6; | |
+ | |
+ $scope.repeat_month_groups[group] = $scope.repeat_month_groups[group] || []; | |
+ $scope.repeat_month_groups[group][index] = { | |
+ val: j + 1, | |
+ displayname: shortMonthNames[j] | |
+ }; | |
+ } | |
+ | |
+ $scope.repeat_keep_one_checkbox_active = function(group, key) { | |
+ var isTrue = false; | |
+ angular.forEach(group, function(value) { | |
+ if (value) { | |
+ isTrue = true; | |
+ } | |
+ }); | |
+ | |
+ if (!isTrue) { | |
+ group[key] = true; | |
} | |
}; | |
- // First Day Dropdown | |
- $scope.recurrenceSelect = [ | |
- { val: t('calendar', 'Daily'), id: '0' }, | |
- { val: t('calendar', 'Weekly'), id: '1' }, | |
- { val: t('calendar', 'Monthly'), id: '2' }, | |
- { val: t('calendar', 'Yearly'), id: '3' }, | |
- { val: t('calendar', 'Other'), id: '4' } | |
- ]; | |
+ $scope.repeat_did_prefill_already = { | |
+ DAILY: false, | |
+ WEEKLY: false, | |
+ MONTHLY: false, | |
+ YEARLY: false | |
+ }; | |
+ $scope.repeat_change_freq = function(freq) { | |
+ if ($scope.repeat_did_prefill_already[freq]) { | |
+ //Don't prefill more than once | |
+ return; | |
+ } | |
+ | |
+ $scope.repeat_did_prefill_already[freq] = true; | |
+ var date = angular.element('#advanced_from').datepicker('getDate'); | |
+ if (freq === 'WEEKLY') { | |
+ var days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; | |
+ $scope.repeat.weekly.weekdays[days[date.getDay()]] = true; | |
+ } else if (freq === 'MONTHLY') { | |
+ $scope.repeat.monthly.monthdays[date.getDate()] = true; | |
+ } else if (freq === 'YEARLY') { | |
+ $scope.repeat.yearly.months[date.getMonth() + 1] = true; | |
+ } | |
+ }; | |
+ | |
+ | |
+ | |
$scope.cutstats = [ | |
{ displayname: t('Calendar', 'Individual'), val : 'INDIVIDUAL' }, | |
@@ -1961,6 +2086,22 @@ app.filter('datepickerFilter', | |
} | |
); | |
+app.filter('daysFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'day', 'days', count); | |
+ }; | |
+}); | |
+ | |
+app.filter('hoursFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'hour', 'hours', count); | |
+ }; | |
+}); | |
+ | |
app.filter('importCalendarFilter', | |
function () { | |
'use strict'; | |
@@ -2011,6 +2152,30 @@ app.filter('importErrorFilter', | |
} | |
); | |
+app.filter('minutesFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'minute', 'minutes', count); | |
+ }; | |
+}); | |
+ | |
+app.filter('monthsFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'month', 'months', count); | |
+ }; | |
+}); | |
+ | |
+app.filter('periodsFilter', ['$filter', function($filter) { | |
+ 'use strict'; | |
+ | |
+ return function(label, count) { | |
+ return $filter(label + 'Filter')(count); | |
+ }; | |
+}]); | |
+ | |
app.filter('simpleReminderDescription', function() { | |
'use strict'; | |
var actionMapper = { | |
@@ -2060,6 +2225,14 @@ app.filter('simpleReminderDescription', function() { | |
}; | |
}); | |
+app.filter('secondsFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'second', 'seconds', count); | |
+ }; | |
+}); | |
+ | |
app.filter('subscriptionFilter', | |
[ function () { | |
'use strict'; | |
@@ -2079,6 +2252,14 @@ app.filter('subscriptionFilter', | |
} | |
]); | |
+app.filter('timesFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'time', 'times', count); | |
+ }; | |
+}); | |
+ | |
app.filter('timezoneFilter', ['$filter', function($filter) { | |
'use strict'; | |
@@ -2108,6 +2289,22 @@ app.filter('timezoneWithoutContinentFilter', function() { | |
}; | |
}); | |
+app.filter('weeksFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'week', 'weeks', count); | |
+ }; | |
+}); | |
+ | |
+app.filter('yearsFilter', function() { | |
+ 'use strict'; | |
+ | |
+ return function(count) { | |
+ return n('calendar', 'year', 'years', count); | |
+ }; | |
+}); | |
+ | |
app.factory('Calendar', ['$rootScope', '$filter', 'VEventService', 'TimezoneService', 'RandomStringService', function($rootScope, $filter, VEventService, TimezoneService, RandomStringService) { | |
'use strict'; | |
@@ -3452,6 +3649,44 @@ app.factory('is', function () { | |
}; | |
}); | |
+app.service('LocalizationService', function() { | |
+ 'use strict'; | |
+ | |
+ var monthNames = []; | |
+ var monthNamesShort = []; | |
+ for (var i = 0; i < 12; i++) { | |
+ monthNames.push(moment.localeData().months(moment([0, i]), '')); | |
+ monthNamesShort.push(moment.localeData().monthsShort(moment([0, i]), '')); | |
+ } | |
+ | |
+ var dayNames = []; | |
+ var dayNamesShort = []; | |
+ var momentWeekHelper = moment().startOf('week'); | |
+ momentWeekHelper.subtract(momentWeekHelper.format('d')); | |
+ for (var j = 0; j < 7; j++) { | |
+ dayNames.push(moment.localeData().weekdays(momentWeekHelper)); | |
+ dayNamesShort.push(moment.localeData().weekdaysShort(momentWeekHelper)); | |
+ momentWeekHelper.add(1, 'days'); | |
+ } | |
+ | |
+ return { | |
+ monthNames: function() { | |
+ return monthNames; | |
+ }, | |
+ shortMonthNames: function() { | |
+ return monthNamesShort; | |
+ }, | |
+ weekdayNames: function() { | |
+ return dayNames; | |
+ }, | |
+ shortWeekdayNames: function() { | |
+ return dayNamesShort; | |
+ }, | |
+ firstDayOfWeek: function() { | |
+ return parseInt(moment().startOf('week').format('d')); | |
+ } | |
+ }; | |
+}); | |
app.factory('objectConverter', function () { | |
'use strict'; | |
@@ -3833,12 +4068,27 @@ app.factory('objectConverter', function () { | |
}, | |
repeating: function(data, vevent) { | |
var iCalEvent = new ICAL.Event(vevent); | |
- | |
data.repeating = iCalEvent.isRecurring(); | |
- simpleParser.dates(data, vevent, 'rdate'); | |
- simpleParser.string(data, vevent, 'rrule'); | |
- simpleParser.dates(data, vevent, 'exdate'); | |
+ var rrule = vevent.getFirstPropertyValue('rrule'); | |
+ if (rrule) { | |
+ data.rrule = { | |
+ count: rrule.count, | |
+ freq: rrule.freq, | |
+ interval: rrule.interval, | |
+ parameters: rrule.parts, | |
+ until: null | |
+ }; | |
+ | |
+ // TODO - handle until properly | |
+ //if (rrule.until) { | |
+ // simpleParser.date(data.rrule, rrule, 'until'); | |
+ //} | |
+ } else { | |
+ data.rrule = { | |
+ freq: 'NONE' | |
+ }; | |
+ } | |
} | |
}; | |
@@ -3946,16 +4196,17 @@ app.factory('objectConverter', function () { | |
repeating: function(vevent, oldSimpleData, newSimpleData) { | |
// We won't support exrule, because it's deprecated and barely used in the wild | |
if (newSimpleData.repeating === false) { | |
- delete vevent.rdate; | |
- delete vevent.rrule; | |
- delete vevent.exdate; | |
+ vevent.removeAllProperties('rdate'); | |
+ vevent.removeAllProperties('rrule'); | |
+ vevent.removeAllProperties('exdate'); | |
return; | |
} | |
- simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'rdate'); | |
- simpleReader.string(vevent, oldSimpleData, newSimpleData, 'rrule'); | |
- simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'exdate'); | |
+ //TODO - parse rrule | |
+ //simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'rdate'); | |
+ //simpleReader.string(vevent, oldSimpleData, newSimpleData, 'rrule'); | |
+ //simpleReader.dates(vevent, oldSimpleData, newSimpleData, 'exdate'); | |
} | |
}; | |
@@ -4013,7 +4264,7 @@ app.factory('objectConverter', function () { | |
parameters = simpleProperties[key].parameters; | |
if (oldSimpleData[key] !== newSimpleData[key]) { | |
if (newSimpleData === null) { | |
- delete vevent[key]; | |
+ vevent.removeAllProperties(key); | |
} else { | |
reader(vevent, oldSimpleData, newSimpleData, key, parameters); | |
} | |
diff --git a/templates/part.eventsrepeat.php b/templates/part.eventsrepeat.php | |
index 070db4d..09e1da8 100644 | |
--- a/templates/part.eventsrepeat.php | |
+++ b/templates/part.eventsrepeat.php | |
@@ -22,33 +22,125 @@ | |
* | |
*/ | |
?> | |
- | |
-<fieldset class="event-fieldset"> | |
- <label class="label"><?php p($l->t('Repeat'))?></label> | |
- <select ng-model="repeatmodel" ng-options="repeat as repeat.displayname for repeat in repeater" ng-change="changerepeater(repeatmodel)"> | |
- </select> | |
- <select ng-hide="monthday" ng-model="monthdaymodel" ng-options="day as day.displayname for day in monthdays" ng-change="changemonthday(monthdaymodel)"> | |
- </select> | |
- <select ng-hide="yearly" ng-model="yearmodel" ng-options="year as year.displayname for year in years" ng-change="changeyear(yearmodel)"> | |
- </select> | |
- <select ng-hide="weekly" ng-model="weekmodel" id="weeklyselect" ng-change="changeweek(weekmodel)" multiple="multiple" data-placeholder="yoll" title="yol"> | |
- <option ng-repeat="week in weeks" value="{{ week.val }}"> {{ week.displayname }}</option> | |
+<fieldset> | |
+ <select | |
+ id="frequency_select" | |
+ ng-options="repeat.val as repeat.displayname for repeat in repeat_options_simple" | |
+ ng-model="repeat.simple"> | |
</select> | |
</fieldset> | |
+<div ng-show="repeat.simple === 'CUSTOM'"> | |
+ <fieldset> | |
+ <label class="pull-left inline-label"><?php p($l->t('every')); ?></label> | |
+ <select | |
+ class="pull-half pull-right" | |
+ id="frequency_select" | |
+ ng-options="repeat_option.val as repeat_option.displayname | periodsFilter: repeat.interval for repeat_option in repeat_options" | |
+ ng-model="repeat.freq" | |
+ ng-change="repeat_change_freq(repeat.freq)"> | |
+ </select> | |
+ <input | |
+ class="pull-right" | |
+ type="number" | |
+ min="1" | |
+ ng-model="repeat.interval"> | |
+ <div class="clear-both"></div> | |
+ </fieldset> | |
+ <fieldset ng-show="repeat.freq === 'WEEKLY'"> | |
+ <label><?php p($l->t('on weekdays')); ?>:</label> | |
+ <table class="event-checkbox-table"> | |
+ <tr> | |
+ <td ng-repeat="weekday in repeat_short_weekdays" class="seven-rows"> | |
+ <input type="checkbox" id="repeat_weekdays_{{$index}}" class="repeat_checkboxtable_checkbox" value="{{ weekday.val }}" | |
+ ng-model="repeat.weekly.weekdays[weekday.val]" ng-change="repeat_keep_one_checkbox_active(repeat.weekly.weekdays, weekday.val)"> | |
+ <label for="repeat_weekdays_{{$index}}" class="repeat_checkboxtable_label"> | |
+ {{ weekday.displayname }} | |
+ </label> | |
+ </td> | |
+ </tr> | |
+ </table> | |
+ </fieldset> | |
+ <fieldset class="event-fieldset" ng-show="repeat.freq === 'MONTHLY'"> | |
+ <label><input type="radio" name="repeat_monthly_radio" value="on-days" ng-model="repeat.monthly.radio"><?php p($l->t('on days')); ?>:</label> | |
+ <div ng-show="repeat.monthly.radio === 'on-days'"> | |
+ <table class="event-checkbox-table"> | |
+ <tr ng-repeat="day_group in [[1,2,3,4,5,6,7], [8,9,10,11,12,13,14], [15,16,17,18,19,20,21], [22,23,24,25,26,27,28], [29,30,31]]"> | |
+ <td ng-repeat="day in day_group" class="seven-rows"> | |
+ <input type="checkbox" id="repeat_monthdays_{{day}}" class="repeat_checkboxtable_checkbox" value="{{ day }}" | |
+ ng-model="repeat.monthly.monthdays[day]" ng-change="repeat_keep_one_checkbox_active(repeat.monthly.monthdays, day)"> | |
+ <label for="repeat_monthdays_{{day}}" class="repeat_checkboxtable_label"> | |
+ {{ day }} | |
+ </label> | |
+ </td> | |
+ </tr> | |
+ </table> | |
+ </div> | |
+ <div class="clear-both"></div> | |
+ <label><input type="radio" name="repeat_monthly_radio" value="on-the" ng-model="repeat.monthly.radio"><?php p($l->t('on the')); ?>:</label> | |
+ <div class="clear-both"></div> | |
+ <div ng-show="repeat.monthly.radio === 'on-the'"> | |
+ <select | |
+ class="pull-half pull-left" | |
+ ng-options="repeat.val as repeat.displayname for repeat in repeat_ordinal" | |
+ ng-model="repeat.monthly.onthe_ordinal"> | |
+ </select> | |
+ <select | |
+ class="pull-half pull-right" | |
+ ng-options="repeat.val as repeat.displayname for repeat in repeat_weekdays" | |
+ ng-model="repeat.monthly.onthe_day"> | |
+ </select> | |
+ </div> | |
+ </fieldset> | |
-<fieldset class="event-fieldset"> | |
- <label class="label"><?php p($l->t('Interval'))?></label> | |
- <input type="number" min="1" max="1000" value="1" name="interval" ng-model="intervalmodel"> | |
-</fieldset> | |
- | |
+ <fieldset class="event-fieldset" ng-show="repeat.freq === 'YEARLY'"> | |
+ <table class="event-checkbox-table"> | |
+ <tr ng-repeat="month_group in repeat_month_groups"> | |
+ <td ng-repeat="month in month_group" class="seven-rows"> | |
+ <input type="checkbox" id="repeat_month_{{month.val}}" class="repeat_checkboxtable_checkbox" value="{{ month.val }}" | |
+ ng-model="repeat.yearly.months[month.val]" ng-change="repeat_keep_one_checkbox_active(repeat.yearly.months, month.val)"> | |
+ <label for="repeat_month_{{month.val}}" class="repeat_checkboxtable_label"> | |
+ {{ month.displayname }} | |
+ </label> | |
+ </td> | |
+ </tr> | |
+ </table> | |
+ <div class="clear-both"></div> | |
+ <label><input type="checkbox" ng-model="repeat.yearly.onthe_checkbox"><?php p($l->t('on the')); ?>:</label> | |
+ <div ng-show="repeat.yearly.onthe_checkbox"> | |
+ <select | |
+ class="pull-half pull-left" | |
+ ng-options="repeat.val as repeat.displayname for repeat in repeat_ordinal" | |
+ ng-model="repeat.yearly.onthe_ordinal"> | |
+ </select> | |
+ <select | |
+ class="pull-half pull-right" | |
+ ng-options="repeat.val as repeat.displayname for repeat in repeat_weekdays" | |
+ ng-model="repeat.yearly.onthe_day"> | |
+ </select> | |
+ </div> | |
+ </fieldset> | |
+</div> | |
-<fieldset class="event-fieldset"> | |
- <label class="label"><?php p($l->t('End'))?></label> | |
- <select> | |
- <option ng-repeat="end in ender" value="end.val" ng-model="end.val">{{ end.displayname }}</option> | |
- </select> | |
+<fieldset class="event-fieldset" ng-hide="repeat.simple === 'NONE'"> | |
+ <label class="pull-left inline-label"> | |
+ <?php p($l->t('end repeat ...')); ?> | |
+ </label> | |
+ <div class="pull-right pull-half"> | |
+ <select id="frequency_select" | |
+ ng-options="repeat.val as repeat.displayname for repeat in repeat_end" | |
+ ng-model="repeat.end"> | |
+ </select> | |
+ </div> | |
+ <div class="clear-both"></div> | |
+ <div class="pull-right pull-half" ng-show="repeat.end === 'COUNT'"> | |
+ <input type="number" min="1" ng-model="repeat.count"> | |
+ {{ repeat.count | timesFilter }} | |
+ </div> | |
+ <div class="pull-right pull-half" ng-show="repeat.end === 'UNTIL'"> | |
+ <input type="text"> | |
+ </div> | |
</fieldset> | |
diff --git a/templates/part.eventssidebareditor.php b/templates/part.eventssidebareditor.php | |
index b83dc07..7cdfa22 100644 | |
--- a/templates/part.eventssidebareditor.php | |
+++ b/templates/part.eventssidebareditor.php | |
@@ -72,6 +72,10 @@ class="advanced--input h2" | |
<fieldset ng-show="eventsalarmview" class="advanced--fieldset" ng-disabled="readOnly"> | |
<?php print_unescaped($this->inc('part.eventsalarms')); ?> | |
</fieldset> | |
+ | |
+ <fieldset ng-show="eventsrepeatview" class="advanced--fieldset"> | |
+ <?php print_unescaped($this->inc('part.eventsrepeat')); ?> | |
+ </fieldset> | |
</div> | |
<div class="advanced--button-area" ng-show="!readOnly"> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment