From ffd32a803f282524218c383853cec114eb7ed9f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 4 Oct 2018 17:36:02 +0200 Subject: [PATCH] Enhance activity list with comment data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- js/app/Run.js | 33 ++++++++++++-- js/controller/ActivityController.js | 67 ++++++++++++++++++++++++++++- js/controller/BoardController.js | 4 ++ js/service/ActivityService.js | 49 ++++++++++++++++++++- 4 files changed, 146 insertions(+), 7 deletions(-) diff --git a/js/app/Run.js b/js/app/Run.js index 60523305c..e16a7fe35 100644 --- a/js/app/Run.js +++ b/js/app/Run.js @@ -4,23 +4,48 @@ * @author Julius Härtl * * @license GNU AGPL version 3 or any later version - * + * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program 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 program. If not, see . - * + * */ import app from './App.js'; +app.directive("contenteditable", function() { + return { + require: "ngModel", + link: function(scope, element, attrs, ngModel) { + + //read the text typed in the div (syncing model with the view) + function read() { + ngModel.$setViewValue(element.html()); + } + + //render the data now in your model into your view + //$render is invoked when the modelvalue differs from the viewvalue + //see documentation: https://docs.angularjs.org/api/ng/type/ngModel.NgModelController# + ngModel.$render = function() { + element.html(ngModel.$viewValue || ""); + }; + + //do this whenever someone starts typing + element.bind("blur keyup change", function() { + scope.$apply(read); + }); + } + }; +}); + /* global Snap */ app.run(function ($document, $rootScope, $transitions, BoardService) { 'use strict'; diff --git a/js/controller/ActivityController.js b/js/controller/ActivityController.js index 77ebeaef6..404c980dd 100644 --- a/js/controller/ActivityController.js +++ b/js/controller/ActivityController.js @@ -22,6 +22,9 @@ /* global OC OCA */ +import CommentCollection from '../legacy/commentcollection'; +import CommentModel from '../legacy/commentmodel'; + class ActivityController { constructor ($scope, CardService, ActivityService) { 'ngInject'; @@ -30,12 +33,14 @@ class ActivityController { this.$scope = $scope; this.type = ''; this.loading = false; + this.$scope.newComment = ''; const self = this; this.$scope.$watch(function () { return self.element.id; }, function (params) { if (self.getData(self.element.id).length === 0) { + self.activityservice.loadComments(self.element.id); self.loading = true; self.fetchUntilResults(); } @@ -43,6 +48,48 @@ class ActivityController { }, true); } + + postComment() { + const self = this; + var model = this.activityservice.commentCollection.create({ + actorId: OC.getCurrentUser().uid, + actorDisplayName: OC.getCurrentUser().displayName, + actorType: 'users', + verb: 'comment', + message: self.$scope.newComment, + creationDateTime: (new Date()).toUTCString() + }, { + at: 0, + // wait for real creation before adding + wait: true, + success: function() { + console.log("SUCCESS"); + self.$scope.newComment = ''; + self.activityservice.fetchNewerActivities(self.type, self.element.id).then(function () {}); + }, + error: function() { + + } + }); + } + + updateComment(item) { + let newMessage = 'Edited at ' + (new Date()); + item.commentModel.save({ + message: newMessage, + }); + item.message = newMessage; + + } + + deleteComment() { + + } + + getCommentDetails() {} + + + getData(id) { return this.activityservice.getData(this.type, id); } @@ -59,7 +106,7 @@ class ActivityController { let promise = self.activityservice.fetchMoreActivities(self.type, self.element.id); promise.then(function (data) { let dataLengthAfter = self.getData(self.element.id).length; - if (data !== null && (dataLengthAfter <= dataLengthBefore || dataLengthAfter < 5)) { + if (data !== null && (dataLengthAfter <= dataLengthBefore || dataLengthAfter < self.activityservice.RESULT_PER_PAGE)) { _executeFetch(); } else { self.loading = false; @@ -73,6 +120,24 @@ class ActivityController { _executeFetch(); } + getComments() { + return this.activityservice.comments; + } + + getActivityStream() { + const self = this; + let activities = this.activityservice.getData(this.type, this.element.id); + this.data = []; + for (let i in activities) { + let activity = activities[i]; + activity.timelineType = 'activity'; + activity.timelineTimestamp = activity.timestamp; + this.data.push(activity); + } + let sorted = this.data.sort((a, b) => b.timelineTimestamp - a.timelineTimestamp); + return sorted; + } + page() { if (!this.activityservice.since[this.type][this.element.id].finished) { this.loading = true; diff --git a/js/controller/BoardController.js b/js/controller/BoardController.js index 2e3653ad0..d4951fbd2 100644 --- a/js/controller/BoardController.js +++ b/js/controller/BoardController.js @@ -482,4 +482,8 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St } return card.attachmentCount; }; + + $scope.unreadCommentCount = function(card) { + return card.commentsUnread; + }; }); diff --git a/js/service/ActivityService.js b/js/service/ActivityService.js index 514057edd..ae32983e0 100644 --- a/js/service/ActivityService.js +++ b/js/service/ActivityService.js @@ -21,6 +21,8 @@ */ import app from '../app/App.js'; +import CommentCollection from '../legacy/commentcollection'; +import CommentModel from '../legacy/commentmodel'; const DECK_ACTIVITY_TYPE_BOARD = 'deck_board'; const DECK_ACTIVITY_TYPE_CARD = 'deck_card'; @@ -28,6 +30,8 @@ const DECK_ACTIVITY_TYPE_CARD = 'deck_card'; /* global OC oc_requesttoken */ class ActivityService { + static get RESULT_PER_PAGE() { return 5; } + constructor ($rootScope, $filter, $http, $q) { this.running = false; this.runningNewer = false; @@ -37,6 +41,31 @@ class ActivityService { this.data = {}; this.data[DECK_ACTIVITY_TYPE_BOARD] = {}; this.data[DECK_ACTIVITY_TYPE_CARD] = {}; + this.toEnhanceWithComments = []; + this.commentCollection = new CommentCollection(); + this.commentCollection._limit = this.RESULT_PER_PAGE; + this.commentCollection.on('request', function() { + console.log("REQUEST"); + }, this); + this.commentCollection.on('sync', function() { + console.log("SYNC"); + for (let index in this.toEnhanceWithComments) { + let item = this.toEnhanceWithComments[index]; + item.commentModel = this.commentCollection.get(item.subject_rich[1].comment); + if (typeof item.commentModel !== 'undefined') { + // FIXME: not working + this.toEnhanceWithComments.remove(item); + } + } + console.log(this.toEnhanceWithComments); + var firstUnread = this.commentCollection.findWhere({isUnread: true}); + if (typeof firstUnread !== 'undefined') { + this.commentCollection.updateReadMarker(); + } + }, this); + this.commentCollection.on('add', function(data) { + console.log("ADD"); + }, this); this.since = { deck_card: { @@ -49,10 +78,10 @@ class ActivityService { static getUrl(type, id, since) { if (type === DECK_ACTIVITY_TYPE_CARD) { - return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'filter?format=json&object_type=deck_card&object_id=' + id + '&limit=50&since=' + since; + return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'filter?format=json&object_type=deck_card&object_id=' + id + '&limit=' + this.RESULT_PER_PAGE + '&since=' + since; } if (type === DECK_ACTIVITY_TYPE_BOARD) { - return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'deck?format=json&limit=50&since=' + since; + return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'deck?format=json&limit=' + this.RESULT_PER_PAGE + '&since=' + since; } } @@ -86,12 +115,14 @@ class ActivityService { self.running = false; }); } + fetchMoreActivities(type, id) { this.checkData(type, id); if (this.running === true) { return this.runningPromise; } if (!this.since[type][id].finished) { + this.commentCollection.fetchNext(); this.runningPromise = this.fetchCardActivities(type, id, this.since[type][id].oldest); return this.runningPromise; } @@ -112,6 +143,7 @@ class ActivityService { } addItem(type, id, item) { + const self = this; const existingEntry = this.data[type][id].findIndex((entry) => { return entry.activity_id === item.activity_id; }); if (existingEntry !== -1) { return; @@ -123,6 +155,13 @@ class ActivityService { return; } item.timestamp = new Date(item.datetime).getTime(); + + if (item.subject_rich[1].comment) { + item.commentModel = this.commentCollection.get(item.subject_rich[1].comment); + if (typeof item.commentModel === 'undefined') { + this.toEnhanceWithComments.push(item); + } + } this.data[type][id].push(item); } @@ -179,6 +218,12 @@ class ActivityService { return this.data[type][id]; } + loadComments(id) { + this.commentCollection.reset(); + this.commentCollection.setObjectId(id); + this.commentCollection.fetchNext(); + } + } app.service('ActivityService', ActivityService);