parent
0e95b9f2d5
commit
cca33942aa
@ -0,0 +1,34 @@ |
||||
<?php |
||||
/** |
||||
* @author Vincent Petry <pvince81@owncloud.com> |
||||
* |
||||
* @copyright Copyright (c) 2016, ownCloud, Inc. |
||||
* @license AGPL-3.0 |
||||
* |
||||
* This code is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License, version 3, |
||||
* as published by the Free Software Foundation. |
||||
* |
||||
* 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, version 3, |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/> |
||||
* |
||||
*/ |
||||
|
||||
$eventDispatcher = \OC::$server->getEventDispatcher(); |
||||
$eventDispatcher->addListener( |
||||
'OCA\Files::loadAdditionalScripts', |
||||
function() { |
||||
\OCP\Util::addScript('oc-backbone-webdav'); |
||||
\OCP\Util::addScript('comments', 'app'); |
||||
\OCP\Util::addScript('comments', 'commentmodel'); |
||||
\OCP\Util::addScript('comments', 'commentcollection'); |
||||
\OCP\Util::addScript('comments', 'commentstabview'); |
||||
\OCP\Util::addScript('comments', 'filesplugin'); |
||||
\OCP\Util::addStyle('comments', 'comments'); |
||||
} |
||||
); |
@ -0,0 +1,16 @@ |
||||
<?xml version="1.0"?> |
||||
<info> |
||||
<id>comments</id> |
||||
<name>Comments</name> |
||||
<description>Files app plugin to add comments to files</description> |
||||
<licence>AGPL</licence> |
||||
<author>Arthur Shiwon, Vincent Petry</author> |
||||
<default_enable/> |
||||
<version>0.1</version> |
||||
<dependencies> |
||||
<owncloud min-version="9.0" max-version="9.0" /> |
||||
</dependencies> |
||||
<documentation> |
||||
<user>user-comments</user> |
||||
</documentation> |
||||
</info> |
@ -0,0 +1,20 @@ |
||||
/* |
||||
* Copyright (c) 2016 Vincent Petry <pvince81@owncloud.com> |
||||
* |
||||
* This file is licensed under the Affero General Public License version 3 |
||||
* or later. |
||||
* |
||||
* See the COPYING-README file. |
||||
* |
||||
*/ |
||||
|
||||
(function() { |
||||
if (!OCA.Comments) { |
||||
/** |
||||
* @namespace |
||||
*/ |
||||
OCA.Comments = {}; |
||||
} |
||||
|
||||
})(); |
||||
|
@ -0,0 +1,82 @@ |
||||
/* |
||||
* 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) { |
||||
|
||||
function filterFunction(model, term) { |
||||
return model.get('name').substr(0, term.length) === term; |
||||
} |
||||
|
||||
/** |
||||
* @class OCA.Comments.CommentsCollection |
||||
* @classdesc |
||||
* |
||||
* Collection of comments assigned to a file |
||||
* |
||||
*/ |
||||
var CommentsCollection = OC.Backbone.Collection.extend( |
||||
/** @lends OCA.Comments.CommentsCollection.prototype */ { |
||||
|
||||
sync: OC.Backbone.davSync, |
||||
|
||||
model: OCA.Comments.CommentModel, |
||||
|
||||
_objectType: 'files', |
||||
_objectId: null, |
||||
|
||||
_endReached: false, |
||||
_currentIndex: 0, |
||||
|
||||
initialize: function(models, options) { |
||||
options = options || {}; |
||||
if (options.objectType) { |
||||
this._objectType = options.objectType; |
||||
} |
||||
if (options.objectId) { |
||||
this._objectId = options.objectId; |
||||
} |
||||
}, |
||||
|
||||
url: function() { |
||||
return OC.linkToRemote('dav') + '/comments/' + |
||||
encodeURIComponent(this._objectType) + '/' + |
||||
encodeURIComponent(this._objectId) + '/'; |
||||
}, |
||||
|
||||
setObjectId: function(objectId) { |
||||
this._objectId = objectId; |
||||
}, |
||||
|
||||
hasMoreResults: function() { |
||||
return !this._endReached; |
||||
}, |
||||
|
||||
/** |
||||
* Fetch the next set of results |
||||
*/ |
||||
fetchNext: function() { |
||||
if (!this.hasMoreResults()) { |
||||
return null; |
||||
} |
||||
if (this._currentIndex === 0) { |
||||
return this.fetch(); |
||||
} |
||||
return this.fetch({remove: false}); |
||||
}, |
||||
|
||||
reset: function() { |
||||
this._currentIndex = 0; |
||||
OC.Backbone.Collection.prototype.reset.apply(this, arguments); |
||||
} |
||||
}); |
||||
|
||||
OCA.Comments.CommentsCollection = CommentsCollection; |
||||
})(OC, OCA); |
||||
|
@ -0,0 +1,47 @@ |
||||
/* |
||||
* 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.CommentModel |
||||
* @classdesc |
||||
* |
||||
* Comment |
||||
* |
||||
*/ |
||||
var CommentModel = OC.Backbone.Model.extend( |
||||
/** @lends OCA.Comments.CommentModel.prototype */ { |
||||
sync: OC.Backbone.davSync, |
||||
|
||||
defaults: { |
||||
// TODO
|
||||
}, |
||||
|
||||
davProperties: { |
||||
'id': '{' + NS_OWNCLOUD + '}id', |
||||
'message': '{' + NS_OWNCLOUD + '}message', |
||||
'actorType': '{' + NS_OWNCLOUD + '}actorType', |
||||
'actorId': '{' + NS_OWNCLOUD + '}actorId', |
||||
'actorDisplayName': '{' + NS_OWNCLOUD + '}actorDisplayName', |
||||
'creationDateTime': '{' + NS_OWNCLOUD + '}creationDateTime', |
||||
'objectType': '{' + NS_OWNCLOUD + '}objectType', |
||||
'objectId': '{' + NS_OWNCLOUD + '}objectId' |
||||
}, |
||||
|
||||
parse: function(data) { |
||||
// TODO: parse non-string values
|
||||
return data; |
||||
} |
||||
}); |
||||
|
||||
OCA.Comments.CommentModel = CommentModel; |
||||
})(OC, OCA); |
||||
|
@ -0,0 +1,166 @@ |
||||
/* |
||||
* Copyright (c) 2016 |
||||
* |
||||
* This file is licensed under the Affero General Public License version 3 |
||||
* or later. |
||||
* |
||||
* See the COPYING-README file. |
||||
* |
||||
*/ |
||||
|
||||
(function() { |
||||
var TEMPLATE = |
||||
'<div>' + |
||||
' <form class="newCommentForm">' + |
||||
' <textarea></textarea>' + |
||||
' <input type="submit" value="{{submitText}}" />' + |
||||
' </form>' + |
||||
' <ul class="comments">' + |
||||
' </ul>' + |
||||
'</div>' + |
||||
'<div class="empty hidden">{{emptyResultLabel}}</div>' + |
||||
/* |
||||
'<input type="button" class="showMore hidden" value="{{moreLabel}}"' + |
||||
' name="show-more" id="show-more" />' + |
||||
*/ |
||||
'<div class="loading hidden" style="height: 50px"></div>'; |
||||
|
||||
var COMMENT_TEMPLATE = |
||||
'<li>' + |
||||
' <hr />' + |
||||
' <div class="authorRow">' + |
||||
' <span class="author"><em>{{actorDisplayName}}</em></span>' + |
||||
' <span class="date">{{creationDateTime}}</span>' + |
||||
' </div>' + |
||||
' <div class="message">{{message}}</div>' + |
||||
'</li>'; |
||||
|
||||
/** |
||||
* @memberof OCA.Comments |
||||
*/ |
||||
var CommentsTabView = OCA.Files.DetailTabView.extend( |
||||
/** @lends OCA.Comments.CommentsTabView.prototype */ { |
||||
id: 'commentsTabView', |
||||
className: 'tab commentsTabView', |
||||
|
||||
events: { |
||||
'submit .newCommentForm': '_onSubmitComment' |
||||
}, |
||||
|
||||
initialize: function() { |
||||
OCA.Files.DetailTabView.prototype.initialize.apply(this, arguments); |
||||
this.collection = new OCA.Comments.CommentsCollection(); |
||||
this.collection.on('request', this._onRequest, this); |
||||
this.collection.on('sync', this._onEndRequest, this); |
||||
this.collection.on('add', this._onAddModel, this); |
||||
// TODO: error handling
|
||||
_.bindAll(this, '_onSubmitComment'); |
||||
}, |
||||
|
||||
template: function(params) { |
||||
if (!this._template) { |
||||
this._template = Handlebars.compile(TEMPLATE); |
||||
} |
||||
return this._template(_.extend({ |
||||
submitText: t('comments', 'Submit comment') |
||||
}, params)); |
||||
}, |
||||
|
||||
commentTemplate: function(params) { |
||||
if (!this._commentTemplate) { |
||||
this._commentTemplate = Handlebars.compile(COMMENT_TEMPLATE); |
||||
} |
||||
return this._commentTemplate(params); |
||||
}, |
||||
|
||||
getLabel: function() { |
||||
return t('comments', 'Comments'); |
||||
}, |
||||
|
||||
setFileInfo: function(fileInfo) { |
||||
if (fileInfo) { |
||||
this.render(); |
||||
this.collection.setObjectId(fileInfo.id); |
||||
// reset to first page
|
||||
this.collection.reset([], {silent: true}); |
||||
this.nextPage(); |
||||
} else { |
||||
this.render(); |
||||
this.collection.reset(); |
||||
} |
||||
}, |
||||
|
||||
render: function() { |
||||
this.$el.html(this.template({ |
||||
emptyResultLabel: t('comments', 'No other comments available'), |
||||
moreLabel: t('comments', 'More comments...') |
||||
})); |
||||
this.$el.find('.has-tooltip').tooltip(); |
||||
this.$container = this.$el.find('ul.comments'); |
||||
this.delegateEvents(); |
||||
}, |
||||
|
||||
_formatItem: function(commentModel) { |
||||
// TODO: format
|
||||
return commentModel.attributes; |
||||
}, |
||||
|
||||
_toggleLoading: function(state) { |
||||
this._loading = state; |
||||
this.$el.find('.loading').toggleClass('hidden', !state); |
||||
}, |
||||
|
||||
_onRequest: function() { |
||||
this._toggleLoading(true); |
||||
this.$el.find('.showMore').addClass('hidden'); |
||||
}, |
||||
|
||||
_onEndRequest: function() { |
||||
this._toggleLoading(false); |
||||
this.$el.find('.empty').toggleClass('hidden', !!this.collection.length); |
||||
this.$el.find('.showMore').toggleClass('hidden', !this.collection.hasMoreResults()); |
||||
}, |
||||
|
||||
_onAddModel: function(model, collection, options) { |
||||
var $el = $(this.commentTemplate(this._formatItem(model))); |
||||
if (!_.isUndefined(options.at) && collection.length > 1) { |
||||
this.$container.find('li').eq(options.at).before($el); |
||||
} else { |
||||
this.$container.append($el); |
||||
} |
||||
}, |
||||
|
||||
nextPage: function() { |
||||
if (this._loading || !this.collection.hasMoreResults()) { |
||||
return; |
||||
} |
||||
|
||||
this.collection.fetchNext(); |
||||
}, |
||||
|
||||
_onClickShowMoreVersions: function(ev) { |
||||
ev.preventDefault(); |
||||
this.nextPage(); |
||||
}, |
||||
|
||||
_onSubmitComment: function(e) { |
||||
var $textArea = $(e.target).find('textarea'); |
||||
e.preventDefault(); |
||||
this.collection.create({ |
||||
actorId: OC.currentUser, |
||||
// FIXME: how to get current user's display name ?
|
||||
actorDisplayName: OC.currentUser, |
||||
actorType: 'users', |
||||
verb: 'comment', |
||||
message: $textArea.val() |
||||
}, {at: 0}); |
||||
|
||||
// TODO: spinner/disable field?
|
||||
$textArea.val(''); |
||||
return false; |
||||
} |
||||
}); |
||||
|
||||
OCA.Comments.CommentsTabView = CommentsTabView; |
||||
})(); |
||||
|
@ -0,0 +1,41 @@ |
||||
/* |
||||
* Copyright (c) 2016 Vincent Petry <pvince81@owncloud.com> |
||||
* |
||||
* This file is licensed under the Affero General Public License version 3 |
||||
* or later. |
||||
* |
||||
* See the COPYING-README file. |
||||
* |
||||
*/ |
||||
|
||||
(function() { |
||||
OCA.Comments = _.extend({}, OCA.Comments); |
||||
if (!OCA.Comments) { |
||||
/** |
||||
* @namespace |
||||
*/ |
||||
OCA.Comments = {}; |
||||
} |
||||
|
||||
/** |
||||
* @namespace |
||||
*/ |
||||
OCA.Comments.FilesPlugin = { |
||||
allowedLists: [ |
||||
'files', |
||||
'favorites' |
||||
], |
||||
|
||||
attach: function(fileList) { |
||||
if (this.allowedLists.indexOf(fileList.id) < 0) { |
||||
return; |
||||
} |
||||
|
||||
fileList.registerTabView(new OCA.Comments.CommentsTabView('commentsTabView')); |
||||
} |
||||
}; |
||||
|
||||
})(); |
||||
|
||||
OC.Plugins.register('OCA.Files.FileList', OCA.Comments.FilesPlugin); |
||||
|
Loading…
Reference in new issue