diff options
author | raimund-schluessler <raimund.schluessler@googlemail.com> | 2014-07-19 11:54:15 +0400 |
---|---|---|
committer | raimund-schluessler <raimund.schluessler@googlemail.com> | 2014-07-19 11:54:15 +0400 |
commit | bb0ddc1751ed8b0c54e516cec2f27de2a595e1fd (patch) | |
tree | f47085318dacda89c570bf6ee76790bcbc1657a6 | |
parent | 65978357c0279930efeac3cbb90aa9323e923813 (diff) |
First working implementation of commenting
-rw-r--r-- | appinfo/routes.php | 10 | ||||
-rw-r--r-- | css/style.css | 80 | ||||
-rw-r--r-- | css/style.less | 84 | ||||
-rw-r--r-- | js/app/controllers/detailscontroller.coffee | 26 | ||||
-rw-r--r-- | js/app/services/businesslayer/tasksbusinesslayer.coffee | 21 | ||||
-rw-r--r-- | js/app/services/models/tasksmodel.coffee | 22 | ||||
-rw-r--r-- | js/app/services/persistence.coffee | 18 | ||||
-rw-r--r-- | js/public/app.js | 119 | ||||
-rw-r--r-- | l10n/de.php | 1 | ||||
-rw-r--r-- | lib/controller/taskscontroller.php | 30 | ||||
-rw-r--r-- | lib/helper.php | 16 | ||||
-rw-r--r-- | templates/part.details.php | 46 |
12 files changed, 425 insertions, 48 deletions
diff --git a/appinfo/routes.php b/appinfo/routes.php index c0523484..9af9e280 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -253,6 +253,16 @@ $this->create('task_comment', '/tasks/{taskID}/comment') } ); +$this->create('task_deletecomment', '/tasks/{taskID}/comment/{commentID}/delete') + ->post() + ->action( + function($params){ + session_write_close(); + $dispatcher = new Dispatcher($params); + $dispatcher->dispatch('TasksController', 'deleteComment'); + } + ); + /* * Settings */ diff --git a/css/style.css b/css/style.css index 0ab32ac0..d65b6919 100644 --- a/css/style.css +++ b/css/style.css @@ -636,7 +636,7 @@ border-top: 1px solid #D3D3D3; bottom: 0; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset; - height: 35px; + height: 65px; left: 0; position: absolute; right: 0; @@ -647,9 +647,34 @@ } #task-details div.footer .icon { position: absolute; - top: 8px; + bottom: 7px; left: 8px; } +#task-details div.footer .detail-addcomment { + padding: 4px 10px 0; +} +#task-details div.footer .detail-addcomment input { + background: none repeat scroll 0 0 white; + border: 1px solid #bdbcbb; + border-radius: 0; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset; + box-sizing: border-box; + color: #423e3e; + font-family: "Helvetica Neue", "Helvetica", "Arial", Sans-Serif; + font-size: 13px; + font-weight: 500; + margin-top: 2px; + outline: medium none; + padding: 4px; + transition: all 0.2s ease-in-out 0s; +} +#task-details div.footer .detail-addcomment input[type="text"] { + width: 260px; +} +#task-details div.footer .detail-addcomment input[type="button"] { + float: right; + margin-right: 0; +} #task-details.completed .body .section .section-title { color: #9FA2A6 !important; } @@ -723,7 +748,7 @@ position: relative; } #task-details .body { - bottom: 36px; + bottom: 65px; left: 0; overflow: auto; position: absolute; @@ -742,7 +767,7 @@ border-color: #CFCFCF; font-size: 13px; line-height: 26px; - margin: 20px; + margin: 0 20px; padding: 5px 15px; cursor: text; } @@ -956,6 +981,53 @@ #task-details .body .section.detail-reminder.date .section-description { display: block; } +#task-details .body .section.detail-note { + padding: 20px 0; + height: auto; +} +#task-details .body .section.detail-comments { + background: none; + padding: 10px 0; + height: auto; +} +#task-details .body .section.detail-comments .comment-item { + padding: 5px 60px 0; + position: relative; +} +#task-details .body .section.detail-comments .comment-item .icon.detail-delete { + top: 5px; +} +#task-details .body .section.detail-comments .comment-item:hover .icon.detail-delete { + display: block; +} +#task-details .body .section.detail-comments .comment-item .avatar { + width: 40px; + height: 40px; + position: absolute; + left: 10px; + top: 10px; + border-radius: 2px; + overflow: hidden; +} +#task-details .body .section.detail-comments .comment-item .avatar img { + height: 100%; + width: 100%; +} +#task-details .body .section.detail-comments .comment-item .username { + display: inline-block; + font-weight: bold; +} +#task-details .body .section.detail-comments .comment-item .time { + color: #9fa2a6; + font-size: 11px; +} +#task-details .body .section.detail-addcomment { + background: url("../img/divider.svg") repeat-x scroll center top transparent; + bottom: 0; + left: 0; + position: absolute; + right: 0; +} #modal-wrapper { position: absolute; width: 100%; diff --git a/css/style.less b/css/style.less index 0761850f..fba94a42 100644 --- a/css/style.less +++ b/css/style.less @@ -674,12 +674,11 @@ position: relative; } div.footer{ - // background: none repeat scroll 0 0 #f1f1f1; background: url("../img/bgTask.png") repeat scroll 0 0 #FFFFFF; border-top: 1px solid #D3D3D3; bottom: 0; box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset; - height: 35px; + height: 65px; left: 0; position: absolute; right: 0; @@ -689,9 +688,34 @@ } .icon{ position:absolute; - top:8px; + bottom:7px; left:8px; } + .detail-addcomment{ + padding: 4px 10px 0; + input{ + background: none repeat scroll 0 0 white; + border: 1px solid #bdbcbb; + border-radius: 0; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1) inset; + box-sizing: border-box; + color: #423e3e; + font-family: "Helvetica Neue","Helvetica","Arial",Sans-Serif; + font-size: 13px; + font-weight: 500; + margin-top: 2px; + outline: medium none; + padding: 4px; + transition: all 0.2s ease-in-out 0s; + &[type="text"]{ + width: 260px; + } + &[type="button"]{ + float: right; + margin-right: 0; + } + } + } } &.completed{ .body{ @@ -772,7 +796,7 @@ } } .body{ - bottom: 36px; + bottom: 65px; left: 0; overflow: auto; position: absolute; @@ -786,7 +810,7 @@ // box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 1px 0 #F8F5DB inset; font-size: 13px; line-height: 26px; - margin: 20px; + margin: 0 20px; padding: 5px 15px; cursor:text; .expandingArea{ @@ -1002,6 +1026,56 @@ } } } + &.detail-note{ + padding: 20px 0; + height:auto; + } + &.detail-comments{ + background: none; + padding: 10px 0; + height: auto; + .comment-item{ + padding: 5px 60px 0; + position: relative; + .icon.detail-delete{ + top: 5px; + } + &:hover{ + .icon.detail-delete{ + display: block; + } + } + .avatar{ + width: 40px; + height: 40px; + position: absolute; + left: 10px; + top: 10px; + border-radius: 2px; + overflow: hidden; + img{ + height: 100%; + width: 100%; + } + } + .username{ + display: inline-block; + font-weight: bold; + } + .comment{} + .time{ + color: #9fa2a6; + font-size: 11px; + } + } + } + &.detail-addcomment{ + background: url("../img/divider.svg") repeat-x scroll center top transparent; + bottom: 0; + left: 0; + position: absolute; + right: 0; + } } } } diff --git a/js/app/controllers/detailscontroller.coffee b/js/app/controllers/detailscontroller.coffee index 95743e56..c80f00b7 100644 --- a/js/app/controllers/detailscontroller.coffee +++ b/js/app/controllers/detailscontroller.coffee @@ -40,6 +40,8 @@ $timeout, $routeParams, SettingsModel) -> @_$scope.settingsmodel = @_$settingsmodel + @_$scope.isAddingComment = false + @_$scope.durations = [ { name: t('tasks_enhanced','week'), @@ -288,8 +290,28 @@ $timeout, $routeParams, SettingsModel) -> @_$scope.setReminderDuration = (taskID) -> _tasksbusinesslayer.setReminder(_$scope.route.taskID) - @_$scope.addComment = () -> - _tasksbusinesslayer.addComment(_$scope.route.taskID,'test') + @_$scope.addComment = (CommentContent) -> + _$scope.isAddingComment = true + + comment = { + tmpID: 'newComment' + Date.now() + comment: CommentContent + taskID: _$scope.route.taskID + time: moment().format('YYYYMMDDTHHmmss') + } + + _tasksbusinesslayer.addComment comment + , (data) => + _$tasksmodel.updateComment(data.comment) + _$scope.isAddingComment = false + , => + _$scope.isAddingComment = false + + _$scope.CommentContent = '' + + @_$scope.deleteComment = (commentID) -> + _tasksbusinesslayer.deleteComment(_$scope.route.taskID, commentID) + return new DetailsController($scope, $window, TasksModel, TasksBusinessLayer, $route, $location, $timeout, $routeParams, diff --git a/js/app/services/businesslayer/tasksbusinesslayer.coffee b/js/app/services/businesslayer/tasksbusinesslayer.coffee index 70f849d3..1d74c127 100644 --- a/js/app/services/businesslayer/tasksbusinesslayer.coffee +++ b/js/app/services/businesslayer/tasksbusinesslayer.coffee @@ -332,8 +332,25 @@ angular.module('Tasks').factory 'TasksBusinessLayer', setShowHidden: (showHidden) -> @_persistence.setShowHidden(showHidden) - addComment: (taskID, comment) -> - @_persistence.addComment(taskID, comment) + # addComment: (taskID, comment) -> + # @_persistence.addComment(taskID, comment) + + addComment: (comment, onSuccess=null, onFailure=null) -> + onSuccess or= -> + onFailure or= -> + + @_$tasksmodel.addComment(comment) + + success = (response) => + if response.status == 'error' + onFailure() + else + onSuccess(response.data) + @_persistence.addComment(comment, success) + + deleteComment: (taskID, commentID) -> + @_$tasksmodel.deleteComment(taskID, commentID) + @_persistence.deleteComment(taskID, commentID) return new TasksBusinessLayer(TasksModel, Persistence) diff --git a/js/app/services/models/tasksmodel.coffee b/js/app/services/models/tasksmodel.coffee index 299661e7..af884cc2 100644 --- a/js/app/services/models/tasksmodel.coffee +++ b/js/app/services/models/tasksmodel.coffee @@ -165,5 +165,27 @@ angular.module('Tasks').factory 'TasksModel', setNote: (taskID, note) -> @update({id:taskID,note:note}) + addComment: (comment) -> + task = @getById(comment.taskID) + task.comments.push(comment) + + updateComment: (comment) -> + task = @getById(comment.taskID) + i = 0 + for com in task.comments + if com.tmpID == comment.tmpID + task.comments[i] = comment + break + i++ + + deleteComment: (taskID, commentID) -> + task = @getById(taskID) + i = 0 + for comment in task.comments + if comment.id == commentID + task.comments.splice(i,1) + break + i++ + return new TasksModel(Utils) ]
\ No newline at end of file diff --git a/js/app/services/persistence.coffee b/js/app/services/persistence.coffee index 39f9df66..dab98b69 100644 --- a/js/app/services/persistence.coffee +++ b/js/app/services/persistence.coffee @@ -326,16 +326,28 @@ angular.module('Tasks').factory 'Persistence', @_request.post '/apps/tasks_enhanced/settings/showhidden/{showHidden}', params - addComment: (taskID, comment) -> + addComment: (comment, onSuccess=null, onFailure=null) -> params = routeParams: - taskID: taskID + taskID: comment.taskID data: - comment: comment + comment: comment.comment + tmpID: comment.tmpID + onSuccess: onSuccess + onFailure: onFailure @_request.post '/apps/tasks_enhanced/tasks/{taskID}/comment', params + deleteComment: (taskID, commentID) -> + params = + routeParams: + taskID: taskID + commentID: commentID + + @_request.post '/apps/tasks_enhanced/tasks/{taskID}/comment/ + {commentID}/delete', params + return new Persistence(Request, Loading, $rootScope) ]
\ No newline at end of file diff --git a/js/public/app.js b/js/public/app.js index 61579472..26dd4fc6 100644 --- a/js/public/app.js +++ b/js/public/app.js @@ -410,6 +410,7 @@ return _$scope.task = _$tasksmodel.getById(_$scope.route.taskID); }); this._$scope.settingsmodel = this._$settingsmodel; + this._$scope.isAddingComment = false; this._$scope.durations = [ { name: t('tasks_enhanced', 'week'), @@ -663,8 +664,26 @@ this._$scope.setReminderDuration = function(taskID) { return _tasksbusinesslayer.setReminder(_$scope.route.taskID); }; - this._$scope.addComment = function() { - return _tasksbusinesslayer.addComment(_$scope.route.taskID, 'test'); + this._$scope.addComment = function(CommentContent) { + var comment, + _this = this; + _$scope.isAddingComment = true; + comment = { + tmpID: 'newComment' + Date.now(), + comment: CommentContent, + taskID: _$scope.route.taskID, + time: moment().format('YYYYMMDDTHHmmss') + }; + _tasksbusinesslayer.addComment(comment, function(data) { + _$tasksmodel.updateComment(data.comment); + return _$scope.isAddingComment = false; + }, function() { + return _$scope.isAddingComment = false; + }); + return _$scope.CommentContent = ''; + }; + this._$scope.deleteComment = function(commentID) { + return _tasksbusinesslayer.deleteComment(_$scope.route.taskID, commentID); }; } @@ -1630,8 +1649,31 @@ return this._persistence.setShowHidden(showHidden); }; - TasksBusinessLayer.prototype.addComment = function(taskID, comment) { - return this._persistence.addComment(taskID, comment); + TasksBusinessLayer.prototype.addComment = function(comment, onSuccess, onFailure) { + var success, + _this = this; + if (onSuccess == null) { + onSuccess = null; + } + if (onFailure == null) { + onFailure = null; + } + onSuccess || (onSuccess = function() {}); + onFailure || (onFailure = function() {}); + this._$tasksmodel.addComment(comment); + success = function(response) { + if (response.status === 'error') { + return onFailure(); + } else { + return onSuccess(response.data); + } + }; + return this._persistence.addComment(comment, success); + }; + + TasksBusinessLayer.prototype.deleteComment = function(taskID, commentID) { + this._$tasksmodel.deleteComment(taskID, commentID); + return this._persistence.deleteComment(taskID, commentID); }; return TasksBusinessLayer; @@ -2156,6 +2198,46 @@ }); }; + TasksModel.prototype.addComment = function(comment) { + var task; + task = this.getById(comment.taskID); + return task.comments.push(comment); + }; + + TasksModel.prototype.updateComment = function(comment) { + var com, i, task, _i, _len, _ref, _results; + task = this.getById(comment.taskID); + i = 0; + _ref = task.comments; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + com = _ref[_i]; + if (com.tmpID === comment.tmpID) { + task.comments[i] = comment; + break; + } + _results.push(i++); + } + return _results; + }; + + TasksModel.prototype.deleteComment = function(taskID, commentID) { + var comment, i, task, _i, _len, _ref, _results; + task = this.getById(taskID); + i = 0; + _ref = task.comments; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + comment = _ref[_i]; + if (comment.id === commentID) { + task.comments.splice(i, 1); + break; + } + _results.push(i++); + } + return _results; + }; + return TasksModel; })(_Model); @@ -2589,19 +2671,40 @@ return this._request.post('/apps/tasks_enhanced/settings/showhidden/{showHidden}', params); }; - Persistence.prototype.addComment = function(taskID, comment) { + Persistence.prototype.addComment = function(comment, onSuccess, onFailure) { var params; + if (onSuccess == null) { + onSuccess = null; + } + if (onFailure == null) { + onFailure = null; + } params = { routeParams: { - taskID: taskID + taskID: comment.taskID }, data: { - comment: comment - } + comment: comment.comment, + tmpID: comment.tmpID + }, + onSuccess: onSuccess, + onFailure: onFailure }; return this._request.post('/apps/tasks_enhanced/tasks/{taskID}/comment', params); }; + Persistence.prototype.deleteComment = function(taskID, commentID) { + var params; + params = { + routeParams: { + taskID: taskID, + commentID: commentID + } + }; + return this._request.post('/apps/tasks_enhanced/tasks/{taskID}/comment/\ + {commentID}/delete', params); + }; + return Persistence; })(); diff --git a/l10n/de.php b/l10n/de.php index 50940550..e5be8371 100644 --- a/l10n/de.php +++ b/l10n/de.php @@ -86,4 +86,5 @@ "Friday" => "Freitag", "Saturday" => "Samstag", "Sunday" => "Sonntag", +"Add Comment" => "Kommentar hinzufügen", );
\ No newline at end of file diff --git a/lib/controller/taskscontroller.php b/lib/controller/taskscontroller.php index 4a071079..bfaea758 100644 --- a/lib/controller/taskscontroller.php +++ b/lib/controller/taskscontroller.php @@ -439,8 +439,6 @@ class TasksController extends Controller { } } - - return $response; } @@ -500,17 +498,30 @@ class TasksController extends Controller { $commentId = 1+max($commentIds); $now = new \DateTime(); - $now = $now->format('Ymd\THis\Z'); - $tmp = $vtodo->addProperty('COMMENT',$comment, + $vtodo->addProperty('COMMENT',$comment, array( 'ID' => $commentId, 'USERID' => $userId, - 'DATE-TIME' => $now + 'DATE-TIME' => $now->format('Ymd\THis\Z') ) ); \OC_Calendar_Object::edit($taskId, $vcalendar->serialize()); - $response->setData(); - + $user_timezone = \OC_Calendar_App::getTimezone(); + $now->setTimezone(new \DateTimeZone($user_timezone)); + $comment = array( + 'taskID' => $taskId, + 'id' => $commentId, + 'tmpID' => $this->params('tmpID'), + 'userID' => $userId, + 'comment' => $comment, + 'time' => $now->format('Ymd\THis') + ); + $result = array( + 'data' => array( + 'comment' => $comment + ) + ); + $response->setData($result); } catch(\Exception $e) { // throw new BusinessLayerException($e->getMessage()); } @@ -520,12 +531,11 @@ class TasksController extends Controller { /** * @NoAdminRequired */ - public function deleteCommentById(){ + public function deleteComment(){ $taskId = $this->params('taskID'); $commentId = $this->params('commentID'); $userId = $this->api->getUserId(); $response = new JSONResponse(); - $test = array(); try { $vcalendar = \OC_Calendar_App::getVCalendar($taskId); $vtodo = $vcalendar->VTODO; @@ -535,7 +545,7 @@ class TasksController extends Controller { } catch(\Exception $e) { // throw new BusinessLayerException($e->getMessage()); } - $response->setData($test); + $response->setData(); return $response; } diff --git a/lib/helper.php b/lib/helper.php index aabecbf7..ca7c8bcb 100644 --- a/lib/helper.php +++ b/lib/helper.php @@ -169,6 +169,22 @@ Class helper { $task['completed'] = false; } $task['complete'] = $vtodo->getAsString('PERCENT-COMPLETE')==''?'0':$vtodo->getAsString('PERCENT-COMPLETE'); + $comments = $vtodo->COMMENT; + if($comments){ + $comments_parsed = array(); + foreach($comments as $com) { + $time = new \DateTime($com['DATE-TIME']->value); + $time->setTimezone(new \DateTimeZone($user_timezone)); + $time = $time->format('Ymd\THis'); + $comments_parsed[] = array( + 'id' => (int)$com['ID']->value, + 'userID' => $com['USERID']->value, + 'comment' => $com->value, + 'time' => $time + ); + } + } + $task['comments'] = $comments_parsed; return $task; } diff --git a/templates/part.details.php b/templates/part.details.php index 5797d1cb..61efe3f4 100644 --- a/templates/part.details.php +++ b/templates/part.details.php @@ -85,32 +85,50 @@ </div> </div> <!-- <ul class="subtasks buffer"></ul> --> - <div class="note"> - <div class="note-body selectable" ng-click="editNote()" stop-event="click" oc-click-focus="{selector: '.expandingArea textarea', timeout: 0}"> - <!-- - <a class="open-fullscreen-note"> - <span class="icon note-fullscreen"></span> - </a> - --> - <div class="content-fakeable"> - <div class="display-view" ng-hide="route.parameter=='note'">{{ task.note }}</div> - <div class="edit-view" ng-show="route.parameter=='note'"> - <div class="expandingArea active"> - <pre><span>{{ task.note }}</span><br /><br /></pre> - <textarea ng-model="task.note"></textarea> + <div class="section detail-note"> + <div class="note"> + <div class="note-body selectable" ng-click="editNote()" stop-event="click" oc-click-focus="{selector: '.expandingArea textarea', timeout: 0}"> + <!-- + <a class="open-fullscreen-note"> + <span class="icon note-fullscreen"></span> + </a> + --> + <div class="content-fakeable"> + <div class="display-view" ng-hide="route.parameter=='note'">{{ task.note }}</div> + <div class="edit-view" ng-show="route.parameter=='note'"> + <div class="expandingArea active"> + <pre><span>{{ task.note }}</span><br /><br /></pre> + <textarea ng-model="task.note"></textarea> + </div> </div> </div> </div> </div> </div> + <div class="section detail-comments"> + <ul> + <li ng-repeat="comment in task.comments" class="comment-item" rel=" {{ comment.id }} "> + <div class="avatar"><img src=""></div> + <a class="detail-delete" ng-click="deleteComment(comment.id)" stop-event="click"> + <span class="icon detail-delete"></span> + </a> + <span class="username">{{ comment.userID }}</span> + <div class="comment">{{ comment.comment }}</div> + <span class="time"> {{ comment.time}} </span> + </li> + </ul> + </div> </div> <div class="footer"> + <div class="detail-addcomment"> + <input type="text" placeholder="Add comment" ng-model="CommentContent"> + <input type="button" ng-click="addComment(CommentContent)" name="addComment" value="Comment"> + </div> <a class="detail-trash" ng-click="deleteTask(task.id)" stop-event="click"> <span class="icon detail-trash"></span> </a> <a class="detail-close" ng-click="closeDetails()" stop-event="click"> <span class="icon detail-close"></span> </a> - <a ng-click="addComment()">Comment</a> </div> </div>
\ No newline at end of file |