summaryrefslogtreecommitdiffstats
path: root/apps/comments/js
diff options
context:
space:
mode:
authorThomas Müller <thomas.mueller@tmit.eu>2016-02-03 20:53:40 +0100
committerThomas Müller <thomas.mueller@tmit.eu>2016-02-03 20:53:40 +0100
commitda0462015507053c4424f62c32a4a182301fae22 (patch)
tree8ea008a05a11719ab042eedd72c9dacec997eef2 /apps/comments/js
parentdd2f62e3e479a9e9aa8a624d8961d8645c8c1aad (diff)
parent85bec3ffcb0e2c948c57cee2817307af2826d847 (diff)
downloadnextcloud-server-da0462015507053c4424f62c32a4a182301fae22.tar.gz
nextcloud-server-da0462015507053c4424f62c32a4a182301fae22.zip
Merge pull request #22101 from owncloud/comments-filerow
Add file row indicator for unread comments
Diffstat (limited to 'apps/comments/js')
-rw-r--r--apps/comments/js/commentcollection.js61
-rw-r--r--apps/comments/js/commentmodel.js5
-rw-r--r--apps/comments/js/commentstabview.js27
-rw-r--r--apps/comments/js/commentsummarymodel.js65
-rw-r--r--apps/comments/js/filesplugin.js84
5 files changed, 235 insertions, 7 deletions
diff --git a/apps/comments/js/commentcollection.js b/apps/comments/js/commentcollection.js
index d10e5e00865..a15039cf484 100644
--- a/apps/comments/js/commentcollection.js
+++ b/apps/comments/js/commentcollection.js
@@ -10,8 +10,6 @@
(function(OC, OCA) {
- var NS_OWNCLOUD = 'http://owncloud.org/ns';
-
/**
* @class OCA.Comments.CommentCollection
* @classdesc
@@ -26,12 +24,40 @@
model: OCA.Comments.CommentModel,
+ /**
+ * Object type
+ *
+ * @type string
+ */
_objectType: 'files',
+
+ /**
+ * Object id
+ *
+ * @type string
+ */
_objectId: null,
+ /**
+ * True if there are no more page results left to fetch
+ *
+ * @type bool
+ */
_endReached: false,
+
+ /**
+ * Number of comments to fetch per page
+ *
+ * @type int
+ */
_limit : 20,
+ /**
+ * Initializes the collection
+ *
+ * @param {string} [options.objectType] object type
+ * @param {string} [options.objectId] object id
+ */
initialize: function(models, options) {
options = options || {};
if (options.objectType) {
@@ -58,6 +84,7 @@
reset: function() {
this._endReached = false;
+ this._summaryModel = null;
return OC.Backbone.Collection.prototype.reset.apply(this, arguments);
},
@@ -81,6 +108,7 @@
var success = options.success;
options = _.extend({
remove: false,
+ parse: true,
data: body,
davProperties: CommentCollection.prototype.model.prototype.davProperties,
success: function(resp) {
@@ -102,6 +130,35 @@
}, options);
return this.sync('REPORT', this, options);
+ },
+
+ /**
+ * Returns the matching summary model
+ *
+ * @return {OCA.Comments.CommentSummaryModel} summary model
+ */
+ getSummaryModel: function() {
+ if (!this._summaryModel) {
+ this._summaryModel = new OCA.Comments.CommentSummaryModel({
+ id: this._objectId,
+ objectType: this._objectType
+ });
+ }
+ return this._summaryModel;
+ },
+
+ /**
+ * Updates the read marker for this comment thread
+ *
+ * @param {Date} [date] optional date, defaults to now
+ * @param {Object} [options] backbone options
+ */
+ updateReadMarker: function(date, options) {
+ options = options || {};
+
+ return this.getSummaryModel().save({
+ readMarker: (date || new Date()).toUTCString()
+ }, options);
}
});
diff --git a/apps/comments/js/commentmodel.js b/apps/comments/js/commentmodel.js
index b945f71fdd2..ba04fd61de3 100644
--- a/apps/comments/js/commentmodel.js
+++ b/apps/comments/js/commentmodel.js
@@ -34,11 +34,12 @@
'actorDisplayName': '{' + NS_OWNCLOUD + '}actorDisplayName',
'creationDateTime': '{' + NS_OWNCLOUD + '}creationDateTime',
'objectType': '{' + NS_OWNCLOUD + '}objectType',
- 'objectId': '{' + NS_OWNCLOUD + '}objectId'
+ 'objectId': '{' + NS_OWNCLOUD + '}objectId',
+ 'isUnread': '{' + NS_OWNCLOUD + '}isUnread'
},
parse: function(data) {
- // TODO: parse non-string values
+ data.isUnread = (data.isUnread === 'true');
return data;
}
});
diff --git a/apps/comments/js/commentstabview.js b/apps/comments/js/commentstabview.js
index 463ac2d76ef..188d8c5943c 100644
--- a/apps/comments/js/commentstabview.js
+++ b/apps/comments/js/commentstabview.js
@@ -31,7 +31,7 @@
'<div class="loading hidden" style="height: 50px"></div>';
var COMMENT_TEMPLATE =
- '<li class="comment">' +
+ '<li class="comment{{#if isUnread}} unread{{/if}}" data-id="{{id}}">' +
' <div class="authorRow">' +
' {{#if avatarEnabled}}' +
' <div class="avatar" data-username="{{actorId}}"> </div>' +
@@ -97,12 +97,14 @@
setFileInfo: function(fileInfo) {
if (fileInfo) {
+ this.model = fileInfo;
this.render();
this.collection.setObjectId(fileInfo.id);
// reset to first page
this.collection.reset([], {silent: true});
this.nextPage();
} else {
+ this.model = null;
this.render();
this.collection.reset();
}
@@ -139,10 +141,29 @@
this.$el.find('.showMore').addClass('hidden');
},
- _onEndRequest: function() {
+ _onEndRequest: function(type) {
+ var fileInfoModel = this.model;
this._toggleLoading(false);
this.$el.find('.empty').toggleClass('hidden', !!this.collection.length);
this.$el.find('.showMore').toggleClass('hidden', !this.collection.hasMoreResults());
+
+ if (type !== 'REPORT') {
+ return;
+ }
+
+ // find first unread comment
+ var firstUnreadComment = this.collection.findWhere({isUnread: true});
+ if (firstUnreadComment) {
+ // update read marker
+ this.collection.updateReadMarker(
+ null,
+ {
+ success: function() {
+ fileInfoModel.set('commentsUnread', 0);
+ }
+ }
+ );
+ }
},
_onAddModel: function(model, collection, options) {
@@ -210,7 +231,7 @@
actorType: 'users',
verb: 'comment',
message: $textArea.val(),
- creationDateTime: (new Date()).getTime()
+ creationDateTime: (new Date()).toUTCString()
}, {
at: 0,
success: function() {
diff --git a/apps/comments/js/commentsummarymodel.js b/apps/comments/js/commentsummarymodel.js
new file mode 100644
index 00000000000..d405315ca1f
--- /dev/null
+++ b/apps/comments/js/commentsummarymodel.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2016
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function(OC, OCA) {
+ var NS_OWNCLOUD = 'http://owncloud.org/ns';
+ /**
+ * @class OCA.Comments.CommentSummaryModel
+ * @classdesc
+ *
+ * Model containing summary information related to comments
+ * like the read marker.
+ *
+ */
+ var CommentSummaryModel = OC.Backbone.Model.extend(
+ /** @lends OCA.Comments.CommentSummaryModel.prototype */ {
+ sync: OC.Backbone.davSync,
+
+ /**
+ * Object type
+ *
+ * @type string
+ */
+ _objectType: 'files',
+
+ /**
+ * Object id
+ *
+ * @type string
+ */
+ _objectId: null,
+
+ davProperties: {
+ 'readMarker': '{' + NS_OWNCLOUD + '}readMarker'
+ },
+
+ /**
+ * Initializes the summary model
+ *
+ * @param {string} [options.objectType] object type
+ * @param {string} [options.objectId] object id
+ */
+ initialize: function(attrs, options) {
+ options = options || {};
+ if (options.objectType) {
+ this._objectType = options.objectType;
+ }
+ },
+
+ url: function() {
+ return OC.linkToRemote('dav') + '/comments/' +
+ encodeURIComponent(this._objectType) + '/' +
+ encodeURIComponent(this.id) + '/';
+ }
+ });
+
+ OCA.Comments.CommentSummaryModel = CommentSummaryModel;
+})(OC, OCA);
+
diff --git a/apps/comments/js/filesplugin.js b/apps/comments/js/filesplugin.js
index c8d91e0ede3..bf6bb05146b 100644
--- a/apps/comments/js/filesplugin.js
+++ b/apps/comments/js/filesplugin.js
@@ -8,7 +8,15 @@
*
*/
+/* global Handlebars */
+
(function() {
+ var TEMPLATE_COMMENTS_UNREAD =
+ '<a class="action action-comment permanent" title="{{countMessage}}" href="#">' +
+ '<img class="svg" src="{{iconUrl}}"/>' +
+ '{{count}}' +
+ '</a>';
+
OCA.Comments = _.extend({}, OCA.Comments);
if (!OCA.Comments) {
/**
@@ -26,12 +34,88 @@
'favorites'
],
+ _formatCommentCount: function(count) {
+ if (!this._commentsUnreadTemplate) {
+ this._commentsUnreadTemplate = Handlebars.compile(TEMPLATE_COMMENTS_UNREAD);
+ }
+ return this._commentsUnreadTemplate({
+ count: count,
+ countMessage: t('comments', '{count} unread comments', {count: count}),
+ iconUrl: OC.imagePath('core', 'actions/comment')
+ });
+ },
+
attach: function(fileList) {
+ var self = this;
if (this.allowedLists.indexOf(fileList.id) < 0) {
return;
}
fileList.registerTabView(new OCA.Comments.CommentsTabView('commentsTabView'));
+
+ var NS_OC = 'http://owncloud.org/ns';
+
+ var oldGetWebdavProperties = fileList._getWebdavProperties;
+ fileList._getWebdavProperties = function() {
+ var props = oldGetWebdavProperties.apply(this, arguments);
+ props.push('{' + NS_OC + '}comments-unread');
+ return props;
+ };
+
+ fileList.filesClient.addFileInfoParser(function(response) {
+ var data = {};
+ var props = response.propStat[0].properties;
+ var commentsUnread = props['{' + NS_OC + '}comments-unread'];
+ if (!_.isUndefined(commentsUnread) && commentsUnread !== '') {
+ data.commentsUnread = parseInt(commentsUnread, 10);
+ }
+ return data;
+ });
+
+ fileList.$el.addClass('has-comments');
+ var oldCreateRow = fileList._createRow;
+ fileList._createRow = function(fileData) {
+ var $tr = oldCreateRow.apply(this, arguments);
+ if (fileData.commentsUnread) {
+ $tr.attr('data-comments-unread', fileData.commentsUnread);
+ }
+ return $tr;
+ };
+
+ // register "comment" action for reading comments
+ fileList.fileActions.registerAction({
+ name: 'Comment',
+ displayName: t('comments', 'Comment'),
+ mime: 'all',
+ permissions: OC.PERMISSION_READ,
+ type: OCA.Files.FileActions.TYPE_INLINE,
+ render: function(actionSpec, isDefault, context) {
+ var $file = context.$file;
+ var unreadComments = $file.data('comments-unread');
+ if (unreadComments) {
+ var $actionLink = $(self._formatCommentCount(unreadComments));
+ context.$file.find('a.name>span.fileactions').append($actionLink);
+ return $actionLink;
+ }
+ return '';
+ },
+ actionHandler: function(fileName, context) {
+ context.$file.find('.action-comment').tooltip('hide');
+ // open sidebar in comments section
+ context.fileList.showDetailsView(fileName, 'commentsTabView');
+ }
+ });
+
+ // add attribute to "elementToFile"
+ var oldElementToFile = fileList.elementToFile;
+ fileList.elementToFile = function($el) {
+ var fileInfo = oldElementToFile.apply(this, arguments);
+ var commentsUnread = $el.data('comments-unread');
+ if (commentsUnread) {
+ fileInfo.commentsUnread = commentsUnread;
+ }
+ return fileInfo;
+ };
}
};