mirror of
https://github.com/nextcloud/server.git
synced 2026-06-13 18:50:47 -04:00
Reset comments read marker after loading comments
This commit is contained in:
parent
8bb1437e24
commit
85bec3ffcb
8 changed files with 235 additions and 11 deletions
|
|
@ -27,6 +27,7 @@ $eventDispatcher->addListener(
|
|||
\OCP\Util::addScript('comments', 'app');
|
||||
\OCP\Util::addScript('comments', 'commentmodel');
|
||||
\OCP\Util::addScript('comments', 'commentcollection');
|
||||
\OCP\Util::addScript('comments', 'commentsummarymodel');
|
||||
\OCP\Util::addScript('comments', 'commentstabview');
|
||||
\OCP\Util::addScript('comments', 'filesplugin');
|
||||
\OCP\Util::addStyle('comments', 'comments');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
65
apps/comments/js/commentsummarymodel.js
Normal file
65
apps/comments/js/commentsummarymodel.js
Normal file
|
|
@ -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);
|
||||
|
||||
|
|
@ -100,5 +100,49 @@ describe('OCA.Comments.CommentCollection', function() {
|
|||
|
||||
expect(collection.hasMoreResults()).toEqual(true);
|
||||
});
|
||||
describe('resetting read marker', function() {
|
||||
var updateStub;
|
||||
var clock;
|
||||
|
||||
beforeEach(function() {
|
||||
updateStub = sinon.stub(OCA.Comments.CommentSummaryModel.prototype, 'save');
|
||||
clock = sinon.useFakeTimers(Date.UTC(2016, 1, 3, 10, 5, 9));
|
||||
});
|
||||
afterEach(function() {
|
||||
updateStub.restore();
|
||||
clock.restore();
|
||||
});
|
||||
|
||||
it('resets read marker to the default date', function() {
|
||||
var successStub = sinon.stub();
|
||||
collection.updateReadMarker(null, {
|
||||
success: successStub
|
||||
});
|
||||
|
||||
expect(updateStub.calledOnce).toEqual(true);
|
||||
expect(updateStub.lastCall.args[0]).toEqual({
|
||||
readMarker: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
|
||||
});
|
||||
|
||||
updateStub.yieldTo('success');
|
||||
|
||||
expect(successStub.calledOnce).toEqual(true);
|
||||
});
|
||||
it('resets read marker to the given date', function() {
|
||||
var successStub = sinon.stub();
|
||||
collection.updateReadMarker(new Date(Date.UTC(2016, 1, 2, 3, 4, 5)), {
|
||||
success: successStub
|
||||
});
|
||||
|
||||
expect(updateStub.calledOnce).toEqual(true);
|
||||
expect(updateStub.lastCall.args[0]).toEqual({
|
||||
readMarker: new Date(Date.UTC(2016, 1, 2, 3, 4, 5)).toUTCString()
|
||||
});
|
||||
|
||||
updateStub.yieldTo('success');
|
||||
|
||||
expect(successStub.calledOnce).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
|
|||
objectType: 'files',
|
||||
objectId: 5,
|
||||
message: 'First',
|
||||
creationDateTime: Date.UTC(2016, 1, 3, 10, 5, 0)
|
||||
creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 0)).toUTCString()
|
||||
});
|
||||
var comment2 = new OCA.Comments.CommentModel({
|
||||
id: 2,
|
||||
|
|
@ -58,7 +58,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
|
|||
objectType: 'files',
|
||||
objectId: 5,
|
||||
message: 'Second\nNewline',
|
||||
creationDateTime: Date.UTC(2016, 1, 3, 10, 0, 0)
|
||||
creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 0, 0)).toUTCString()
|
||||
});
|
||||
|
||||
testComments = [comment1, comment2];
|
||||
|
|
@ -142,7 +142,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
|
|||
objectType: 'files',
|
||||
objectId: 5,
|
||||
message: 'Third',
|
||||
creationDateTime: Date.UTC(2016, 1, 3, 5, 0, 0)
|
||||
creationDateTime: new Date(Date.UTC(2016, 1, 3, 5, 0, 0)).toUTCString()
|
||||
});
|
||||
|
||||
view.collection.add(comment3);
|
||||
|
|
@ -184,7 +184,7 @@ describe('OCA.Comments.CommentsTabView tests', function() {
|
|||
actorType: 'users',
|
||||
verb: 'comment',
|
||||
message: 'New message',
|
||||
creationDateTime: Date.UTC(2016, 1, 3, 10, 5, 9)
|
||||
creationDateTime: new Date(Date.UTC(2016, 1, 3, 10, 5, 9)).toUTCString()
|
||||
});
|
||||
});
|
||||
it('does not create a comment if the field is empty', function() {
|
||||
|
|
@ -195,4 +195,38 @@ describe('OCA.Comments.CommentsTabView tests', function() {
|
|||
});
|
||||
|
||||
});
|
||||
describe('read marker', function() {
|
||||
var updateMarkerStub;
|
||||
|
||||
beforeEach(function() {
|
||||
updateMarkerStub = sinon.stub(OCA.Comments.CommentCollection.prototype, 'updateReadMarker');
|
||||
});
|
||||
afterEach(function() {
|
||||
updateMarkerStub.restore();
|
||||
});
|
||||
|
||||
it('resets the read marker after REPORT', function() {
|
||||
testComments[0].set('isUnread', true, {silent: true});
|
||||
testComments[1].set('isUnread', true, {silent: true});
|
||||
view.collection.set(testComments);
|
||||
view.collection.trigger('sync', 'REPORT');
|
||||
|
||||
expect(updateMarkerStub.calledOnce).toEqual(true);
|
||||
expect(updateMarkerStub.lastCall.args[0]).toBeFalsy();
|
||||
});
|
||||
it('does not reset the read marker if there was no unread comments', function() {
|
||||
view.collection.set(testComments);
|
||||
view.collection.trigger('sync', 'REPORT');
|
||||
|
||||
expect(updateMarkerStub.notCalled).toEqual(true);
|
||||
});
|
||||
it('does not reset the read marker when posting comments', function() {
|
||||
testComments[0].set('isUnread', true, {silent: true});
|
||||
testComments[1].set('isUnread', true, {silent: true});
|
||||
view.collection.set(testComments);
|
||||
view.collection.trigger('sync', 'POST');
|
||||
|
||||
expect(updateMarkerStub.notCalled).toEqual(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ module.exports = function(config) {
|
|||
'apps/comments/js/app.js',
|
||||
'apps/comments/js/commentmodel.js',
|
||||
'apps/comments/js/commentcollection.js',
|
||||
'apps/comments/js/commentsummarymodel.js',
|
||||
'apps/comments/js/commentstabview.js',
|
||||
'apps/comments/js/filesplugin.js'
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in a new issue