Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/tasks.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorraimund-schluessler <raimund.schluessler@googlemail.com>2014-05-06 22:12:03 +0400
committerraimund-schluessler <raimund.schluessler@googlemail.com>2014-05-06 22:12:03 +0400
commit6cdfb6cb6895d77fc08d62d2543c3c33a415281f (patch)
tree9cd42d795689b212c8b7f9e77aa97289f6dbf02a
parentb4d84ffdb830691bea1452eb94c67fa29bcb8478 (diff)
Set reminders of any type
-rw-r--r--css/style.css22
-rw-r--r--css/style.less24
-rw-r--r--img/sprites.svg74
-rw-r--r--js/app/controllers/detailscontroller.coffee85
-rw-r--r--js/app/filters/reminderDetails.coffee31
-rw-r--r--js/app/services/businesslayer/tasksbusinesslayer.coffee159
-rw-r--r--js/app/services/models/tasksmodel.coffee4
-rw-r--r--js/app/services/persistence.coffee9
-rw-r--r--js/public/app.js349
-rw-r--r--l10n/de.php18
-rw-r--r--lib/controller/taskscontroller.php51
-rw-r--r--lib/helper.php55
-rw-r--r--templates/main.php2
-rw-r--r--templates/part.details.php6
14 files changed, 785 insertions, 104 deletions
diff --git a/css/style.css b/css/style.css
index 109014ac..d7ad9958 100644
--- a/css/style.css
+++ b/css/style.css
@@ -816,6 +816,7 @@
padding: 9px 20px 9px 55px;
position: relative;
text-shadow: 0 1px 0 white;
+ border-top: none;
}
#task-details .body .section input {
-moz-box-sizing: border-box;
@@ -842,7 +843,8 @@
border-radius: 0px;
border: 1px solid #CCC;
padding: 0;
- width: 100px;
+ width: 98px;
+ margin: 0;
font-weight: normal;
}
#task-details .body .section .icon {
@@ -867,6 +869,14 @@
#task-details .body .section .icon.detail-start {
background-position: -220px -80px;
}
+#task-details .body .section .icon.detail-remindertype {
+ display: none;
+ left: 38px;
+ opacity: 0.4;
+}
+#task-details .body .section .icon.detail-remindertype:hover {
+ opacity: 0.8;
+}
#task-details .body .section .section-title {
color: #9FA2A6;
font-weight: bold;
@@ -904,6 +914,12 @@
#task-details .body .section.date .section-title.repeat {
margin-top: -2px;
}
+#task-details .body .section.editing .icon.detail-remindertype {
+ display: block;
+}
+#task-details .body .section .icon.detail-remindertype {
+ background-position: -260px -40px;
+}
#task-details .body .section.detail-reminder .section-description {
display: none;
font-size: 11px;
@@ -943,6 +959,10 @@ input.datepicker-input {
input.timepicker-input {
width: 80px;
}
+input.duration-input {
+ margin: 2px 0 0 0.3em;
+ width: 35px;
+}
.ui-widget-content {
background: none repeat scroll 0 0 #F9F9F9;
border-radius: 4px 4px 4px 4px;
diff --git a/css/style.less b/css/style.less
index d34814c1..d672bb7f 100644
--- a/css/style.less
+++ b/css/style.less
@@ -851,6 +851,7 @@
padding: 9px 20px 9px 55px;
position: relative;
text-shadow: 0 1px 0 white;
+ border-top:none;
input{
-moz-box-sizing: border-box;
background: none repeat scroll 0 0 white;
@@ -876,7 +877,8 @@
border-radius: 0px;
border: 1px solid #CCC;
padding:0;
- width: 100px;
+ width: 98px;
+ margin:0;
font-weight: normal;
}
.icon{
@@ -899,6 +901,14 @@
&.detail-date, &.detail-start {
background-position: -220px -80px;
}
+ &.detail-remindertype{
+ display: none;
+ left: 38px;
+ opacity: 0.4;
+ &:hover{
+ opacity: 0.8;
+ }
+ }
}
.section-title{
color: #9FA2A6;
@@ -941,6 +951,14 @@
}
}
}
+ &.editing{
+ .icon.detail-remindertype{
+ display: block;
+ }
+ }
+ .icon.detail-remindertype{
+ background-position: -260px -40px;
+ }
&.detail-reminder{
.section-description{
display: none;
@@ -992,6 +1010,10 @@ input.datepicker-input{
input.timepicker-input{
width: 80px;
}
+input.duration-input{
+ margin: 2px 0 0 0.3em;
+ width: 35px;
+}
.ui-widget-content{
color: #423E3E;
background: none repeat scroll 0 0 #F9F9F9;
diff --git a/img/sprites.svg b/img/sprites.svg
index 9251e93d..7cd220e4 100644
--- a/img/sprites.svg
+++ b/img/sprites.svg
@@ -1485,34 +1485,72 @@
<g>
<g>
<defs>
- <rect id="SVGID_205_" x="220" y="80" width="20" height="20"/>
+ <rect id="SVGID_205_" x="260" y="40" width="20" height="20"/>
</defs>
<clipPath id="SVGID_206_">
<use xlink:href="#SVGID_205_" overflow="visible"/>
</clipPath>
- <rect x="224.555" y="90.047" clip-path="url(#SVGID_206_)" fill="#FFFFFF" width="10.892" height="1.406"/>
- <rect x="224.555" y="92.485" clip-path="url(#SVGID_206_)" fill="#FFFFFF" width="10.892" height="1.406"/>
+ <polygon clip-path="url(#SVGID_206_)" fill="#737272" points="264.172,45.436 266.518,41.954 268.863,45.436 "/>
<g clip-path="url(#SVGID_206_)">
<defs>
- <rect id="SVGID_207_" x="220" y="80" width="20" height="20"/>
+ <rect id="SVGID_207_" x="260" y="40" width="20" height="20"/>
</defs>
<clipPath id="SVGID_208_">
<use xlink:href="#SVGID_207_" overflow="visible"/>
</clipPath>
- <path clip-path="url(#SVGID_208_)" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="8" d="M222.875,96.831
- c0,0.11,0.09,0.2,0.201,0.2h13.85c0.109,0,0.199-0.09,0.199-0.2V86.419c0-0.111-0.09-0.2-0.199-0.2h-13.85
- c-0.111,0-0.201,0.089-0.201,0.2V96.831z"/>
- <rect x="222.875" y="86.218" clip-path="url(#SVGID_208_)" fill="#FFFFFF" width="14.25" height="2.813"/>
- <rect x="225.095" y="83.531" clip-path="url(#SVGID_208_)" fill="#FFFFFF" width="1.11" height="2.438"/>
- <rect x="233.797" y="83.531" clip-path="url(#SVGID_208_)" fill="#FFFFFF" width="1.108" height="2.438"/>
- <path clip-path="url(#SVGID_208_)" fill="none" stroke="#B0B0B0" stroke-width="2" stroke-miterlimit="8" d="M222.875,95.737
- c0,0.11,0.09,0.2,0.201,0.2h13.85c0.109,0,0.199-0.09,0.199-0.2V85.325c0-0.111-0.09-0.2-0.199-0.2h-13.85
- c-0.111,0-0.201,0.089-0.201,0.2V95.737z"/>
- <rect x="222.875" y="85.124" clip-path="url(#SVGID_208_)" fill="#B0B0B0" width="14.25" height="2.813"/>
- <rect x="225.095" y="82.437" clip-path="url(#SVGID_208_)" fill="#B0B0B0" width="1.11" height="2.438"/>
- <rect x="233.797" y="82.437" clip-path="url(#SVGID_208_)" fill="#B0B0B0" width="1.108" height="2.438"/>
- <rect x="224.555" y="89.344" clip-path="url(#SVGID_208_)" fill="#B0B0B0" width="10.892" height="1.406"/>
- <rect x="224.555" y="91.781" clip-path="url(#SVGID_208_)" fill="#B0B0B0" width="10.892" height="1.406"/>
+ <polygon clip-path="url(#SVGID_208_)" fill="none" stroke="#727272" stroke-miterlimit="10" points="264.172,45.436
+ 266.518,41.954 268.863,45.436 "/>
+ </g>
+ <rect x="265.553" y="45.436" clip-path="url(#SVGID_206_)" fill="#737272" width="1.93" height="8"/>
+
+ <rect x="265.553" y="45.436" clip-path="url(#SVGID_206_)" fill="none" stroke="#727272" stroke-miterlimit="10" width="1.93" height="8"/>
+ <polygon clip-path="url(#SVGID_206_)" fill="#737272" points="275.828,54.564 273.482,58.046 271.137,54.564 "/>
+ <g clip-path="url(#SVGID_206_)">
+ <defs>
+ <rect id="SVGID_209_" x="260" y="40" width="20" height="20"/>
+ </defs>
+ <clipPath id="SVGID_210_">
+ <use xlink:href="#SVGID_209_" overflow="visible"/>
+ </clipPath>
+ <polygon clip-path="url(#SVGID_210_)" fill="none" stroke="#727272" stroke-miterlimit="10" points="275.828,54.564
+ 273.482,58.046 271.137,54.564 "/>
+ </g>
+ <rect x="272.518" y="46.564" clip-path="url(#SVGID_206_)" fill="#737272" width="1.93" height="8"/>
+
+ <rect x="272.518" y="46.564" clip-path="url(#SVGID_206_)" fill="none" stroke="#727272" stroke-miterlimit="10" width="1.93" height="8"/>
+ </g>
+</g>
+<g>
+ <g>
+ <defs>
+ <rect id="SVGID_211_" x="220" y="80" width="20" height="20"/>
+ </defs>
+ <clipPath id="SVGID_212_">
+ <use xlink:href="#SVGID_211_" overflow="visible"/>
+ </clipPath>
+ <rect x="224.555" y="90.047" clip-path="url(#SVGID_212_)" fill="#FFFFFF" width="10.891" height="1.406"/>
+ <rect x="224.555" y="92.485" clip-path="url(#SVGID_212_)" fill="#FFFFFF" width="10.891" height="1.406"/>
+ <g clip-path="url(#SVGID_212_)">
+ <defs>
+ <rect id="SVGID_213_" x="220" y="80" width="20" height="20"/>
+ </defs>
+ <clipPath id="SVGID_214_">
+ <use xlink:href="#SVGID_213_" overflow="visible"/>
+ </clipPath>
+ <path clip-path="url(#SVGID_214_)" fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="8" d="M222.875,96.831
+ c0,0.11,0.089,0.2,0.2,0.2h13.85c0.11,0,0.2-0.09,0.2-0.2V86.419c0-0.111-0.09-0.2-0.2-0.2h-13.85c-0.111,0-0.2,0.089-0.2,0.2
+ V96.831z"/>
+ <rect x="222.875" y="86.218" clip-path="url(#SVGID_214_)" fill="#FFFFFF" width="14.25" height="2.813"/>
+ <rect x="225.094" y="83.531" clip-path="url(#SVGID_214_)" fill="#FFFFFF" width="1.11" height="2.438"/>
+ <rect x="233.796" y="83.531" clip-path="url(#SVGID_214_)" fill="#FFFFFF" width="1.108" height="2.438"/>
+ <path clip-path="url(#SVGID_214_)" fill="none" stroke="#B0B0B0" stroke-width="2" stroke-miterlimit="8" d="M222.875,95.737
+ c0,0.11,0.089,0.2,0.2,0.2h13.85c0.11,0,0.2-0.09,0.2-0.2V85.325c0-0.111-0.09-0.2-0.2-0.2h-13.85c-0.111,0-0.2,0.089-0.2,0.2
+ V95.737z"/>
+ <rect x="222.875" y="85.124" clip-path="url(#SVGID_214_)" fill="#B0B0B0" width="14.25" height="2.813"/>
+ <rect x="225.094" y="82.437" clip-path="url(#SVGID_214_)" fill="#B0B0B0" width="1.11" height="2.438"/>
+ <rect x="233.796" y="82.437" clip-path="url(#SVGID_214_)" fill="#B0B0B0" width="1.108" height="2.438"/>
+ <rect x="224.555" y="89.344" clip-path="url(#SVGID_214_)" fill="#B0B0B0" width="10.891" height="1.406"/>
+ <rect x="224.555" y="91.781" clip-path="url(#SVGID_214_)" fill="#B0B0B0" width="10.891" height="1.406"/>
</g>
</g>
</g>
diff --git a/js/app/controllers/detailscontroller.coffee b/js/app/controllers/detailscontroller.coffee
index c8a4001d..c6ea4677 100644
--- a/js/app/controllers/detailscontroller.coffee
+++ b/js/app/controllers/detailscontroller.coffee
@@ -38,15 +38,57 @@ $timeout, $routeParams) ->
)
@_$scope.durations = [
- {name: t('tasks_enhanced','years'), abbr: 'y'},
- {name: t('tasks_enhanced','months'), abbr: 'm'},
- {name: t('tasks_enhanced','days'), abbr: 'd'},
- {name: t('tasks_enhanced','hours'), abbr: 'h'},
- {name: t('tasks_enhanced','minutes'), abbr: 'i'},
- {name: t('tasks_enhanced','seconds'), abbr: 's'}
+ {
+ name: t('tasks_enhanced','week'),
+ names: t('tasks_enhanced','weeks'),
+ id: 'week'},
+ {
+ name: t('tasks_enhanced','day'),
+ names: t('tasks_enhanced','days'),
+ id: 'day'},
+ {
+ name: t('tasks_enhanced','hour'),
+ names: t('tasks_enhanced','hours'),
+ id: 'hour'},
+ {
+ name: t('tasks_enhanced','minute'),
+ names: t('tasks_enhanced','minutes'),
+ id: 'minute'},
+ {
+ name: t('tasks_enhanced','second'),
+ names: t('tasks_enhanced','seconds'),
+ id: 'second'}
]
- @_$scope.duration = _$scope.durations[1]
+ @_$scope.params = (task) ->
+ params = [
+ {
+ name: t('tasks_enhanced','before beginning'),
+ invert: true
+ related:'START',
+ id: "10"},
+ {
+ name: t('tasks_enhanced','after beginning'),
+ invert: false
+ related:'START',
+ id: "00"},
+ {
+ name: t('tasks_enhanced','before end'),
+ invert: true
+ related:'END',
+ id: "11"},
+ {
+ name: t('tasks_enhanced','after end'),
+ invert: false
+ related:'END',
+ id: "01"}
+ ]
+ if task.due && task.start
+ return params
+ else if task.start
+ return params.slice(0,2)
+ else
+ return params.slice(2)
@_$scope.closeDetails = () ->
if _$scope.status.searchActive
@@ -54,7 +96,6 @@ $timeout, $routeParams) ->
else
_$location.path('/lists/'+_$scope.route.listID)
-
@_$scope.deleteTask = (taskID) ->
_$scope.closeDetails()
_$timeout(() ->
@@ -76,6 +117,7 @@ $timeout, $routeParams) ->
else
_$location.path('/lists/'+_$scope.route.listID +
'/tasks/' + _$scope.route.taskID + '/edit/duedate')
+ _tasksbusinesslayer.initDueDate(_$scope.route.taskID)
@_$scope.editStart = () ->
if _$scope.status.searchActive
@@ -84,6 +126,7 @@ $timeout, $routeParams) ->
else
_$location.path('/lists/'+_$scope.route.listID +
'/tasks/' + _$scope.route.taskID + '/edit/startdate')
+ _tasksbusinesslayer.initStartDate(_$scope.route.taskID)
@_$scope.editReminder = () ->
if _$scope.status.searchActive
@@ -92,6 +135,7 @@ $timeout, $routeParams) ->
else
_$location.path('/lists/'+_$scope.route.listID +
'/tasks/' + _$scope.route.taskID + '/edit/reminder')
+ _tasksbusinesslayer.initReminder(_$scope.route.taskID)
@_$scope.editNote = () ->
if _$scope.status.searchActive
@@ -182,23 +226,42 @@ $timeout, $routeParams) ->
moment(date,'HH:mm'),'time')
@_$scope.setreminderday = (date) ->
- _tasksbusinesslayer.setReminder(_$scope.route.taskID,
+ _tasksbusinesslayer.setReminderDate(_$scope.route.taskID,
moment(date,'MM/DD/YYYY'),'day')
@_$scope.setremindertime = (date) ->
- _tasksbusinesslayer.setReminder(_$scope.route.taskID,
+ _tasksbusinesslayer.setReminderDate(_$scope.route.taskID,
moment(date,'HH:mm'),'time')
@_$scope.reminderType = (task) ->
if !angular.isUndefined(task)
if task.reminder == null
- if moment(task.start, "YYYYMMDDTHHmmss").isValid()
+ if moment(task.start, "YYYYMMDDTHHmmss").isValid() ||
+ moment(task.due, "YYYYMMDDTHHmmss").isValid()
return 'DURATION'
else
return 'DATE-TIME'
else
return task.reminder.type
+ @_$scope.changeReminderType = (task) ->
+ _tasksbusinesslayer.checkReminderDate(task.id)
+ if @reminderType(task) == 'DURATION'
+ if task.reminder
+ task.reminder.type = 'DATE-TIME'
+ else
+ task.reminder = {type:'DATE-TIME'}
+ else
+ if task.reminder
+ task.reminder.type = 'DURATION'
+ else
+ task.reminder = {type:'DURATION'}
+ _tasksbusinesslayer.setReminder(task.id)
+
+
+ @_$scope.setReminderDuration = (taskID) ->
+ _tasksbusinesslayer.setReminder(_$scope.route.taskID)
+
return new DetailsController($scope, $window, TasksModel,
TasksBusinessLayer, $route, $location, $timeout, $routeParams)
] \ No newline at end of file
diff --git a/js/app/filters/reminderDetails.coffee b/js/app/filters/reminderDetails.coffee
index 346374e7..f649e785 100644
--- a/js/app/filters/reminderDetails.coffee
+++ b/js/app/filters/reminderDetails.coffee
@@ -25,15 +25,34 @@ angular.module('Tasks').filter 'reminderDetails', () ->
if reminder.type == 'DATE-TIME' &&
moment(reminder.date, "YYYYMMDDTHHmmss").isValid()
return moment(reminder.date, "YYYYMMDDTHHmmss").lang('reminder').calendar()
- else if reminder.type == 'DURATION'
+ else if reminder.type == 'DURATION' && reminder.duration
ds = t('tasks_enhanced', 'Remind me')
for token in scope.durations
- if reminder.duration[token.abbr]
- ds+=' '+reminder.duration[token.abbr]+' '+t('tasks_enhanced',token.name)
- if reminder.duration.invert
- ds+= ' '+t('tasks_enhanced','before')
+ if +reminder.duration[token.id]
+ time = 1
+ ds+=' '+reminder.duration[token.id]+' '
+ if +reminder.duration[token.id] == 1
+ ds+=token.name
+ else
+ ds+=token.names
+ if !time
+ if reminder.duration.params.related == 'END'
+ ds+= ' '+t('tasks_enhanced','at the end')
+ else
+ ds+= ' '+t('tasks_enhanced','at the beginning')
else
- ds+= ' '+t('tasks_enhanced','after')
+ if reminder.duration.params.invert
+ if reminder.duration.params.related == 'END'
+ ds+= ' '+t('tasks_enhanced','before end')
+ else
+ ds+= ' '+t('tasks_enhanced','before beginning')
+ else
+ if reminder.duration.params.related == 'END'
+ ds+= ' '+t('tasks_enhanced','after end')
+ else
+ ds+= ' '+t('tasks_enhanced','after beginning')
return ds
+ else
+ return t('tasks_enhanced', 'Remind me')
else
return t('tasks_enhanced', 'Remind me') \ No newline at end of file
diff --git a/js/app/services/businesslayer/tasksbusinesslayer.coffee b/js/app/services/businesslayer/tasksbusinesslayer.coffee
index a472c4fd..84b998b5 100644
--- a/js/app/services/businesslayer/tasksbusinesslayer.coffee
+++ b/js/app/services/businesslayer/tasksbusinesslayer.coffee
@@ -62,6 +62,11 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
@_$tasksmodel.removeById(taskID)
@_persistence.deleteTask(taskID)
+ initDueDate: (taskID) ->
+ due = moment(@_$tasksmodel.getById(taskID).due, "YYYYMMDDTHHmmss")
+ if !due.isValid()
+ @setDue(taskID, moment().startOf('hour').add('h',1),'time')
+
setDue: (taskID, date, type='day') ->
due = moment(@_$tasksmodel.getById(taskID).due, "YYYYMMDDTHHmmss")
if type=='day'
@@ -77,13 +82,23 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
else
return
@_$tasksmodel.setDueDate(taskID,due.format('YYYYMMDDTHHmmss'))
+ @checkReminderDate(taskID)
@_persistence.setDueDate(taskID,
if due.isValid() then due.unix() else false)
deleteDueDate: (taskID) ->
+ reminder = @_$tasksmodel.getById(taskID).reminder
+ if (reminder != null && reminder.type == 'DURATION' &&
+ reminder.duration.params.related == 'END')
+ @deleteReminderDate(taskID)
@_$tasksmodel.setDueDate(taskID, null)
@_persistence.setDueDate(taskID, false)
+ initStartDate: (taskID) ->
+ start = moment(@_$tasksmodel.getById(taskID).start, "YYYYMMDDTHHmmss")
+ if !start.isValid()
+ @setStart(taskID, moment().startOf('hour').add('h',1),'time')
+
setStart: (taskID, date, type='day') ->
start = moment(@_$tasksmodel.getById(taskID).start, "YYYYMMDDTHHmmss")
if type == 'day'
@@ -99,23 +114,59 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
else
return
@_$tasksmodel.setStartDate(taskID,start.format('YYYYMMDDTHHmmss'))
+ @checkReminderDate(taskID)
@_persistence.setStartDate(taskID,
if start.isValid() then start.unix() else false)
deleteStartDate: (taskID) ->
+ reminder = @_$tasksmodel.getById(taskID).reminder
+ if (reminder != null && reminder.type == 'DURATION' &&
+ reminder.duration.params.related == 'START')
+ @deleteReminderDate(taskID)
@_$tasksmodel.setStartDate(taskID, null)
@_persistence.setStartDate(taskID, false)
- setReminder: (taskID, date, type='day') ->
+ initReminder: (taskID) ->
+ if !@checkReminderDate(taskID)
+ task = @_$tasksmodel.getById(taskID)
+ task.reminder = {
+ type: 'DURATION',
+ action: 'DISPLAY',
+ duration: {
+ token: 'week',
+ week: 0,
+ day: 0,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ params: {
+ invert: true
+ }
+ }
+ }
+ if moment(task.start, "YYYYMMDDTHHmmss").isValid()
+ p = task.reminder.duration.params
+ p.related = 'START'
+ p.id = '10'
+ else if moment(task.due, "YYYYMMDDTHHmmss").isValid()
+ p = task.reminder.duration.params
+ p.related = 'END'
+ p.id = '11'
+ else
+ task.reminder.type = 'DATE-TIME'
+ task.reminder.date = moment().startOf('hour').add('h',1)
+ .format('YYYYMMDDTHHmmss')
+ @setReminder(taskID)
+
+ setReminderDate: (taskID, date, type='day') ->
reminder = @_$tasksmodel.getById(taskID).reminder
newreminder = {
type: 'DATE-TIME',
action: 'DISPLAY',
- duration: null,
- trigger: null
+ duration: null
}
if type == 'day'
- if !(angular.isUndefined(reminder) || reminder == null)
+ if (@checkReminderDate(taskID) || reminder == null)
reminderdate = moment(reminder.date, "YYYYMMDDTHHmmss")
newreminder.action = reminder.action
if (reminderdate.isValid() && reminder.type == 'DATE-TIME')
@@ -125,7 +176,7 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
else
reminderdate = date.add('h',12)
else if type == 'time'
- if !(angular.isUndefined(reminder) || reminder == null)
+ if (@checkReminderDate(taskID) || reminder == null)
reminderdate = moment(reminder.date, "YYYYMMDDTHHmmss")
newreminder.action = reminder.action
if (reminderdate.isValid() && reminder.type == 'DATE-TIME')
@@ -137,11 +188,105 @@ angular.module('Tasks').factory 'TasksBusinessLayer',
else
return
newreminder.date = reminderdate.format('YYYYMMDDTHHmmss')
- @_$tasksmodel.setReminderDate(taskID,newreminder)
+ @_$tasksmodel.setReminder(taskID,newreminder)
@_persistence.setReminder(taskID,newreminder)
+ setReminder: (taskID) ->
+ if @checkReminderDate(taskID)
+ reminder = @_$tasksmodel.getById(taskID).reminder
+ @_persistence.setReminder(taskID,reminder)
+
+ checkReminderDate: (taskID) ->
+ task = @_$tasksmodel.getById(taskID)
+ reminder = task.reminder
+ if(reminder != null && reminder.type == 'DURATION')
+ if !reminder.duration
+ return false
+ else if reminder.duration.params.related == 'START'
+ token = 'start'
+ else if reminder.duration.params.related == 'END'
+ token = 'due'
+ else
+ return false
+ date = moment(task[token], "YYYYMMDDTHHmmss")
+ duration = reminder.duration
+ d = {
+ w: duration.week,
+ d: duration.day,
+ h: duration.hour,
+ m: duration.minute,
+ s: duration.second
+ }
+ if duration.params.invert
+ date = date.subtract(d)
+ else
+ date = date.add(d)
+ task.reminder.date = date.format('YYYYMMDDTHHmmss')
+ else if(reminder != null && reminder.type == 'DATE-TIME')
+ duration = reminder.duration
+ date = moment(reminder.date, "YYYYMMDDTHHmmss")
+ if !date.isValid()
+ return false
+ if duration
+ if duration.params.related == 'START'
+ related = moment(task.start, "YYYYMMDDTHHmmss")
+ else
+ related = moment(task.due, "YYYYMMDDTHHmmss")
+ seg = @secondsToSegments(date.diff(related, 'seconds'))
+ duration.params.invert = seg.invert
+ duration.token = 'week'
+ duration.week = seg.week
+ duration.day = seg.day
+ duration.hour = seg.hour
+ duration.minute = seg.minute
+ duration.second = seg.second
+ else
+ if task.start
+ related = moment(task.start, "YYYYMMDDTHHmmss")
+ rel = 'START'
+ d = 0
+ else if task.due
+ related = moment(task.due, "YYYYMMDDTHHmmss")
+ rel = 'END'
+ d = 1
+ else
+ return true
+ seg = @secondsToSegments(date.diff(related, 'seconds'))
+ reminder.duration = {
+ token: 'week'
+ params: {
+ related: rel
+ invert: seg.invert
+ id: +seg.invert+''+d
+ }
+ week: seg.week
+ day: seg.day
+ hour: seg.hour
+ minute: seg.minute
+ second: seg.second
+ }
+ else
+ return false
+ return true
+
+ secondsToSegments: (s) ->
+ if s<0
+ s *= -1
+ i = true
+ else
+ i = false
+ w = Math.floor(s/604800)
+ s -= w*604800
+ d = Math.floor(s/86400)
+ s -= d*86400
+ h = Math.floor(s/3600)
+ s -= h*3600
+ m = Math.floor(s/60)
+ s -= m*60
+ return {week:w, day:d, hour:h, minute:m, second:s, invert: i}
+
deleteReminderDate: (taskID) ->
- @_$tasksmodel.setReminderDate(taskID, null)
+ @_$tasksmodel.setReminder(taskID, null)
@_persistence.setReminder(taskID,false)
changeCalendarId: (taskID, calendarID) ->
diff --git a/js/app/services/models/tasksmodel.coffee b/js/app/services/models/tasksmodel.coffee
index a759c751..32b63284 100644
--- a/js/app/services/models/tasksmodel.coffee
+++ b/js/app/services/models/tasksmodel.coffee
@@ -127,7 +127,7 @@ angular.module('Tasks').factory 'TasksModel',
setDueDate: (taskID,date) ->
@update({id:taskID,due:date})
- setReminderDate: (taskID,reminder) ->
+ setReminder: (taskID,reminder) ->
@update({id:taskID,reminder:reminder})
setStartDate: (taskID,date) ->
@@ -136,7 +136,7 @@ angular.module('Tasks').factory 'TasksModel',
overdue: (due) ->
return (moment(due, "YYYYMMDDTHHmmss").isValid() &&
moment(due, "YYYYMMDDTHHmmss").
- diff(moment().startOf('day'), 'days', true) < 0)
+ diff(moment()) < 0)
due: (due) ->
return moment(due, 'YYYYMMDDTHHmmss').isValid()
diff --git a/js/app/services/persistence.coffee b/js/app/services/persistence.coffee
index ab07ed88..dbfbeba3 100644
--- a/js/app/services/persistence.coffee
+++ b/js/app/services/persistence.coffee
@@ -205,7 +205,14 @@ angular.module('Tasks').factory 'Persistence',
data:
type: reminder.type
action: reminder.action
- duration: reminder.duration
+ week: reminder.duration.week
+ day: reminder.duration.day
+ hour: reminder.duration.hour
+ minute: reminder.duration.minute
+ second: reminder.duration.second
+ invert: reminder.duration.params.invert
+ related: reminder.duration.params.related
+
else return
@_request.post '/apps/tasks_enhanced/tasks/{taskID}/reminder', params
diff --git a/js/public/app.js b/js/public/app.js
index 63c4ad2e..328f04a8 100644
--- a/js/public/app.js
+++ b/js/public/app.js
@@ -349,26 +349,60 @@
});
this._$scope.durations = [
{
- name: t('tasks_enhanced', 'years'),
- abbr: 'y'
+ name: t('tasks_enhanced', 'week'),
+ names: t('tasks_enhanced', 'weeks'),
+ id: 'week'
}, {
- name: t('tasks_enhanced', 'months'),
- abbr: 'm'
+ name: t('tasks_enhanced', 'day'),
+ names: t('tasks_enhanced', 'days'),
+ id: 'day'
}, {
- name: t('tasks_enhanced', 'days'),
- abbr: 'd'
+ name: t('tasks_enhanced', 'hour'),
+ names: t('tasks_enhanced', 'hours'),
+ id: 'hour'
}, {
- name: t('tasks_enhanced', 'hours'),
- abbr: 'h'
+ name: t('tasks_enhanced', 'minute'),
+ names: t('tasks_enhanced', 'minutes'),
+ id: 'minute'
}, {
- name: t('tasks_enhanced', 'minutes'),
- abbr: 'i'
- }, {
- name: t('tasks_enhanced', 'seconds'),
- abbr: 's'
+ name: t('tasks_enhanced', 'second'),
+ names: t('tasks_enhanced', 'seconds'),
+ id: 'second'
}
];
- this._$scope.duration = _$scope.durations[1];
+ this._$scope.params = function(task) {
+ var params;
+ params = [
+ {
+ name: t('tasks_enhanced', 'before beginning'),
+ invert: true,
+ related: 'START',
+ id: "10"
+ }, {
+ name: t('tasks_enhanced', 'after beginning'),
+ invert: false,
+ related: 'START',
+ id: "00"
+ }, {
+ name: t('tasks_enhanced', 'before end'),
+ invert: true,
+ related: 'END',
+ id: "11"
+ }, {
+ name: t('tasks_enhanced', 'after end'),
+ invert: false,
+ related: 'END',
+ id: "01"
+ }
+ ];
+ if (task.due && task.start) {
+ return params;
+ } else if (task.start) {
+ return params.slice(0, 2);
+ } else {
+ return params.slice(2);
+ }
+ };
this._$scope.closeDetails = function() {
if (_$scope.status.searchActive) {
return _$location.path('/search/' + _$scope.route.searchString);
@@ -391,24 +425,27 @@
};
this._$scope.editDueDate = function() {
if (_$scope.status.searchActive) {
- return _$location.path('/search/' + _$scope.route.searchString + '/tasks/' + _$scope.route.taskID + '/edit/duedate');
+ _$location.path('/search/' + _$scope.route.searchString + '/tasks/' + _$scope.route.taskID + '/edit/duedate');
} else {
- return _$location.path('/lists/' + _$scope.route.listID + '/tasks/' + _$scope.route.taskID + '/edit/duedate');
+ _$location.path('/lists/' + _$scope.route.listID + '/tasks/' + _$scope.route.taskID + '/edit/duedate');
}
+ return _tasksbusinesslayer.initDueDate(_$scope.route.taskID);
};
this._$scope.editStart = function() {
if (_$scope.status.searchActive) {
- return _$location.path('/search/' + _$scope.route.searchString + '/tasks/' + _$scope.route.taskID + '/edit/startdate');
+ _$location.path('/search/' + _$scope.route.searchString + '/tasks/' + _$scope.route.taskID + '/edit/startdate');
} else {
- return _$location.path('/lists/' + _$scope.route.listID + '/tasks/' + _$scope.route.taskID + '/edit/startdate');
+ _$location.path('/lists/' + _$scope.route.listID + '/tasks/' + _$scope.route.taskID + '/edit/startdate');
}
+ return _tasksbusinesslayer.initStartDate(_$scope.route.taskID);
};
this._$scope.editReminder = function() {
if (_$scope.status.searchActive) {
- return _$location.path('/search/' + _$scope.route.searchString + '/tasks/' + _$scope.route.taskID + '/edit/reminder');
+ _$location.path('/search/' + _$scope.route.searchString + '/tasks/' + _$scope.route.taskID + '/edit/reminder');
} else {
- return _$location.path('/lists/' + _$scope.route.listID + '/tasks/' + _$scope.route.taskID + '/edit/reminder');
+ _$location.path('/lists/' + _$scope.route.listID + '/tasks/' + _$scope.route.taskID + '/edit/reminder');
}
+ return _tasksbusinesslayer.initReminder(_$scope.route.taskID);
};
this._$scope.editNote = function() {
if (_$scope.status.searchActive) {
@@ -500,15 +537,15 @@
return _tasksbusinesslayer.setDue(_$scope.route.taskID, moment(date, 'HH:mm'), 'time');
};
this._$scope.setreminderday = function(date) {
- return _tasksbusinesslayer.setReminder(_$scope.route.taskID, moment(date, 'MM/DD/YYYY'), 'day');
+ return _tasksbusinesslayer.setReminderDate(_$scope.route.taskID, moment(date, 'MM/DD/YYYY'), 'day');
};
this._$scope.setremindertime = function(date) {
- return _tasksbusinesslayer.setReminder(_$scope.route.taskID, moment(date, 'HH:mm'), 'time');
+ return _tasksbusinesslayer.setReminderDate(_$scope.route.taskID, moment(date, 'HH:mm'), 'time');
};
this._$scope.reminderType = function(task) {
if (!angular.isUndefined(task)) {
if (task.reminder === null) {
- if (moment(task.start, "YYYYMMDDTHHmmss").isValid()) {
+ if (moment(task.start, "YYYYMMDDTHHmmss").isValid() || moment(task.due, "YYYYMMDDTHHmmss").isValid()) {
return 'DURATION';
} else {
return 'DATE-TIME';
@@ -518,6 +555,30 @@
}
}
};
+ this._$scope.changeReminderType = function(task) {
+ _tasksbusinesslayer.checkReminderDate(task.id);
+ if (this.reminderType(task) === 'DURATION') {
+ if (task.reminder) {
+ task.reminder.type = 'DATE-TIME';
+ } else {
+ task.reminder = {
+ type: 'DATE-TIME'
+ };
+ }
+ } else {
+ if (task.reminder) {
+ task.reminder.type = 'DURATION';
+ } else {
+ task.reminder = {
+ type: 'DURATION'
+ };
+ }
+ }
+ return _tasksbusinesslayer.setReminder(task.id);
+ };
+ this._$scope.setReminderDuration = function(taskID) {
+ return _tasksbusinesslayer.setReminder(_$scope.route.taskID);
+ };
}
return DetailsController;
@@ -1006,6 +1067,14 @@
return this._persistence.deleteTask(taskID);
};
+ TasksBusinessLayer.prototype.initDueDate = function(taskID) {
+ var due;
+ due = moment(this._$tasksmodel.getById(taskID).due, "YYYYMMDDTHHmmss");
+ if (!due.isValid()) {
+ return this.setDue(taskID, moment().startOf('hour').add('h', 1), 'time');
+ }
+ };
+
TasksBusinessLayer.prototype.setDue = function(taskID, date, type) {
var due;
if (type == null) {
@@ -1028,14 +1097,28 @@
return;
}
this._$tasksmodel.setDueDate(taskID, due.format('YYYYMMDDTHHmmss'));
+ this.checkReminderDate(taskID);
return this._persistence.setDueDate(taskID, due.isValid() ? due.unix() : false);
};
TasksBusinessLayer.prototype.deleteDueDate = function(taskID) {
+ var reminder;
+ reminder = this._$tasksmodel.getById(taskID).reminder;
+ if (reminder !== null && reminder.type === 'DURATION' && reminder.duration.params.related === 'END') {
+ this.deleteReminderDate(taskID);
+ }
this._$tasksmodel.setDueDate(taskID, null);
return this._persistence.setDueDate(taskID, false);
};
+ TasksBusinessLayer.prototype.initStartDate = function(taskID) {
+ var start;
+ start = moment(this._$tasksmodel.getById(taskID).start, "YYYYMMDDTHHmmss");
+ if (!start.isValid()) {
+ return this.setStart(taskID, moment().startOf('hour').add('h', 1), 'time');
+ }
+ };
+
TasksBusinessLayer.prototype.setStart = function(taskID, date, type) {
var start;
if (type == null) {
@@ -1058,15 +1141,56 @@
return;
}
this._$tasksmodel.setStartDate(taskID, start.format('YYYYMMDDTHHmmss'));
+ this.checkReminderDate(taskID);
return this._persistence.setStartDate(taskID, start.isValid() ? start.unix() : false);
};
TasksBusinessLayer.prototype.deleteStartDate = function(taskID) {
+ var reminder;
+ reminder = this._$tasksmodel.getById(taskID).reminder;
+ if (reminder !== null && reminder.type === 'DURATION' && reminder.duration.params.related === 'START') {
+ this.deleteReminderDate(taskID);
+ }
this._$tasksmodel.setStartDate(taskID, null);
return this._persistence.setStartDate(taskID, false);
};
- TasksBusinessLayer.prototype.setReminder = function(taskID, date, type) {
+ TasksBusinessLayer.prototype.initReminder = function(taskID) {
+ var p, task;
+ if (!this.checkReminderDate(taskID)) {
+ task = this._$tasksmodel.getById(taskID);
+ task.reminder = {
+ type: 'DURATION',
+ action: 'DISPLAY',
+ duration: {
+ token: 'week',
+ week: 0,
+ day: 0,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ params: {
+ invert: true
+ }
+ }
+ };
+ if (moment(task.start, "YYYYMMDDTHHmmss").isValid()) {
+ p = task.reminder.duration.params;
+ p.related = 'START';
+ p.id = '10';
+ } else if (moment(task.due, "YYYYMMDDTHHmmss").isValid()) {
+ p = task.reminder.duration.params;
+ p.related = 'END';
+ p.id = '11';
+ } else {
+ task.reminder.type = 'DATE-TIME';
+ task.reminder.date = moment().startOf('hour').add('h', 1).format('YYYYMMDDTHHmmss');
+ }
+ }
+ return this.setReminder(taskID);
+ };
+
+ TasksBusinessLayer.prototype.setReminderDate = function(taskID, date, type) {
var newreminder, reminder, reminderdate;
if (type == null) {
type = 'day';
@@ -1075,11 +1199,10 @@
newreminder = {
type: 'DATE-TIME',
action: 'DISPLAY',
- duration: null,
- trigger: null
+ duration: null
};
if (type === 'day') {
- if (!(angular.isUndefined(reminder) || reminder === null)) {
+ if (this.checkReminderDate(taskID) || reminder === null) {
reminderdate = moment(reminder.date, "YYYYMMDDTHHmmss");
newreminder.action = reminder.action;
if (reminderdate.isValid() && reminder.type === 'DATE-TIME') {
@@ -1091,7 +1214,7 @@
reminderdate = date.add('h', 12);
}
} else if (type === 'time') {
- if (!(angular.isUndefined(reminder) || reminder === null)) {
+ if (this.checkReminderDate(taskID) || reminder === null) {
reminderdate = moment(reminder.date, "YYYYMMDDTHHmmss");
newreminder.action = reminder.action;
if (reminderdate.isValid() && reminder.type === 'DATE-TIME') {
@@ -1106,12 +1229,128 @@
return;
}
newreminder.date = reminderdate.format('YYYYMMDDTHHmmss');
- this._$tasksmodel.setReminderDate(taskID, newreminder);
+ this._$tasksmodel.setReminder(taskID, newreminder);
return this._persistence.setReminder(taskID, newreminder);
};
+ TasksBusinessLayer.prototype.setReminder = function(taskID) {
+ var reminder;
+ if (this.checkReminderDate(taskID)) {
+ reminder = this._$tasksmodel.getById(taskID).reminder;
+ return this._persistence.setReminder(taskID, reminder);
+ }
+ };
+
+ TasksBusinessLayer.prototype.checkReminderDate = function(taskID) {
+ var d, date, duration, rel, related, reminder, seg, task, token;
+ task = this._$tasksmodel.getById(taskID);
+ reminder = task.reminder;
+ if (reminder !== null && reminder.type === 'DURATION') {
+ if (!reminder.duration) {
+ return false;
+ } else if (reminder.duration.params.related === 'START') {
+ token = 'start';
+ } else if (reminder.duration.params.related === 'END') {
+ token = 'due';
+ } else {
+ return false;
+ }
+ date = moment(task[token], "YYYYMMDDTHHmmss");
+ duration = reminder.duration;
+ d = {
+ w: duration.week,
+ d: duration.day,
+ h: duration.hour,
+ m: duration.minute,
+ s: duration.second
+ };
+ if (duration.params.invert) {
+ date = date.subtract(d);
+ } else {
+ date = date.add(d);
+ }
+ task.reminder.date = date.format('YYYYMMDDTHHmmss');
+ } else if (reminder !== null && reminder.type === 'DATE-TIME') {
+ duration = reminder.duration;
+ date = moment(reminder.date, "YYYYMMDDTHHmmss");
+ if (!date.isValid()) {
+ return false;
+ }
+ if (duration) {
+ if (duration.params.related === 'START') {
+ related = moment(task.start, "YYYYMMDDTHHmmss");
+ } else {
+ related = moment(task.due, "YYYYMMDDTHHmmss");
+ }
+ seg = this.secondsToSegments(date.diff(related, 'seconds'));
+ duration.params.invert = seg.invert;
+ duration.token = 'week';
+ duration.week = seg.week;
+ duration.day = seg.day;
+ duration.hour = seg.hour;
+ duration.minute = seg.minute;
+ duration.second = seg.second;
+ } else {
+ if (task.start) {
+ related = moment(task.start, "YYYYMMDDTHHmmss");
+ rel = 'START';
+ d = 0;
+ } else if (task.due) {
+ related = moment(task.due, "YYYYMMDDTHHmmss");
+ rel = 'END';
+ d = 1;
+ } else {
+ return true;
+ }
+ seg = this.secondsToSegments(date.diff(related, 'seconds'));
+ reminder.duration = {
+ token: 'week',
+ params: {
+ related: rel,
+ invert: seg.invert,
+ id: +seg.invert + '' + d
+ },
+ week: seg.week,
+ day: seg.day,
+ hour: seg.hour,
+ minute: seg.minute,
+ second: seg.second
+ };
+ }
+ } else {
+ return false;
+ }
+ return true;
+ };
+
+ TasksBusinessLayer.prototype.secondsToSegments = function(s) {
+ var d, h, i, m, w;
+ if (s < 0) {
+ s *= -1;
+ i = true;
+ } else {
+ i = false;
+ }
+ w = Math.floor(s / 604800);
+ s -= w * 604800;
+ d = Math.floor(s / 86400);
+ s -= d * 86400;
+ h = Math.floor(s / 3600);
+ s -= h * 3600;
+ m = Math.floor(s / 60);
+ s -= m * 60;
+ return {
+ week: w,
+ day: d,
+ hour: h,
+ minute: m,
+ second: s,
+ invert: i
+ };
+ };
+
TasksBusinessLayer.prototype.deleteReminderDate = function(taskID) {
- this._$tasksmodel.setReminderDate(taskID, null);
+ this._$tasksmodel.setReminder(taskID, null);
return this._persistence.setReminder(taskID, false);
};
@@ -1611,7 +1850,7 @@
});
};
- TasksModel.prototype.setReminderDate = function(taskID, reminder) {
+ TasksModel.prototype.setReminder = function(taskID, reminder) {
return this.update({
id: taskID,
reminder: reminder
@@ -1626,7 +1865,7 @@
};
TasksModel.prototype.overdue = function(due) {
- return moment(due, "YYYYMMDDTHHmmss").isValid() && moment(due, "YYYYMMDDTHHmmss").diff(moment().startOf('day'), 'days', true) < 0;
+ return moment(due, "YYYYMMDDTHHmmss").isValid() && moment(due, "YYYYMMDDTHHmmss").diff(moment()) < 0;
};
TasksModel.prototype.due = function(due) {
@@ -1930,7 +2169,13 @@
data: {
type: reminder.type,
action: reminder.action,
- duration: reminder.duration
+ week: reminder.duration.week,
+ day: reminder.duration.day,
+ hour: reminder.duration.hour,
+ minute: reminder.duration.minute,
+ second: reminder.duration.second,
+ invert: reminder.duration.params.invert,
+ related: reminder.duration.params.related
}
};
} else {
@@ -2112,25 +2357,49 @@
(function() {
angular.module('Tasks').filter('reminderDetails', function() {
return function(reminder, scope) {
- var ds, token, _i, _len, _ref;
+ var ds, time, token, _i, _len, _ref;
if (!(angular.isUndefined(reminder) || reminder === null)) {
if (reminder.type === 'DATE-TIME' && moment(reminder.date, "YYYYMMDDTHHmmss").isValid()) {
return moment(reminder.date, "YYYYMMDDTHHmmss").lang('reminder').calendar();
- } else if (reminder.type === 'DURATION') {
+ } else if (reminder.type === 'DURATION' && reminder.duration) {
ds = t('tasks_enhanced', 'Remind me');
_ref = scope.durations;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
token = _ref[_i];
- if (reminder.duration[token.abbr]) {
- ds += ' ' + reminder.duration[token.abbr] + ' ' + t('tasks_enhanced', token.name);
+ if (+reminder.duration[token.id]) {
+ time = 1;
+ ds += ' ' + reminder.duration[token.id] + ' ';
+ if (+reminder.duration[token.id] === 1) {
+ ds += token.name;
+ } else {
+ ds += token.names;
+ }
}
}
- if (reminder.duration.invert) {
- ds += ' ' + t('tasks_enhanced', 'before');
+ if (!time) {
+ if (reminder.duration.params.related === 'END') {
+ ds += ' ' + t('tasks_enhanced', 'at the end');
+ } else {
+ ds += ' ' + t('tasks_enhanced', 'at the beginning');
+ }
} else {
- ds += ' ' + t('tasks_enhanced', 'after');
+ if (reminder.duration.params.invert) {
+ if (reminder.duration.params.related === 'END') {
+ ds += ' ' + t('tasks_enhanced', 'before end');
+ } else {
+ ds += ' ' + t('tasks_enhanced', 'before beginning');
+ }
+ } else {
+ if (reminder.duration.params.related === 'END') {
+ ds += ' ' + t('tasks_enhanced', 'after end');
+ } else {
+ ds += ' ' + t('tasks_enhanced', 'after beginning');
+ }
+ }
}
return ds;
+ } else {
+ return t('tasks_enhanced', 'Remind me');
}
} else {
return t('tasks_enhanced', 'Remind me');
diff --git a/l10n/de.php b/l10n/de.php
index 2e3439b7..2280dd6e 100644
--- a/l10n/de.php
+++ b/l10n/de.php
@@ -8,17 +8,33 @@
"All" => "Alle",
"Current" => "Aktuell",
"years" => "Jahre",
+"year" => "Jahr",
"months" => "Monate",
+"month" => "Monat",
"weeks" => "Wochen",
+"week" => "Woche",
+"Week" => "Woche",
"days" => "Tage",
+"day" => "Tag",
"Hours" => "Stunden",
+"Hour" => "Stunde",
"hours" => "Stunden",
+"hour" => "Stunde",
"Minutes" => "Minuten",
+"Minute" => "Minute",
"minutes" => "Minuten",
+"minute" => "Minute",
"seconds" => "Sekunden",
+"second" => "Sekunde",
"before" => "vorher",
"after" => "danach",
-"Week" => "Woche",
+"before beginning" => "vor Beginn",
+"after beginning" => "nach Beginn",
+"before end" => "vor Ende",
+"after end" => "nach Ende",
+"on time" => "pünktlich",
+"at the end" => "am Ende",
+"at the beginning" => "zu Beginn",
"Add Task" => "Task hinzufügen",
"Set due date" => "Fälligkeitsdatum auswählen",
"Remind me" => "Erinnere mich",
diff --git a/lib/controller/taskscontroller.php b/lib/controller/taskscontroller.php
index c4b6f1c0..6d77aed6 100644
--- a/lib/controller/taskscontroller.php
+++ b/lib/controller/taskscontroller.php
@@ -356,6 +356,8 @@ class TasksController extends Controller {
if ($type == false){
unset($vtodo->VALARM);
+ $vtodo->setDateTime('LAST-MODIFIED', 'now', \Sabre\VObject\Property\DateTime::UTC);
+ $vtodo->setDateTime('DTSTAMP', 'now', \Sabre\VObject\Property\DateTime::UTC);
\OC_Calendar_Object::edit($taskId, $vcalendar->serialize());
}
elseif (in_array($type,$types)) {
@@ -369,21 +371,60 @@ class TasksController extends Controller {
} else {
unset($valarm->TRIGGER);
}
- $triggervalue = '';
+ $tv = '';
+ $related = null;
if ($type == 'DATE-TIME') {
$date = new \DateTime('@'.$this->params('date'));
- $triggervalue = $date->format('Ymd\THis\Z');
+ $tv = $date->format('Ymd\THis\Z');
} elseif ($type == 'DURATION') {
- // TODO
- $triggervalue = '-PT5M';
+ $invert = $this->params('invert');
+ $related= $this->params('related');
+ $week = (int)$this->params('week');
+ $day = (int)$this->params('day');
+ $hour = (int)$this->params('hour');
+ $minute = (int)$this->params('minute');
+ $second = (int)$this->params('second');
+
+ // Create duration string
+ if($week || $day || $hour || $minute || $second) {
+ if ($invert){
+ $tv.='-';
+ }
+ $tv.='P';
+ if ($week){
+ $tv.=$week.'W';
+ }
+ if ($day){
+ $tv.=$day.'D';
+ }
+ $tv.='T';
+ if ($hour){
+ $tv.=$hour.'H';
+ }
+ if ($minute){
+ $tv.=$minute.'M';
+ }
+ if ($second){
+ $tv.=$second.'S';
+ }
+ }else{
+ $tv = 'PT0S';
+ }
}
- $valarm->addProperty('TRIGGER', $triggervalue, array('VALUE' => $type));
+ if($related == 'END'){
+ $valarm->addProperty('TRIGGER', $tv, array('VALUE' => $type, 'RELATED' => $related));
+ } else {
+ $valarm->addProperty('TRIGGER', $tv, array('VALUE' => $type));
+ }
+ $vtodo->setDateTime('LAST-MODIFIED', 'now', \Sabre\VObject\Property\DateTime::UTC);
+ $vtodo->setDateTime('DTSTAMP', 'now', \Sabre\VObject\Property\DateTime::UTC);
\OC_Calendar_Object::edit($taskId, $vcalendar->serialize());
} catch (\Exception $e) {
}
}
+
return $response;
}
diff --git a/lib/helper.php b/lib/helper.php
index 86165bf2..016d6bf0 100644
--- a/lib/helper.php
+++ b/lib/helper.php
@@ -36,6 +36,7 @@ Class helper {
public static function arrayForJSON($id, $vtodo, $user_timezone){
$task = array( 'id' => $id );
$task['name'] = $vtodo->getAsString('SUMMARY');
+ $task['created'] = $vtodo->getAsString('CREATED');
$task['note'] = $vtodo->getAsString('DESCRIPTION');
$task['location'] = $vtodo->getAsString('LOCATION');
$task['categories'] = $vtodo->getAsArray('CATEGORIES');
@@ -70,30 +71,68 @@ Class helper {
try {
$reminderType = $reminder->TRIGGER['VALUE']->value;
- $reminderTrigger = $reminder->TRIGGER->value;
$reminderAction = $reminder->ACTION->value;
- $parsed1 = null;
+
if($reminderType == 'DATE-TIME'){
$reminderDate = $reminder->TRIGGER->getDateTime();
$reminderDate->setTimezone(new \DateTimeZone($user_timezone));
$reminderDate = $reminderDate->format('Ymd\THis');
- } elseif ($reminderType == 'DURATION' && $start) {
- $parsed_complete = VObject\DateTimeParser::parseDuration($reminder->TRIGGER);
+ } elseif ($reminderType == 'DURATION' && ($start || $due)) {
+
$parsed = VObject\DateTimeParser::parseDuration($reminder->TRIGGER,true);
// Calculate the reminder date from duration and start date
- $reminderDate = $start->modify($parsed)->format('Ymd\THis');
+ if($reminder->TRIGGER['RELATED']->value == 'END' && $due){
+ $reminderDate = $due->modify($parsed)->format('Ymd\THis');
+ } elseif ($start) {
+ $reminderDate = $start->modify($parsed)->format('Ymd\THis');
+ } else{
+ throw new \Exception('Reminder duration related to not available date.');
+ }
+ $result = preg_match('/^(?P<plusminus>\+|-)?P((?P<week>\d+)W)?((?P<day>\d+)D)?(T((?P<hour>\d+)H)?((?P<minute>\d+)M)?((?P<second>\d+)S)?)?$/', $reminder->TRIGGER, $matches);
+ $invert = false;
+ if ($matches['plusminus']==='-') {
+ $invert = true;
+ }
+
+ $parts = array(
+ 'week',
+ 'day',
+ 'hour',
+ 'minute',
+ 'second',
+ );
+
+ $reminderDuration = array(
+ 'token' => null
+ );
+ foreach($parts as $part) {
+ $matches[$part] = isset($matches[$part])&&$matches[$part]?(int)$matches[$part]:0;
+ $reminderDuration[$part] = $matches[$part];
+ if($matches[$part] && !$reminderDuration['token']){
+ $reminderDuration['token'] = $part;
+ }
+ }
+ if($reminderDuration['token'] == null){
+ $reminderDuration['token'] = $parts[0];
+ }
+
+ $reminderDuration['params'] = array(
+ 'id' => (int)$invert.(int)($reminder->TRIGGER['RELATED']->value == 'END'),
+ 'related'=> $reminder->TRIGGER['RELATED']->value?$reminder->TRIGGER['RELATED']->value:'START',
+ 'invert'=> $invert
+ );
+
} else {
$reminderDate = null;
+ $reminderDuration = null;
}
-
$task['reminder'] = array(
'type' => $reminderType,
- 'trigger' => $reminderTrigger,
'action' => $reminderAction,
'date' => $reminderDate,
- 'duration' => $parsed_complete
+ 'duration' => $reminderDuration
);
} catch(\Exception $e) {
diff --git a/templates/main.php b/templates/main.php
index 4e2ed9db..3ba5be46 100644
--- a/templates/main.php
+++ b/templates/main.php
@@ -5,7 +5,7 @@
<a id="search" ng-click="openSearch()" oc-click-focus="{selector: '#search-toolbar input', timeout: 0}">
<span class="icon search"></span>
</a>
- <a id="loading" ng-click="update()">
+ <a id="loading" ng-click="update()" stop-event="click">
<span class="loading" ng-class="{'done':!isLoading()}"></span>
</a>
</div>
diff --git a/templates/part.details.php b/templates/part.details.php
index 08f1d642..ebe369ae 100644
--- a/templates/part.details.php
+++ b/templates/part.details.php
@@ -49,6 +49,7 @@
<div class="section detail-reminder" ng-class="{'date':isDue(task.reminder.date), 'editing':route.parameter=='reminder'}" ng-click="editReminder()" stop-event="click">
<!-- oc-click-focus="{selector: 'div.detail-reminder input.datepicker-input', timeout: 0}" -->
<span class="icon detail-reminder" ng-class="{'overdue':isOverDue(task.reminder.date)}"></span>
+ <span class="icon detail-remindertype" ng-click="changeReminderType(task)" ng-show="task.due || task.start"></span>
<div class="section-title" ng-class="{'overdue':isOverDue(task.reminder.date)}" ng-hide="route.parameter=='reminder'">
<text rel="">{{ task.reminder | reminderDetails:this }}</text>
</div>
@@ -63,8 +64,9 @@
<input class="timepicker-input medium focus" type="text" key-value="" placeholder="hh:mm" value="{{ task.reminder.date | timeTaskList }}" timepicker="reminder" stop-event="click">
</div>
<div ng-switch-when="DURATION">
- <input class="datepicker-input medium focus" type="text" key-value="" placeholder="" value="">
- <select ng-model="duration" ng-options="duration.name for duration in durations"></select>
+ <input ng-change="setReminderDuration(task.id)" class="duration-input medium focus" type="number" key-value="" placeholder="" ng-model="task.reminder.duration[task.reminder.duration.token]">
+ <select ng-model="task.reminder.duration.token" ng-options="duration.id as duration.names for duration in durations"></select>
+ <select ng-change="setReminderDuration(task.id)" ng-model="task.reminder.duration.params" ng-options="param as param.name for param in params(task) track by param.id"></select>
</div>
</div>
</div>