diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..b86372955e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,12 @@ +module.exports = { + globals: { + __webpack_nonce__: true, + __webpack_public_path__: true, + _: true, + $: true, + moment: true, + escapeHTML: true, + oc_userconfig: true + }, + extends: ['nextcloud'] +} diff --git a/Makefile b/Makefile index 6707760263..a3e1d4eab6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ all: clean dev-setup build-js-production -dev-setup: clean-dev npm-init +# Dev env management +dev-setup: clean clean-dev npm-init npm-init: npm install @@ -8,6 +9,7 @@ npm-init: npm-update: npm update +# Building build-js: npm run dev @@ -17,9 +19,14 @@ build-js-production: watch-js: npm run watch -clean-dev: - rm -rf node_modules +# Linting +lint-fix: + npm run lint:fix +lint-fix-watch: + npm run lint:fix-watch + +# Cleaning clean: rm -rf apps/accessibility/js/ rm -rf apps/comments/js/ @@ -27,12 +34,15 @@ clean: rm -rf apps/files_trashbin/js/ rm -rf apps/files_versions/js/ rm -rf apps/oauth2/js/ + rm -rf apps/settings/js/vue-* rm -rf apps/systemtags/js/systemtags.* rm -rf apps/twofactor_backupcodes/js rm -rf apps/updatenotification/js/updatenotification.* rm -rf apps/workflowengine/js/ rm -rf core/js/dist - rm -rf settings/js/vue-* + +clean-dev: + rm -rf node_modules clean-git: clean git checkout -- apps/accessibility/js/ @@ -41,9 +51,9 @@ clean-git: clean git checkout -- apps/files_trashbin/js/ git checkout -- apps/files_versions/js/ git checkout -- apps/oauth2/js/ + git checkout -- apps/settings/js/vue-* git checkout -- apps/systemtags/js/systemtags.* git checkout -- apps/twofactor_backupcodes/js git checkout -- apps/updatenotification/js/updatenotification.* git checkout -- apps/workflowengine/js/ git checkout -- core/js/dist - git checkout -- settings/js/vue-* diff --git a/apps/accessibility/.eslintrc.js b/apps/accessibility/.eslintrc.js deleted file mode 100644 index 2cc3899a0c..0000000000 --- a/apps/accessibility/.eslintrc.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - env: { - browser: true, - es6: true - }, - extends: 'eslint:recommended', - parserOptions: { - sourceType: 'module' - }, - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'] - } -}; diff --git a/apps/accessibility/js/accessibility.js b/apps/accessibility/js/accessibility.js index 6e0b9c3958..af132e1a3c 100644 Binary files a/apps/accessibility/js/accessibility.js and b/apps/accessibility/js/accessibility.js differ diff --git a/apps/accessibility/js/accessibility.js.map b/apps/accessibility/js/accessibility.js.map index cafc3dd859..51fc6eb16d 100644 Binary files a/apps/accessibility/js/accessibility.js.map and b/apps/accessibility/js/accessibility.js.map differ diff --git a/apps/accessibility/src/App.vue b/apps/accessibility/src/Accessibility.vue similarity index 60% rename from apps/accessibility/src/App.vue rename to apps/accessibility/src/Accessibility.vue index 7fdc54af66..56592103d5 100644 --- a/apps/accessibility/src/App.vue +++ b/apps/accessibility/src/Accessibility.vue @@ -1,60 +1,56 @@ diff --git a/apps/accessibility/src/components/ItemPreview.vue b/apps/accessibility/src/components/ItemPreview.vue new file mode 100644 index 0000000000..66f751b37d --- /dev/null +++ b/apps/accessibility/src/components/ItemPreview.vue @@ -0,0 +1,40 @@ + + + diff --git a/apps/accessibility/src/components/itemPreview.vue b/apps/accessibility/src/components/itemPreview.vue deleted file mode 100644 index 7f4e17b16f..0000000000 --- a/apps/accessibility/src/components/itemPreview.vue +++ /dev/null @@ -1,28 +0,0 @@ - - - diff --git a/apps/accessibility/src/main.js b/apps/accessibility/src/main.js index 5d9b2a2d0a..618f4a7355 100644 --- a/apps/accessibility/src/main.js +++ b/apps/accessibility/src/main.js @@ -1,12 +1,12 @@ -import Vue from 'vue'; -import App from './App.vue'; +import Vue from 'vue' +import App from './Accessibility.vue' /* global t */ // bind to window -Vue.prototype.OC = OC; -Vue.prototype.t = t; +Vue.prototype.OC = OC +Vue.prototype.t = t -new Vue({ +export default new Vue({ el: '#accessibility', render: h => h(App) -}); +}) diff --git a/apps/comments/js/comments.js b/apps/comments/js/comments.js index 179f31d95f..0af7b54d60 100644 Binary files a/apps/comments/js/comments.js and b/apps/comments/js/comments.js differ diff --git a/apps/comments/js/comments.js.map b/apps/comments/js/comments.js.map index f14874b52f..bbd2e6954c 100644 Binary files a/apps/comments/js/comments.js.map and b/apps/comments/js/comments.js.map differ diff --git a/apps/comments/src/activitytabviewplugin.js b/apps/comments/src/activitytabviewplugin.js index b6195b80c4..2afee4c2be 100644 --- a/apps/comments/src/activitytabviewplugin.js +++ b/apps/comments/src/activitytabviewplugin.js @@ -1,4 +1,4 @@ -/* +/** * @author Joas Schilling * Copyright (c) 2016 * @@ -18,18 +18,18 @@ * @param {jQuery} $el jQuery handle for this activity * @param {string} view The view that displayes this activity */ - prepareModelForDisplay: function (model, $el, view) { + prepareModelForDisplay: function(model, $el, view) { if (model.get('app') !== 'comments' || model.get('type') !== 'comments') { - return; + return } if (view === 'ActivityTabView') { - $el.addClass('comment'); + $el.addClass('comment') if (model.get('message') && this._isLong(model.get('message'))) { - $el.addClass('collapsed'); - var $overlay = $('
').addClass('message-overlay'); - $el.find('.activitymessage').after($overlay); - $el.on('click', this._onClickCollapsedComment); + $el.addClass('collapsed') + var $overlay = $('
').addClass('message-overlay') + $el.find('.activitymessage').after($overlay) + $el.on('click', this._onClickCollapsedComment) } } }, @@ -38,22 +38,21 @@ * Copy of CommentsTabView._onClickComment() */ _onClickCollapsedComment: function(ev) { - var $row = $(ev.target); + var $row = $(ev.target) if (!$row.is('.comment')) { - $row = $row.closest('.comment'); + $row = $row.closest('.comment') } - $row.removeClass('collapsed'); + $row.removeClass('collapsed') }, /* * Copy of CommentsTabView._isLong() */ _isLong: function(message) { - return message.length > 250 || (message.match(/\n/g) || []).length > 1; + return message.length > 250 || (message.match(/\n/g) || []).length > 1 } - }; + } +})() -})(); - -OC.Plugins.register('OCA.Activity.RenderingPlugins', OCA.Comments.ActivityTabViewPlugin); +OC.Plugins.register('OCA.Activity.RenderingPlugins', OCA.Comments.ActivityTabViewPlugin) diff --git a/apps/comments/src/app.js b/apps/comments/src/app.js index 547059393a..626d7703a3 100644 --- a/apps/comments/src/app.js +++ b/apps/comments/src/app.js @@ -13,8 +13,7 @@ /** * @namespace */ - OCA.Comments = {}; + OCA.Comments = {} } -})(); - +})() diff --git a/apps/comments/src/commentcollection.js b/apps/comments/src/commentcollection.js index a15039cf48..8e7f9e37d5 100644 --- a/apps/comments/src/commentcollection.js +++ b/apps/comments/src/commentcollection.js @@ -1,3 +1,4 @@ +/* eslint-disable */ /* * Copyright (c) 2016 * @@ -20,148 +21,147 @@ var CommentCollection = OC.Backbone.Collection.extend( /** @lends OCA.Comments.CommentCollection.prototype */ { - sync: OC.Backbone.davSync, + sync: OC.Backbone.davSync, - model: OCA.Comments.CommentModel, + model: OCA.Comments.CommentModel, - /** + /** * Object type * * @type string */ - _objectType: 'files', + _objectType: 'files', - /** + /** * Object id * * @type string */ - _objectId: null, + _objectId: null, - /** + /** * True if there are no more page results left to fetch * * @type bool */ - _endReached: false, + _endReached: false, - /** + /** * Number of comments to fetch per page * * @type int */ - _limit : 20, + _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) { - this._objectType = options.objectType; - } - if (options.objectId) { - this._objectId = options.objectId; - } - }, + 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) + '/'; - }, + url: function() { + return OC.linkToRemote('dav') + '/comments/' + + encodeURIComponent(this._objectType) + '/' + + encodeURIComponent(this._objectId) + '/' + }, - setObjectId: function(objectId) { - this._objectId = objectId; - }, + setObjectId: function(objectId) { + this._objectId = objectId + }, - hasMoreResults: function() { - return !this._endReached; - }, + hasMoreResults: function() { + return !this._endReached + }, - reset: function() { - this._endReached = false; - this._summaryModel = null; - return OC.Backbone.Collection.prototype.reset.apply(this, arguments); - }, + reset: function() { + this._endReached = false + this._summaryModel = null + return OC.Backbone.Collection.prototype.reset.apply(this, arguments) + }, - /** + /** * Fetch the next set of results */ - fetchNext: function(options) { - var self = this; - if (!this.hasMoreResults()) { - return null; - } - - var body = '\n' + - '\n' + - // load one more so we know there is more - ' ' + (this._limit + 1) + '\n' + - ' ' + this.length + '\n' + - '\n'; - - options = options || {}; - var success = options.success; - options = _.extend({ - remove: false, - parse: true, - data: body, - davProperties: CommentCollection.prototype.model.prototype.davProperties, - success: function(resp) { - if (resp.length <= self._limit) { - // no new entries, end reached - self._endReached = true; - } else { - // remove last entry, for next page load - resp = _.initial(resp); - } - if (!self.set(resp, options)) { - return false; - } - if (success) { - success.apply(null, arguments); - } - self.trigger('sync', 'REPORT', self, options); + fetchNext: function(options) { + var self = this + if (!this.hasMoreResults()) { + return null } - }, options); - return this.sync('REPORT', this, options); - }, + var body = '\n' + + '\n' + // load one more so we know there is more + + ' ' + (this._limit + 1) + '\n' + + ' ' + this.length + '\n' + + '\n' - /** + options = options || {} + var success = options.success + options = _.extend({ + remove: false, + parse: true, + data: body, + davProperties: CommentCollection.prototype.model.prototype.davProperties, + success: function(resp) { + if (resp.length <= self._limit) { + // no new entries, end reached + self._endReached = true + } else { + // remove last entry, for next page load + resp = _.initial(resp) + } + if (!self.set(resp, options)) { + return false + } + if (success) { + success.apply(null, arguments) + } + self.trigger('sync', 'REPORT', self, options) + } + }, options) + + return this.sync('REPORT', this, options) + }, + + /** * Returns the matching summary model * - * @return {OCA.Comments.CommentSummaryModel} summary model + * @returns {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; - }, + 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 || {}; + updateReadMarker: function(date, options) { + options = options || {} - return this.getSummaryModel().save({ - readMarker: (date || new Date()).toUTCString() - }, options); - } - }); - - OCA.Comments.CommentCollection = CommentCollection; -})(OC, OCA); + return this.getSummaryModel().save({ + readMarker: (date || new Date()).toUTCString() + }, options) + } + }) + OCA.Comments.CommentCollection = CommentCollection +})(OC, OCA) diff --git a/apps/comments/src/commentmodel.js b/apps/comments/src/commentmodel.js index 3711e53c9f..804fbdfd3c 100644 --- a/apps/comments/src/commentmodel.js +++ b/apps/comments/src/commentmodel.js @@ -12,7 +12,7 @@ _.extend(OC.Files.Client, { PROPERTY_FILEID: '{' + OC.Files.Client.NS_OWNCLOUD + '}id', - PROPERTY_MESSAGE: '{' + OC.Files.Client.NS_OWNCLOUD + '}message', + PROPERTY_MESSAGE: '{' + OC.Files.Client.NS_OWNCLOUD + '}message', PROPERTY_ACTORTYPE: '{' + OC.Files.Client.NS_OWNCLOUD + '}actorType', PROPERTY_ACTORID: '{' + OC.Files.Client.NS_OWNCLOUD + '}actorId', PROPERTY_ISUNREAD: '{' + OC.Files.Client.NS_OWNCLOUD + '}isUnread', @@ -21,7 +21,7 @@ PROPERTY_ACTORDISPLAYNAME: '{' + OC.Files.Client.NS_OWNCLOUD + '}actorDisplayName', PROPERTY_CREATIONDATETIME: '{' + OC.Files.Client.NS_OWNCLOUD + '}creationDateTime', PROPERTY_MENTIONS: '{' + OC.Files.Client.NS_OWNCLOUD + '}mentions' - }); + }) /** * @class OCA.Comments.CommentModel @@ -32,62 +32,62 @@ */ var CommentModel = OC.Backbone.Model.extend( /** @lends OCA.Comments.CommentModel.prototype */ { - sync: OC.Backbone.davSync, + sync: OC.Backbone.davSync, - defaults: { - actorType: 'users', - objectType: 'files' - }, + defaults: { + actorType: 'users', + objectType: 'files' + }, - davProperties: { - 'id': OC.Files.Client.PROPERTY_FILEID, - 'message': OC.Files.Client.PROPERTY_MESSAGE, - 'actorType': OC.Files.Client.PROPERTY_ACTORTYPE, - 'actorId': OC.Files.Client.PROPERTY_ACTORID, - 'actorDisplayName': OC.Files.Client.PROPERTY_ACTORDISPLAYNAME, - 'creationDateTime': OC.Files.Client.PROPERTY_CREATIONDATETIME, - 'objectType': OC.Files.Client.PROPERTY_OBJECTTYPE, - 'objectId': OC.Files.Client.PROPERTY_OBJECTID, - 'isUnread': OC.Files.Client.PROPERTY_ISUNREAD, - 'mentions': OC.Files.Client.PROPERTY_MENTIONS - }, + davProperties: { + 'id': OC.Files.Client.PROPERTY_FILEID, + 'message': OC.Files.Client.PROPERTY_MESSAGE, + 'actorType': OC.Files.Client.PROPERTY_ACTORTYPE, + 'actorId': OC.Files.Client.PROPERTY_ACTORID, + 'actorDisplayName': OC.Files.Client.PROPERTY_ACTORDISPLAYNAME, + 'creationDateTime': OC.Files.Client.PROPERTY_CREATIONDATETIME, + 'objectType': OC.Files.Client.PROPERTY_OBJECTTYPE, + 'objectId': OC.Files.Client.PROPERTY_OBJECTID, + 'isUnread': OC.Files.Client.PROPERTY_ISUNREAD, + 'mentions': OC.Files.Client.PROPERTY_MENTIONS + }, - parse: function(data) { - return { - id: data.id, - message: data.message, - actorType: data.actorType, - actorId: data.actorId, - actorDisplayName: data.actorDisplayName, - creationDateTime: data.creationDateTime, - objectType: data.objectType, - objectId: data.objectId, - isUnread: (data.isUnread === 'true'), - mentions: this._parseMentions(data.mentions) - }; - }, - - _parseMentions: function(mentions) { - if(_.isUndefined(mentions)) { - return {}; - } - var result = {}; - for(var i in mentions) { - var mention = mentions[i]; - if(_.isUndefined(mention.localName) || mention.localName !== 'mention') { - continue; + parse: function(data) { + return { + id: data.id, + message: data.message, + actorType: data.actorType, + actorId: data.actorId, + actorDisplayName: data.actorDisplayName, + creationDateTime: data.creationDateTime, + objectType: data.objectType, + objectId: data.objectId, + isUnread: (data.isUnread === 'true'), + mentions: this._parseMentions(data.mentions) } - result[i] = {}; - for (var child = mention.firstChild; child; child = child.nextSibling) { - if(_.isUndefined(child.localName) || !child.localName.startsWith('mention')) { - continue; + }, + + _parseMentions: function(mentions) { + if (_.isUndefined(mentions)) { + return {} + } + var result = {} + for (var i in mentions) { + var mention = mentions[i] + if (_.isUndefined(mention.localName) || mention.localName !== 'mention') { + continue + } + result[i] = {} + for (var child = mention.firstChild; child; child = child.nextSibling) { + if (_.isUndefined(child.localName) || !child.localName.startsWith('mention')) { + continue + } + result[i][child.localName] = child.textContent } - result[i][child.localName] = child.textContent; } + return result } - return result; - } - }); + }) - OCA.Comments.CommentModel = CommentModel; -})(OC, OCA); + OCA.Comments.CommentModel = CommentModel +})(OC, OCA) diff --git a/apps/comments/src/comments.js b/apps/comments/src/comments.js index f0d4433674..e632936c77 100644 --- a/apps/comments/src/comments.js +++ b/apps/comments/src/comments.js @@ -15,4 +15,4 @@ import './vendor/At.js/dist/js/jquery.atwho.min' import './style/autocomplete.scss' import './style/comments.scss' -window.OCA.Comments = OCA.Comments; +window.OCA.Comments = OCA.Comments diff --git a/apps/comments/src/commentsmodifymenu.js b/apps/comments/src/commentsmodifymenu.js index 2640dcf420..7c9470f13b 100644 --- a/apps/comments/src/commentsmodifymenu.js +++ b/apps/comments/src/commentsmodifymenu.js @@ -8,7 +8,6 @@ * */ -/* global Handlebars */ (function() { /** @@ -23,7 +22,7 @@ _scopes: [ { name: 'edit', - displayName: t('comments', 'Edit comment'), + displayName: t('comments', 'Edit comment'), iconClass: 'icon-rename' }, { @@ -45,14 +44,14 @@ * @param {Object} event event object */ _onClickAction: function(event) { - var $target = $(event.currentTarget); + var $target = $(event.currentTarget) if (!$target.hasClass('menuitem')) { - $target = $target.closest('.menuitem'); + $target = $target.closest('.menuitem') } - OC.hideMenus(); + OC.hideMenus() - this.trigger('select:menu-item-clicked', event, $target.data('action')); + this.trigger('select:menu-item-clicked', event, $target.data('action')) }, /** @@ -61,49 +60,49 @@ render: function() { this.$el.html(OCA.Comments.Templates['commentsmodifymenu']({ items: this._scopes - })); + })) }, /** * Displays the menu + * @param {Event} context the click event */ show: function(context) { - this._context = context; + this._context = context - for(var i in this._scopes) { - this._scopes[i].active = false; + for (var i in this._scopes) { + this._scopes[i].active = false } - - var $el = $(context.target); - var offsetIcon = $el.offset(); - var offsetContainer = $el.closest('.authorRow').offset(); + var $el = $(context.target) + var offsetIcon = $el.offset() + var offsetContainer = $el.closest('.authorRow').offset() // adding some extra top offset to push the menu below the button. var position = { top: offsetIcon.top - offsetContainer.top + 48, left: '', right: '' - }; + } - position.left = offsetIcon.left - offsetContainer.left; + position.left = offsetIcon.left - offsetContainer.left if (position.left > 200) { // we need to position the menu to the right. - position.left = ''; - position.right = this.$el.closest('.comment').find('.date').width(); - this.$el.removeClass('menu-left').addClass('menu-right'); + position.left = '' + position.right = this.$el.closest('.comment').find('.date').width() + this.$el.removeClass('menu-left').addClass('menu-right') } else { - this.$el.removeClass('menu-right').addClass('menu-left'); + this.$el.removeClass('menu-right').addClass('menu-left') } - this.$el.css(position); - this.render(); - this.$el.removeClass('hidden'); + this.$el.css(position) + this.render() + this.$el.removeClass('hidden') - OC.showMenu(null, this.$el); + OC.showMenu(null, this.$el) } - }); + }) - OCA.Comments = OCA.Comments || {}; - OCA.Comments.CommentsModifyMenu = CommentsModifyMenu; -})(OC, OCA); + OCA.Comments = OCA.Comments || {} + OCA.Comments.CommentsModifyMenu = CommentsModifyMenu +})(OC, OCA) diff --git a/apps/comments/src/commentstabview.js b/apps/comments/src/commentstabview.js index 8b71fc1f87..a638f46a2c 100644 --- a/apps/comments/src/commentstabview.js +++ b/apps/comments/src/commentstabview.js @@ -1,3 +1,4 @@ +/* eslint-disable */ /* * Copyright (c) 2016 * @@ -17,252 +18,252 @@ */ var CommentsTabView = OCA.Files.DetailTabView.extend( /** @lends OCA.Comments.CommentsTabView.prototype */ { - id: 'commentsTabView', - className: 'tab commentsTabView', - _autoCompleteData: undefined, - _commentsModifyMenu: undefined, + id: 'commentsTabView', + className: 'tab commentsTabView', + _autoCompleteData: undefined, + _commentsModifyMenu: undefined, - events: { - 'submit .newCommentForm': '_onSubmitComment', - 'click .showMore': '_onClickShowMore', - 'click .cancel': '_onClickCloseComment', - 'click .comment': '_onClickComment', - 'keyup div.message': '_onTextChange', - 'change div.message': '_onTextChange', - 'input div.message': '_onTextChange', - 'paste div.message': '_onPaste' - }, + events: { + 'submit .newCommentForm': '_onSubmitComment', + 'click .showMore': '_onClickShowMore', + 'click .cancel': '_onClickCloseComment', + 'click .comment': '_onClickComment', + 'keyup div.message': '_onTextChange', + 'change div.message': '_onTextChange', + 'input div.message': '_onTextChange', + 'paste div.message': '_onPaste' + }, - _commentMaxLength: 1000, + _commentMaxLength: 1000, - initialize: function() { - OCA.Files.DetailTabView.prototype.initialize.apply(this, arguments); - this.collection = new OCA.Comments.CommentCollection(); - this.collection.on('request', this._onRequest, this); - this.collection.on('sync', this._onEndRequest, this); - this.collection.on('add', this._onAddModel, this); - this.collection.on('change:message', this._onChangeModel, this); + initialize: function() { + OCA.Files.DetailTabView.prototype.initialize.apply(this, arguments) + this.collection = new OCA.Comments.CommentCollection() + this.collection.on('request', this._onRequest, this) + this.collection.on('sync', this._onEndRequest, this) + this.collection.on('add', this._onAddModel, this) + this.collection.on('change:message', this._onChangeModel, this) - this._commentMaxThreshold = this._commentMaxLength * 0.9; + this._commentMaxThreshold = this._commentMaxLength * 0.9 - // TODO: error handling - _.bindAll(this, '_onTypeComment', '_initAutoComplete', '_onAutoComplete'); - }, + // TODO: error handling + _.bindAll(this, '_onTypeComment', '_initAutoComplete', '_onAutoComplete') + }, - template: function(params) { - var currentUser = OC.getCurrentUser(); - return OCA.Comments.Templates['view'](_.extend({ - actorId: currentUser.uid, - actorDisplayName: currentUser.displayName - }, params)); - }, + template: function(params) { + var currentUser = OC.getCurrentUser() + return OCA.Comments.Templates['view'](_.extend({ + actorId: currentUser.uid, + actorDisplayName: currentUser.displayName + }, params)) + }, - editCommentTemplate: function(params) { - var currentUser = OC.getCurrentUser(); - return OCA.Comments.Templates['edit_comment'](_.extend({ - actorId: currentUser.uid, - actorDisplayName: currentUser.displayName, - newMessagePlaceholder: t('comments', 'New comment …'), - submitText: t('comments', 'Post'), - cancelText: t('comments', 'Cancel'), - tag: 'li' - }, params)); - }, + editCommentTemplate: function(params) { + var currentUser = OC.getCurrentUser() + return OCA.Comments.Templates['edit_comment'](_.extend({ + actorId: currentUser.uid, + actorDisplayName: currentUser.displayName, + newMessagePlaceholder: t('comments', 'New comment …'), + submitText: t('comments', 'Post'), + cancelText: t('comments', 'Cancel'), + tag: 'li' + }, params)) + }, - commentTemplate: function(params) { - params = _.extend({ - editTooltip: t('comments', 'Edit comment'), - isUserAuthor: OC.getCurrentUser().uid === params.actorId, - isLong: this._isLong(params.message) - }, params); + commentTemplate: function(params) { + params = _.extend({ + editTooltip: t('comments', 'Edit comment'), + isUserAuthor: OC.getCurrentUser().uid === params.actorId, + isLong: this._isLong(params.message) + }, params) - if (params.actorType === 'deleted_users') { + if (params.actorType === 'deleted_users') { // makes the avatar a X - params.actorId = null; - params.actorDisplayName = t('comments', '[Deleted user]'); - } + params.actorId = null + params.actorDisplayName = t('comments', '[Deleted user]') + } - return OCA.Comments.Templates['comment'](params); - }, + return OCA.Comments.Templates['comment'](params) + }, - getLabel: function() { - return t('comments', 'Comments'); - }, + getLabel: function() { + return t('comments', 'Comments') + }, - getIcon: function() { - return 'icon-comment'; - }, + getIcon: function() { + return 'icon-comment' + }, - setFileInfo: function(fileInfo) { - if (fileInfo) { - this.model = fileInfo; + setFileInfo: function(fileInfo) { + if (fileInfo) { + this.model = fileInfo - this.render(); - this._initAutoComplete($('#commentsTabView').find('.newCommentForm .message')); - this.collection.setObjectId(this.model.id); - // reset to first page - this.collection.reset([], {silent: true}); - this.nextPage(); - } else { - this.model = null; - this.render(); - this.collection.reset(); - } - }, + this.render() + this._initAutoComplete($('#commentsTabView').find('.newCommentForm .message')) + this.collection.setObjectId(this.model.id) + // reset to first page + this.collection.reset([], { silent: true }) + this.nextPage() + } else { + this.model = null + this.render() + this.collection.reset() + } + }, - render: function() { - this.$el.html(this.template({ - emptyResultLabel: t('comments', 'No comments yet, start the conversation!'), - moreLabel: t('comments', 'More comments …') - })); - this.$el.find('.comments').before(this.editCommentTemplate({ tag: 'div'})); - this.$el.find('.has-tooltip').tooltip(); - this.$container = this.$el.find('ul.comments'); - this.$el.find('.avatar').avatar(OC.getCurrentUser().uid, 32); - this.delegateEvents(); - this.$el.find('.message').on('keydown input change', this._onTypeComment); + render: function() { + this.$el.html(this.template({ + emptyResultLabel: t('comments', 'No comments yet, start the conversation!'), + moreLabel: t('comments', 'More comments …') + })) + this.$el.find('.comments').before(this.editCommentTemplate({ tag: 'div' })) + this.$el.find('.has-tooltip').tooltip() + this.$container = this.$el.find('ul.comments') + this.$el.find('.avatar').avatar(OC.getCurrentUser().uid, 32) + this.delegateEvents() + this.$el.find('.message').on('keydown input change', this._onTypeComment) - autosize(this.$el.find('.newCommentRow .message')) - this.$el.find('.newCommentForm .message').focus(); - }, + autosize(this.$el.find('.newCommentRow .message')) + this.$el.find('.newCommentForm .message').focus() + }, - _initAutoComplete: function($target) { - var s = this; - var limit = 10; - if(!_.isUndefined(OC.appConfig.comments)) { - limit = OC.appConfig.comments.maxAutoCompleteResults; - } - $target.atwho({ - at: '@', - limit: limit, - callbacks: { - remoteFilter: s._onAutoComplete, - highlighter: function (li) { + _initAutoComplete: function($target) { + var s = this + var limit = 10 + if (!_.isUndefined(OC.appConfig.comments)) { + limit = OC.appConfig.comments.maxAutoCompleteResults + } + $target.atwho({ + at: '@', + limit: limit, + callbacks: { + remoteFilter: s._onAutoComplete, + highlighter: function(li) { // misuse the highlighter callback to instead of // highlighting loads the avatars. - var $li = $(li); - $li.find('.avatar').avatar(undefined, 32); - return $li; + var $li = $(li) + $li.find('.avatar').avatar(undefined, 32) + return $li + }, + sorter: function(q, items) { return items } }, - sorter: function (q, items) { return items; } - }, - displayTpl: function (item) { - return '
  • ' + - '' + - '' + - '' + - '' + escapeHTML(item.label) + '' + - '
  • '; - }, - insertTpl: function (item) { - return '' + - '' + - '' + - '' + - '' + escapeHTML(item.label) + '' + - ''; - }, - searchKey: "label" - }); - $target.on('inserted.atwho', function (je, $el) { - var editionMode = true; - s._postRenderItem( + displayTpl: function(item) { + return '
  • ' + + '' + + '' + + '' + + '' + escapeHTML(item.label) + '' + + '
  • ' + }, + insertTpl: function(item) { + return '' + + '' + + '' + + '' + + '' + escapeHTML(item.label) + '' + + '' + }, + searchKey: 'label' + }) + $target.on('inserted.atwho', function(je, $el) { + var editionMode = true + s._postRenderItem( // we need to pass the parent of the inserted element // passing the whole comments form would re-apply and request // avatars from the server - $(je.target).find( - 'span[data-username="' + $el.find('[data-username]').data('username') + '"]' - ).parent(), - editionMode - ); - }); - }, + $(je.target).find( + 'span[data-username="' + $el.find('[data-username]').data('username') + '"]' + ).parent(), + editionMode + ) + }) + }, - _onAutoComplete: function(query, callback) { - var s = this; - if(!_.isUndefined(this._autoCompleteRequestTimer)) { - clearTimeout(this._autoCompleteRequestTimer); - } - this._autoCompleteRequestTimer = _.delay(function() { - if(!_.isUndefined(this._autoCompleteRequestCall)) { - this._autoCompleteRequestCall.abort(); + _onAutoComplete: function(query, callback) { + var s = this + if (!_.isUndefined(this._autoCompleteRequestTimer)) { + clearTimeout(this._autoCompleteRequestTimer) } - this._autoCompleteRequestCall = $.ajax({ - url: OC.linkToOCS('core', 2) + 'autocomplete/get', - data: { - search: query, - itemType: 'files', - itemId: s.model.get('id'), - sorter: 'commenters|share-recipients', - limit: OC.appConfig.comments.maxAutoCompleteResults - }, - beforeSend: function (request) { - request.setRequestHeader('Accept', 'application/json'); - }, - success: function (result) { - callback(result.ocs.data); + this._autoCompleteRequestTimer = _.delay(function() { + if (!_.isUndefined(this._autoCompleteRequestCall)) { + this._autoCompleteRequestCall.abort() } - }); - }, 400); - }, - - _formatItem: function(commentModel) { - var timestamp = new Date(commentModel.get('creationDateTime')).getTime(); - var data = _.extend({ - timestamp: timestamp, - date: OC.Util.relativeModifiedDate(timestamp), - altDate: OC.Util.formatDate(timestamp), - formattedMessage: this._formatMessage(commentModel.get('message'), commentModel.get('mentions')) - }, commentModel.attributes); - return data; - }, - - _toggleLoading: function(state) { - this._loading = state; - this.$el.find('.loading').toggleClass('hidden', !state); - }, - - _onRequest: function(type) { - if (type === 'REPORT') { - this._toggleLoading(true); - this.$el.find('.showMore').addClass('hidden'); - } - }, - - _onEndRequest: function(type) { - var fileInfoModel = this.model; - this._toggleLoading(false); - this.$el.find('.emptycontent').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); + this._autoCompleteRequestCall = $.ajax({ + url: OC.linkToOCS('core', 2) + 'autocomplete/get', + data: { + search: query, + itemType: 'files', + itemId: s.model.get('id'), + sorter: 'commenters|share-recipients', + limit: OC.appConfig.comments.maxAutoCompleteResults + }, + beforeSend: function(request) { + request.setRequestHeader('Accept', 'application/json') + }, + success: function(result) { + callback(result.ocs.data) } - } - ); - } - this.$el.find('.newCommentForm .message').focus(); - - }, + }) + }, 400) + }, - /** + _formatItem: function(commentModel) { + var timestamp = new Date(commentModel.get('creationDateTime')).getTime() + var data = _.extend({ + timestamp: timestamp, + date: OC.Util.relativeModifiedDate(timestamp), + altDate: OC.Util.formatDate(timestamp), + formattedMessage: this._formatMessage(commentModel.get('message'), commentModel.get('mentions')) + }, commentModel.attributes) + return data + }, + + _toggleLoading: function(state) { + this._loading = state + this.$el.find('.loading').toggleClass('hidden', !state) + }, + + _onRequest: function(type) { + if (type === 'REPORT') { + this._toggleLoading(true) + this.$el.find('.showMore').addClass('hidden') + } + }, + + _onEndRequest: function(type) { + var fileInfoModel = this.model + this._toggleLoading(false) + this.$el.find('.emptycontent').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) + } + } + ) + } + this.$el.find('.newCommentForm .message').focus() + + }, + + /** * takes care of post-rendering after a new comment was added to the * collection * @@ -271,322 +272,321 @@ * @param options * @private */ - _onAddModel: function(model, collection, options) { + _onAddModel: function(model, collection, options) { // we need to render it immediately, to ensure that the right // order of comments is kept on opening comments tab - var $comment = $(this.commentTemplate(this._formatItem(model))); - if (!_.isUndefined(options.at) && collection.length > 1) { - this.$container.find('li').eq(options.at).before($comment); - } else { - this.$container.append($comment); - } - this._postRenderItem($comment); - $('#commentsTabView').find('.newCommentForm div.message').text('').prop('contenteditable', true); - - // we need to update the model, because it consists of client data - // only, but the server might add meta data, e.g. about mentions - var oldMentions = model.get('mentions'); - var self = this; - model.fetch({ - success: function (model) { - if(_.isEqual(oldMentions, model.get('mentions'))) { - // don't attempt to render if unnecessary, avoids flickering - return; - } - var $updated = $(self.commentTemplate(self._formatItem(model))); - $comment.html($updated.html()); - self._postRenderItem($comment); + var $comment = $(this.commentTemplate(this._formatItem(model))) + if (!_.isUndefined(options.at) && collection.length > 1) { + this.$container.find('li').eq(options.at).before($comment) + } else { + this.$container.append($comment) } - }) + this._postRenderItem($comment) + $('#commentsTabView').find('.newCommentForm div.message').text('').prop('contenteditable', true) - }, + // we need to update the model, because it consists of client data + // only, but the server might add meta data, e.g. about mentions + var oldMentions = model.get('mentions') + var self = this + model.fetch({ + success: function(model) { + if (_.isEqual(oldMentions, model.get('mentions'))) { + // don't attempt to render if unnecessary, avoids flickering + return + } + var $updated = $(self.commentTemplate(self._formatItem(model))) + $comment.html($updated.html()) + self._postRenderItem($comment) + } + }) - /** + }, + + /** * takes care of post-rendering after a new comment was edited * * @param model * @private */ - _onChangeModel: function (model) { - if(model.get('message').trim() === model.previous('message').trim()) { - return; - } + _onChangeModel: function(model) { + if (model.get('message').trim() === model.previous('message').trim()) { + return + } - var $form = this.$container.find('.comment[data-id="' + model.id + '"] form'); - var $row = $form.closest('.comment'); - var $target = $row.data('commentEl'); - if(_.isUndefined($target)) { + var $form = this.$container.find('.comment[data-id="' + model.id + '"] form') + var $row = $form.closest('.comment') + var $target = $row.data('commentEl') + if (_.isUndefined($target)) { // ignore noise – this is only set after editing a comment and hitting post - return; - } - var self = this; - - // we need to update the model, because it consists of client data - // only, but the server might add meta data, e.g. about mentions - model.fetch({ - success: function (model) { - $target.removeClass('hidden'); - $row.remove(); - - var $message = $target.find('.message'); - $message - .html(self._formatMessage(model.get('message'), model.get('mentions'))) - .find('.avatar') - .each(function () { $(this).avatar(); }); - self._postRenderItem($message); + return } - }); - }, + var self = this - _postRenderItem: function($el, editionMode) { - $el.find('.has-tooltip').tooltip(); - var inlineAvatars = $el.find('.message .avatar'); - if ($($el.context).hasClass('message')) { - inlineAvatars = $el.find('.avatar'); - } - inlineAvatars.each(function () { - var $this = $(this); - $this.avatar($this.attr('data-username'), 16); - }); - $el.find('.authorRow .avatar').each(function () { - var $this = $(this); - $this.avatar($this.attr('data-username'), 32); - }); + // we need to update the model, because it consists of client data + // only, but the server might add meta data, e.g. about mentions + model.fetch({ + success: function(model) { + $target.removeClass('hidden') + $row.remove() - var username = $el.find('.avatar').data('username'); - if (username !== OC.getCurrentUser().uid) { - $el.find('.authorRow .avatar, .authorRow .author').contactsMenu( - username, 0, $el.find('.authorRow')); - } - - var $message = $el.find('.message'); - if($message.length === 0) { - // it is the case when writing a comment and mentioning a person - $message = $el; - } - - - if (!editionMode) { - var self = this; - // add the dropdown menu to display the edit and delete option - var modifyCommentMenu = new OCA.Comments.CommentsModifyMenu(); - $el.find('.authorRow').append(modifyCommentMenu.$el); - $el.find('.more').on('click', _.bind(modifyCommentMenu.show, modifyCommentMenu)); - - self.listenTo(modifyCommentMenu, 'select:menu-item-clicked', function(ev, action) { - if (action === 'edit') { - self._onClickEditComment(ev); - } else if (action === 'delete') { - self._onClickDeleteComment(ev); + var $message = $target.find('.message') + $message + .html(self._formatMessage(model.get('message'), model.get('mentions'))) + .find('.avatar') + .each(function() { $(this).avatar() }) + self._postRenderItem($message) } - }); - } + }) + }, - this._postRenderMessage($message, editionMode); - }, - - _postRenderMessage: function($el, editionMode) { - if (editionMode) { - return; - } - - $el.find('.avatar-name-wrapper').each(function() { - var $this = $(this); - var $avatar = $this.find('.avatar'); - - var user = $avatar.data('user'); - if (user !== OC.getCurrentUser().uid) { - $this.contactsMenu(user, 0, $this); + _postRenderItem: function($el, editionMode) { + $el.find('.has-tooltip').tooltip() + var inlineAvatars = $el.find('.message .avatar') + if ($($el.context).hasClass('message')) { + inlineAvatars = $el.find('.avatar') } - }); - }, + inlineAvatars.each(function() { + var $this = $(this) + $this.avatar($this.attr('data-username'), 16) + }) + $el.find('.authorRow .avatar').each(function() { + var $this = $(this) + $this.avatar($this.attr('data-username'), 32) + }) - /** + var username = $el.find('.avatar').data('username') + if (username !== OC.getCurrentUser().uid) { + $el.find('.authorRow .avatar, .authorRow .author').contactsMenu( + username, 0, $el.find('.authorRow')) + } + + var $message = $el.find('.message') + if ($message.length === 0) { + // it is the case when writing a comment and mentioning a person + $message = $el + } + + if (!editionMode) { + var self = this + // add the dropdown menu to display the edit and delete option + var modifyCommentMenu = new OCA.Comments.CommentsModifyMenu() + $el.find('.authorRow').append(modifyCommentMenu.$el) + $el.find('.more').on('click', _.bind(modifyCommentMenu.show, modifyCommentMenu)) + + self.listenTo(modifyCommentMenu, 'select:menu-item-clicked', function(ev, action) { + if (action === 'edit') { + self._onClickEditComment(ev) + } else if (action === 'delete') { + self._onClickDeleteComment(ev) + } + }) + } + + this._postRenderMessage($message, editionMode) + }, + + _postRenderMessage: function($el, editionMode) { + if (editionMode) { + return + } + + $el.find('.avatar-name-wrapper').each(function() { + var $this = $(this) + var $avatar = $this.find('.avatar') + + var user = $avatar.data('user') + if (user !== OC.getCurrentUser().uid) { + $this.contactsMenu(user, 0, $this) + } + }) + }, + + /** * Convert a message to be displayed in HTML, * converts newlines to
    tags. */ - _formatMessage: function(message, mentions, editMode) { - message = escapeHTML(message).replace(/\n/g, '
    '); + _formatMessage: function(message, mentions, editMode) { + message = escapeHTML(message).replace(/\n/g, '
    ') - for(var i in mentions) { - if(!mentions.hasOwnProperty(i)) { - return; - } - var mention = '@' + mentions[i].mentionId; - if (mentions[i].mentionId.indexOf(' ') !== -1) { - mention = _.escape('@"' + mentions[i].mentionId + '"'); - } - - // escape possible regex characters in the name - mention = mention.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - var regex = new RegExp("(^|\\s)(" + mention + ")\\b", 'g'); - if (mentions[i].mentionId.indexOf(' ') !== -1) { - regex = new RegExp("(^|\\s)(" + mention + ")", 'g'); - } - - var displayName = this._composeHTMLMention(mentions[i].mentionId, mentions[i].mentionDisplayName); - - // replace every mention either at the start of the input or after a whitespace - // followed by a non-word character. - message = message.replace(regex, - function(match, p1) { - // to get number of whitespaces (0 vs 1) right - return p1+displayName; + for (var i in mentions) { + if (!mentions.hasOwnProperty(i)) { + return + } + var mention = '@' + mentions[i].mentionId + if (mentions[i].mentionId.indexOf(' ') !== -1) { + mention = _.escape('@"' + mentions[i].mentionId + '"') } - ); - } - if(editMode !== true) { - message = OCP.Comments.plainToRich(message); - } - return message; - }, - _composeHTMLMention: function(uid, displayName) { - var avatar = '' + - '' + - ''; + // escape possible regex characters in the name + mention = mention.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + var regex = new RegExp('(^|\\s)(' + mention + ')\\b', 'g') + if (mentions[i].mentionId.indexOf(' ') !== -1) { + regex = new RegExp('(^|\\s)(' + mention + ')', 'g') + } - var isCurrentUser = (uid === OC.getCurrentUser().uid); + var displayName = this._composeHTMLMention(mentions[i].mentionId, mentions[i].mentionDisplayName) - return '' + - '' + - '' + - avatar + - '' + _.escape(displayName) + '' + - '' + - ''; - }, - - nextPage: function() { - if (this._loading || !this.collection.hasMoreResults()) { - return; - } - - this.collection.fetchNext(); - }, - - _onClickEditComment: function(ev) { - ev.preventDefault(); - var $comment = $(ev.target).closest('.comment'); - var commentId = $comment.data('id'); - var commentToEdit = this.collection.get(commentId); - var $formRow = $(this.editCommentTemplate(_.extend({ - isEditMode: true, - submitText: t('comments', 'Save') - }, commentToEdit.attributes))); - - $comment.addClass('hidden').removeClass('collapsed'); - // spawn form - $comment.after($formRow); - $formRow.data('commentEl', $comment); - $formRow.find('.message').on('keydown input change', this._onTypeComment); - - // copy avatar element from original to avoid flickering - $formRow.find('.avatar:first').replaceWith($comment.find('.avatar:first').clone()); - $formRow.find('.has-tooltip').tooltip(); - - var $message = $formRow.find('.message'); - $message - .html(this._formatMessage(commentToEdit.get('message'), commentToEdit.get('mentions'), true)) - .find('.avatar') - .each(function () { $(this).avatar(); }); - var editionMode = true; - this._postRenderItem($message, editionMode); - - // Enable autosize - autosize($formRow.find('.message')); - - // enable autocomplete - this._initAutoComplete($formRow.find('.message')); - - return false; - }, - - _onTypeComment: function(ev) { - var $field = $(ev.target); - var len = $field.text().length; - var $submitButton = $field.data('submitButtonEl'); - if (!$submitButton) { - $submitButton = $field.closest('form').find('.submit'); - $field.data('submitButtonEl', $submitButton); - } - $field.tooltip('hide'); - if (len > this._commentMaxThreshold) { - $field.attr('data-original-title', t('comments', 'Allowed characters {count} of {max}', {count: len, max: this._commentMaxLength})); - $field.tooltip({trigger: 'manual'}); - $field.tooltip('show'); - $field.addClass('error'); - } - - var limitExceeded = (len > this._commentMaxLength); - $field.toggleClass('error', limitExceeded); - $submitButton.prop('disabled', limitExceeded); - - // Submits form with Enter, but Shift+Enter is a new line. If the - // autocomplete popover is being shown Enter does not submit the - // form either; it will be handled by At.js which will add the - // currently selected item to the message. - if (ev.keyCode === 13 && !ev.shiftKey && !$field.atwho('isSelecting')) { - $submitButton.click(); - ev.preventDefault(); - } - }, - - _onClickComment: function(ev) { - var $row = $(ev.target); - if (!$row.is('.comment')) { - $row = $row.closest('.comment'); - } - $row.removeClass('collapsed'); - }, - - _onClickCloseComment: function(ev) { - ev.preventDefault(); - var $row = $(ev.target).closest('.comment'); - $row.data('commentEl').removeClass('hidden'); - $row.remove(); - return false; - }, - - _onClickDeleteComment: function(ev) { - ev.preventDefault(); - var $comment = $(ev.target).closest('.comment'); - var commentId = $comment.data('id'); - var $loading = $comment.find('.deleteLoading'); - var $moreIcon = $comment.find('.more'); - - $comment.addClass('disabled'); - $loading.removeClass('hidden'); - $moreIcon.addClass('hidden'); - - $comment.data('commentEl', $comment); - - this.collection.get(commentId).destroy({ - success: function() { - $comment.data('commentEl').remove(); - $comment.remove(); - }, - error: function() { - $loading.addClass('hidden'); - $moreIcon.removeClass('hidden'); - $comment.removeClass('disabled'); - - OC.Notification.showTemporary(t('comments', 'Error occurred while retrieving comment with ID {id}', {id: commentId})); + // replace every mention either at the start of the input or after a whitespace + // followed by a non-word character. + message = message.replace(regex, + function(match, p1) { + // to get number of whitespaces (0 vs 1) right + return p1 + displayName + } + ) } - }); + if (editMode !== true) { + message = OCP.Comments.plainToRich(message) + } + return message + }, - return false; - }, + _composeHTMLMention: function(uid, displayName) { + var avatar = '' + + '' + + '' - _onClickShowMore: function(ev) { - ev.preventDefault(); - this.nextPage(); - }, + var isCurrentUser = (uid === OC.getCurrentUser().uid) - /** + return '' + + '' + + '' + + avatar + + '' + _.escape(displayName) + '' + + '' + + '' + }, + + nextPage: function() { + if (this._loading || !this.collection.hasMoreResults()) { + return + } + + this.collection.fetchNext() + }, + + _onClickEditComment: function(ev) { + ev.preventDefault() + var $comment = $(ev.target).closest('.comment') + var commentId = $comment.data('id') + var commentToEdit = this.collection.get(commentId) + var $formRow = $(this.editCommentTemplate(_.extend({ + isEditMode: true, + submitText: t('comments', 'Save') + }, commentToEdit.attributes))) + + $comment.addClass('hidden').removeClass('collapsed') + // spawn form + $comment.after($formRow) + $formRow.data('commentEl', $comment) + $formRow.find('.message').on('keydown input change', this._onTypeComment) + + // copy avatar element from original to avoid flickering + $formRow.find('.avatar:first').replaceWith($comment.find('.avatar:first').clone()) + $formRow.find('.has-tooltip').tooltip() + + var $message = $formRow.find('.message') + $message + .html(this._formatMessage(commentToEdit.get('message'), commentToEdit.get('mentions'), true)) + .find('.avatar') + .each(function() { $(this).avatar() }) + var editionMode = true + this._postRenderItem($message, editionMode) + + // Enable autosize + autosize($formRow.find('.message')) + + // enable autocomplete + this._initAutoComplete($formRow.find('.message')) + + return false + }, + + _onTypeComment: function(ev) { + var $field = $(ev.target) + var len = $field.text().length + var $submitButton = $field.data('submitButtonEl') + if (!$submitButton) { + $submitButton = $field.closest('form').find('.submit') + $field.data('submitButtonEl', $submitButton) + } + $field.tooltip('hide') + if (len > this._commentMaxThreshold) { + $field.attr('data-original-title', t('comments', 'Allowed characters {count} of {max}', { count: len, max: this._commentMaxLength })) + $field.tooltip({ trigger: 'manual' }) + $field.tooltip('show') + $field.addClass('error') + } + + var limitExceeded = (len > this._commentMaxLength) + $field.toggleClass('error', limitExceeded) + $submitButton.prop('disabled', limitExceeded) + + // Submits form with Enter, but Shift+Enter is a new line. If the + // autocomplete popover is being shown Enter does not submit the + // form either; it will be handled by At.js which will add the + // currently selected item to the message. + if (ev.keyCode === 13 && !ev.shiftKey && !$field.atwho('isSelecting')) { + $submitButton.click() + ev.preventDefault() + } + }, + + _onClickComment: function(ev) { + var $row = $(ev.target) + if (!$row.is('.comment')) { + $row = $row.closest('.comment') + } + $row.removeClass('collapsed') + }, + + _onClickCloseComment: function(ev) { + ev.preventDefault() + var $row = $(ev.target).closest('.comment') + $row.data('commentEl').removeClass('hidden') + $row.remove() + return false + }, + + _onClickDeleteComment: function(ev) { + ev.preventDefault() + var $comment = $(ev.target).closest('.comment') + var commentId = $comment.data('id') + var $loading = $comment.find('.deleteLoading') + var $moreIcon = $comment.find('.more') + + $comment.addClass('disabled') + $loading.removeClass('hidden') + $moreIcon.addClass('hidden') + + $comment.data('commentEl', $comment) + + this.collection.get(commentId).destroy({ + success: function() { + $comment.data('commentEl').remove() + $comment.remove() + }, + error: function() { + $loading.addClass('hidden') + $moreIcon.removeClass('hidden') + $comment.removeClass('disabled') + + OC.Notification.showTemporary(t('comments', 'Error occurred while retrieving comment with ID {id}', { id: commentId })) + } + }) + + return false + }, + + _onClickShowMore: function(ev) { + ev.preventDefault() + this.nextPage() + }, + + /** * takes care of updating comment element states after submit (either new * comment or edit). * @@ -594,106 +594,106 @@ * @param {jQuery} $form * @private */ - _onSubmitSuccess: function(model, $form) { - var $submit = $form.find('.submit'); - var $loading = $form.find('.submitLoading'); + _onSubmitSuccess: function(model, $form) { + var $submit = $form.find('.submit') + var $loading = $form.find('.submitLoading') - $submit.removeClass('hidden'); - $loading.addClass('hidden'); - }, + $submit.removeClass('hidden') + $loading.addClass('hidden') + }, - _commentBodyHTML2Plain: function($el) { - var $comment = $el.clone(); + _commentBodyHTML2Plain: function($el) { + var $comment = $el.clone() - $comment.find('.avatar-name-wrapper').each(function () { - var $this = $(this), - $inserted = $this.parent(), - userId = $this.find('.avatar').data('username'); - if (userId.indexOf(' ') !== -1) { - $inserted.html('@"' + userId + '"'); - } else { - $inserted.html('@' + userId); - } - }); + $comment.find('.avatar-name-wrapper').each(function() { + var $this = $(this) + var $inserted = $this.parent() + var userId = $this.find('.avatar').data('username') + if (userId.indexOf(' ') !== -1) { + $inserted.html('@"' + userId + '"') + } else { + $inserted.html('@' + userId) + } + }) - $comment.html(OCP.Comments.richToPlain($comment.html())); + $comment.html(OCP.Comments.richToPlain($comment.html())) - var oldHtml; - var html = $comment.html(); - do { + var oldHtml + var html = $comment.html() + do { // replace works one by one - oldHtml = html; - html = oldHtml.replace("
    ", "\n"); // preserve line breaks - } while(oldHtml !== html); - $comment.html(html); + oldHtml = html + html = oldHtml.replace('
    ', '\n') // preserve line breaks + } while (oldHtml !== html) + $comment.html(html) - return $comment.text(); - }, + return $comment.text() + }, - _onSubmitComment: function(e) { - var self = this; - var $form = $(e.target); - var commentId = $form.closest('.comment').data('id'); - var currentUser = OC.getCurrentUser(); - var $submit = $form.find('.submit'); - var $loading = $form.find('.submitLoading'); - var $commentField = $form.find('.message'); - var message = $commentField.text().trim(); - e.preventDefault(); + _onSubmitComment: function(e) { + var self = this + var $form = $(e.target) + var commentId = $form.closest('.comment').data('id') + var currentUser = OC.getCurrentUser() + var $submit = $form.find('.submit') + var $loading = $form.find('.submitLoading') + var $commentField = $form.find('.message') + var message = $commentField.text().trim() + e.preventDefault() - if (!message.length || message.length > this._commentMaxLength) { - return; - } + if (!message.length || message.length > this._commentMaxLength) { + return + } - $commentField.prop('contenteditable', false); - $submit.addClass('hidden'); - $loading.removeClass('hidden'); + $commentField.prop('contenteditable', false) + $submit.addClass('hidden') + $loading.removeClass('hidden') - message = this._commentBodyHTML2Plain($commentField); - if (commentId) { + message = this._commentBodyHTML2Plain($commentField) + if (commentId) { // edit mode - var comment = this.collection.get(commentId); - comment.save({ - message: message - }, { - success: function(model) { - self._onSubmitSuccess(model, $form); - if(model.get('message').trim() === model.previous('message').trim()) { + var comment = this.collection.get(commentId) + comment.save({ + message: message + }, { + success: function(model) { + self._onSubmitSuccess(model, $form) + if (model.get('message').trim() === model.previous('message').trim()) { // model change event doesn't trigger, manually remove the row. - var $row = $form.closest('.comment'); - $row.data('commentEl').removeClass('hidden'); - $row.remove(); + var $row = $form.closest('.comment') + $row.data('commentEl').removeClass('hidden') + $row.remove() + } + }, + error: function() { + self._onSubmitError($form, commentId) } - }, - error: function() { - self._onSubmitError($form, commentId); - } - }); - } else { - this.collection.create({ - actorId: currentUser.uid, - actorDisplayName: currentUser.displayName, - actorType: 'users', - verb: 'comment', - message: message, - creationDateTime: (new Date()).toUTCString() - }, { - at: 0, - // wait for real creation before adding - wait: true, - success: function(model) { - self._onSubmitSuccess(model, $form); - }, - error: function() { - self._onSubmitError($form, undefined); - } - }); - } + }) + } else { + this.collection.create({ + actorId: currentUser.uid, + actorDisplayName: currentUser.displayName, + actorType: 'users', + verb: 'comment', + message: message, + creationDateTime: (new Date()).toUTCString() + }, { + at: 0, + // wait for real creation before adding + wait: true, + success: function(model) { + self._onSubmitSuccess(model, $form) + }, + error: function() { + self._onSubmitError($form, undefined) + } + }) + } - return false; - }, + return false + }, - /** + /** * takes care of updating the UI after an error on submit (either new * comment or edit). * @@ -701,51 +701,51 @@ * @param {string|undefined} commentId * @private */ - _onSubmitError: function($form, commentId) { - $form.find('.submit').removeClass('hidden'); - $form.find('.submitLoading').addClass('hidden'); - $form.find('.message').prop('contenteditable', true); + _onSubmitError: function($form, commentId) { + $form.find('.submit').removeClass('hidden') + $form.find('.submitLoading').addClass('hidden') + $form.find('.message').prop('contenteditable', true) - if(!_.isUndefined(commentId)) { - OC.Notification.show(t('comments', 'Error occurred while updating comment with id {id}', {id: commentId}), {type: 'error'}); - } else { - OC.Notification.show(t('comments', 'Error occurred while posting comment'), {type: 'error'}); - } - }, + if (!_.isUndefined(commentId)) { + OC.Notification.show(t('comments', 'Error occurred while updating comment with id {id}', { id: commentId }), { type: 'error' }) + } else { + OC.Notification.show(t('comments', 'Error occurred while posting comment'), { type: 'error' }) + } + }, - /** + /** * ensures the contenteditable div is really empty, when user removed * all input, so that the placeholder will be shown again * * @private */ - _onTextChange: function() { - var $message = $('#commentsTabView').find('.newCommentForm div.message'); - if(!$message.text().trim().length) { - $message.empty(); - } - }, + _onTextChange: function() { + var $message = $('#commentsTabView').find('.newCommentForm div.message') + if (!$message.text().trim().length) { + $message.empty() + } + }, - /** + /** * Limit pasting to plain text * * @param e * @private */ - _onPaste: function (e) { - e.preventDefault(); - var text = e.originalEvent.clipboardData.getData("text/plain"); - document.execCommand('insertText', false, text); - }, + _onPaste: function(e) { + e.preventDefault() + var text = e.originalEvent.clipboardData.getData('text/plain') + document.execCommand('insertText', false, text) + }, - /** + /** * Returns whether the given message is long and needs * collapsing */ - _isLong: function(message) { - return message.length > 250 || (message.match(/\n/g) || []).length > 1; - } - }); + _isLong: function(message) { + return message.length > 250 || (message.match(/\n/g) || []).length > 1 + } + }) - OCA.Comments.CommentsTabView = CommentsTabView; -})(OC, OCA); + OCA.Comments.CommentsTabView = CommentsTabView +})(OC, OCA) diff --git a/apps/comments/src/commentsummarymodel.js b/apps/comments/src/commentsummarymodel.js index ffabbc30fb..1a3002a9f7 100644 --- a/apps/comments/src/commentsummarymodel.js +++ b/apps/comments/src/commentsummarymodel.js @@ -12,7 +12,7 @@ _.extend(OC.Files.Client, { PROPERTY_READMARKER: '{' + OC.Files.Client.NS_OWNCLOUD + '}readMarker' - }); + }) /** * @class OCA.Comments.CommentSummaryModel @@ -24,45 +24,47 @@ */ var CommentSummaryModel = OC.Backbone.Model.extend( /** @lends OCA.Comments.CommentSummaryModel.prototype */ { - sync: OC.Backbone.davSync, + sync: OC.Backbone.davSync, - /** + /** * Object type * * @type string */ - _objectType: 'files', + _objectType: 'files', - /** + /** * Object id * * @type string */ - _objectId: null, + _objectId: null, - davProperties: { - 'readMarker': OC.Files.Client.PROPERTY_READMARKER - }, + davProperties: { + 'readMarker': OC.Files.Client.PROPERTY_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; + /** + * Initializes the summary model + * + * @param {any} [attrs] ignored + * @param {Object} [options] destructuring object + * @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) + '/' } - }, + }) - url: function() { - return OC.linkToRemote('dav') + '/comments/' + - encodeURIComponent(this._objectType) + '/' + - encodeURIComponent(this.id) + '/'; - } - }); - - OCA.Comments.CommentSummaryModel = CommentSummaryModel; -})(OC, OCA); + OCA.Comments.CommentSummaryModel = CommentSummaryModel +})(OC, OCA) diff --git a/apps/comments/src/filesplugin.js b/apps/comments/src/filesplugin.js index 2073be09b6..e315dd2fef 100644 --- a/apps/comments/src/filesplugin.js +++ b/apps/comments/src/filesplugin.js @@ -8,20 +8,18 @@ * */ -/* global Handlebars */ - (function() { _.extend(OC.Files.Client, { PROPERTY_COMMENTS_UNREAD: '{' + OC.Files.Client.NS_OWNCLOUD + '}comments-unread' - }); + }) - OCA.Comments = _.extend({}, OCA.Comments); + OCA.Comments = _.extend({}, OCA.Comments) if (!OCA.Comments) { /** * @namespace */ - OCA.Comments = {}; + OCA.Comments = {} } /** @@ -38,43 +36,43 @@ count: count, countMessage: n('comments', '%n unread comment', '%n unread comments', count), iconUrl: OC.imagePath('core', 'actions/comment') - }); + }) }, attach: function(fileList) { - var self = this; + var self = this if (this.ignoreLists.indexOf(fileList.id) >= 0) { - return; + return } - fileList.registerTabView(new OCA.Comments.CommentsTabView('commentsTabView')); + fileList.registerTabView(new OCA.Comments.CommentsTabView('commentsTabView')) - var oldGetWebdavProperties = fileList._getWebdavProperties; + var oldGetWebdavProperties = fileList._getWebdavProperties fileList._getWebdavProperties = function() { - var props = oldGetWebdavProperties.apply(this, arguments); - props.push(OC.Files.Client.PROPERTY_COMMENTS_UNREAD); - return props; - }; + var props = oldGetWebdavProperties.apply(this, arguments) + props.push(OC.Files.Client.PROPERTY_COMMENTS_UNREAD) + return props + } fileList.filesClient.addFileInfoParser(function(response) { - var data = {}; - var props = response.propStat[0].properties; - var commentsUnread = props[OC.Files.Client.PROPERTY_COMMENTS_UNREAD]; + var data = {} + var props = response.propStat[0].properties + var commentsUnread = props[OC.Files.Client.PROPERTY_COMMENTS_UNREAD] if (!_.isUndefined(commentsUnread) && commentsUnread !== '') { - data.commentsUnread = parseInt(commentsUnread, 10); + data.commentsUnread = parseInt(commentsUnread, 10) } - return data; - }); + return data + }) - fileList.$el.addClass('has-comments'); - var oldCreateRow = fileList._createRow; + fileList.$el.addClass('has-comments') + var oldCreateRow = fileList._createRow fileList._createRow = function(fileData) { - var $tr = oldCreateRow.apply(this, arguments); + var $tr = oldCreateRow.apply(this, arguments) if (fileData.commentsUnread) { - $tr.attr('data-comments-unread', fileData.commentsUnread); + $tr.attr('data-comments-unread', fileData.commentsUnread) } - return $tr; - }; + return $tr + } // register "comment" action for reading comments fileList.fileActions.registerAction({ @@ -94,35 +92,35 @@ 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'); + 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; + var $actionLink = $(self._formatCommentCount(unreadComments)) + context.$file.find('a.name>span.fileactions').append($actionLink) + return $actionLink } - return ''; + return '' }, actionHandler: function(fileName, context) { - context.$file.find('.action-comment').tooltip('hide'); + context.$file.find('.action-comment').tooltip('hide') // open sidebar in comments section - context.fileList.showDetailsView(fileName, 'commentsTabView'); + context.fileList.showDetailsView(fileName, 'commentsTabView') } - }); + }) // add attribute to "elementToFile" - var oldElementToFile = fileList.elementToFile; + var oldElementToFile = fileList.elementToFile fileList.elementToFile = function($el) { - var fileInfo = oldElementToFile.apply(this, arguments); - var commentsUnread = $el.data('comments-unread'); + var fileInfo = oldElementToFile.apply(this, arguments) + var commentsUnread = $el.data('comments-unread') if (commentsUnread) { - fileInfo.commentsUnread = commentsUnread; + fileInfo.commentsUnread = commentsUnread } - return fileInfo; - }; + return fileInfo + } } - }; + } -})(); +})() -OC.Plugins.register('OCA.Files.FileList', OCA.Comments.FilesPlugin); +OC.Plugins.register('OCA.Files.FileList', OCA.Comments.FilesPlugin) diff --git a/apps/comments/src/search.js b/apps/comments/src/search.js index 8e0a35ff6e..c62726d908 100644 --- a/apps/comments/src/search.js +++ b/apps/comments/src/search.js @@ -1,3 +1,4 @@ +/* eslint-disable */ /* * Copyright (c) 2014 * @@ -8,15 +9,15 @@ * */ (function(OC, OCA, $) { - "use strict"; + 'use strict' /** * Construct a new FileActions instance * @constructs Files */ var Comment = function() { - this.initialize(); - }; + this.initialize() + } Comment.prototype = { @@ -27,25 +28,25 @@ */ initialize: function() { - var self = this; + var self = this this.fileAppLoaded = function() { - return !!OCA.Files && !!OCA.Files.App; - }; + return !!OCA.Files && !!OCA.Files.App + } function inFileList($row, result) { - return false; + return false - if (! self.fileAppLoaded()) { - return false; + if (!self.fileAppLoaded()) { + return false } - var dir = self.fileList.getCurrentDirectory().replace(/\/+$/,''); - var resultDir = OC.dirname(result.path); - return dir === resultDir && self.fileList.inList(result.name); + var dir = self.fileList.getCurrentDirectory().replace(/\/+$/, '') + var resultDir = OC.dirname(result.path) + return dir === resultDir && self.fileList.inList(result.name) } function hideNoFilterResults() { - var $nofilterresults = $('.nofilterresults'); - if ( ! $nofilterresults.hasClass('hidden') ) { - $nofilterresults.addClass('hidden'); + var $nofilterresults = $('.nofilterresults') + if (!$nofilterresults.hasClass('hidden')) { + $nofilterresults.addClass('hidden') } } @@ -64,73 +65,73 @@ */ this.renderCommentResult = function($row, result) { if (inFileList($row, result)) { - return null; + return null } - hideNoFilterResults(); - /*render preview icon, show path beneath filename, + hideNoFilterResults() + /* render preview icon, show path beneath filename, show size and last modified date on the right */ - this.updateLegacyMimetype(result); + this.updateLegacyMimetype(result) - var $pathDiv = $('
    ').addClass('path').text(result.path); + var $pathDiv = $('
    ').addClass('path').text(result.path) - var $avatar = $('
    '); + var $avatar = $('
    ') $avatar.addClass('avatar') .css('display', 'inline-block') .css('vertical-align', 'middle') - .css('margin', '0 5px 2px 3px'); + .css('margin', '0 5px 2px 3px') if (result.authorName) { - $avatar.avatar(result.authorId, 21, undefined, false, undefined, result.authorName); + $avatar.avatar(result.authorId, 21, undefined, false, undefined, result.authorName) } else { - $avatar.avatar(result.authorId, 21); + $avatar.avatar(result.authorId, 21) } - $row.find('td.info div.name').after($pathDiv).text(result.comment).prepend($('').addClass('path').css('margin-right', '5px').text(result.authorName)).prepend($avatar); - $row.find('td.result a').attr('href', result.link); + $row.find('td.info div.name').after($pathDiv).text(result.comment).prepend($('').addClass('path').css('margin-right', '5px').text(result.authorName)).prepend($avatar) + $row.find('td.result a').attr('href', result.link) $row.find('td.icon') .css('background-image', 'url(' + OC.imagePath('core', 'actions/comment') + ')') - .css('opacity', '.4'); - var dir = OC.dirname(result.path); + .css('opacity', '.4') + var dir = OC.dirname(result.path) // "result.path" does not include a leading "/", so "OC.dirname" // returns the path itself for files or folders in the root. if (dir === result.path) { - dir = '/'; + dir = '/' } $row.find('td.info a').attr('href', - OC.generateUrl('/apps/files/?dir={dir}&scrollto={scrollto}', {dir: dir, scrollto: result.fileName}) - ); + OC.generateUrl('/apps/files/?dir={dir}&scrollto={scrollto}', { dir: dir, scrollto: result.fileName }) + ) - return $row; - }; + return $row + } this.handleCommentClick = function($row, result, event) { if (self.fileAppLoaded() && self.fileList.id === 'files') { - self.fileList.changeDirectory(OC.dirname(result.path)); - self.fileList.scrollTo(result.name); - return false; + self.fileList.changeDirectory(OC.dirname(result.path)) + self.fileList.scrollTo(result.name) + return false } else { - return true; + return true } - }; + } - this.updateLegacyMimetype = function (result) { + this.updateLegacyMimetype = function(result) { // backward compatibility: if (!result.mime && result.mime_type) { - result.mime = result.mime_type; + result.mime = result.mime_type } - }; - this.setFileList = function (fileList) { - this.fileList = fileList; - }; + } + this.setFileList = function(fileList) { + this.fileList = fileList + } - OC.Plugins.register('OCA.Search.Core', this); + OC.Plugins.register('OCA.Search.Core', this) }, attach: function(search) { - search.setRenderer('comment', this.renderCommentResult.bind(this)); - search.setHandler('comment', this.handleCommentClick.bind(this)); + search.setRenderer('comment', this.renderCommentResult.bind(this)) + search.setHandler('comment', this.handleCommentClick.bind(this)) } - }; + } - OCA.Search.comment = new Comment(); -})(OC, OCA, $); + OCA.Search.comment = new Comment() +})(OC, OCA, $) diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 8db23fca3b..c63c1e3152 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -727,11 +727,11 @@ OC.Uploader.prototype = _.extend({ * * @param {array} selection of files to upload * @param {object} callbacks - object with several callback methods - * @param {function} callbacks.onNoConflicts - * @param {function} callbacks.onSkipConflicts - * @param {function} callbacks.onReplaceConflicts - * @param {function} callbacks.onChooseConflicts - * @param {function} callbacks.onCancel + * @param {Function} callbacks.onNoConflicts + * @param {Function} callbacks.onSkipConflicts + * @param {Function} callbacks.onReplaceConflicts + * @param {Function} callbacks.onChooseConflicts + * @param {Function} callbacks.onCancel */ checkExistingFiles: function (selection, callbacks) { var fileList = this.fileList; diff --git a/apps/files/js/files.js b/apps/files/js/files.js index b46aeb26ee..395b2a53c1 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -336,7 +336,7 @@ * - JS periodically checks for this cookie and then knows when the download has started to call the callback * * @param {string} url download URL - * @param {function} callback function to call once the download has started + * @param {Function} callback function to call once the download has started */ handleDownload: function(url, callback) { var randomToken = Math.random().toString(36).substring(2), diff --git a/apps/files_external/js/statusmanager.js b/apps/files_external/js/statusmanager.js index 0c0c8b36c7..ebedd91f2a 100644 --- a/apps/files_external/js/statusmanager.js +++ b/apps/files_external/js/statusmanager.js @@ -125,7 +125,7 @@ OCA.Files_External.StatusManager = { /** * Function to get external mount point list from the files_external API - * @param {function} afterCallback function to be executed + * @param {Function} afterCallback function to be executed */ getMountPointList: function (afterCallback) { diff --git a/apps/files_sharing/.eslintrc.js b/apps/files_sharing/.eslintrc.js deleted file mode 100644 index 214cccecd8..0000000000 --- a/apps/files_sharing/.eslintrc.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - env: { - browser: true, - es6: true - }, - globals: { - t: true, - n: true, - OC: true, - OCA: true - }, - extends: 'eslint:recommended', - parserOptions: { - sourceType: 'module' - }, - rules: { - indent: ['error', 'tab'], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'always'] - } -}; diff --git a/apps/files_sharing/js/app.js b/apps/files_sharing/js/app.js index b6ca71e15d..29cd3385c3 100644 --- a/apps/files_sharing/js/app.js +++ b/apps/files_sharing/js/app.js @@ -12,7 +12,7 @@ if (!OCA.Sharing) { /** * @namespace OCA.Sharing */ - OCA.Sharing = {}; + OCA.Sharing = {} } /** * @namespace @@ -25,7 +25,7 @@ OCA.Sharing.App = { initSharingIn: function($el) { if (this._inFileList) { - return this._inFileList; + return this._inFileList } this._inFileList = new OCA.Sharing.FileList( @@ -40,19 +40,19 @@ OCA.Sharing.App = { // if handling the event with the file list already created. shown: true } - ); + ) - this._extendFileList(this._inFileList); - this._inFileList.appName = t('files_sharing', 'Shared with you'); - this._inFileList.$el.find('#emptycontent').html('
    ' + - '

    ' + t('files_sharing', 'Nothing shared with you yet') + '

    ' + - '

    ' + t('files_sharing', 'Files and folders others share with you will show up here') + '

    '); - return this._inFileList; + this._extendFileList(this._inFileList) + this._inFileList.appName = t('files_sharing', 'Shared with you') + this._inFileList.$el.find('#emptycontent').html('
    ' + + '

    ' + t('files_sharing', 'Nothing shared with you yet') + '

    ' + + '

    ' + t('files_sharing', 'Files and folders others share with you will show up here') + '

    ') + return this._inFileList }, initSharingOut: function($el) { if (this._outFileList) { - return this._outFileList; + return this._outFileList } this._outFileList = new OCA.Sharing.FileList( $el, @@ -66,19 +66,19 @@ OCA.Sharing.App = { // if handling the event with the file list already created. shown: true } - ); + ) - this._extendFileList(this._outFileList); - this._outFileList.appName = t('files_sharing', 'Shared with others'); - this._outFileList.$el.find('#emptycontent').html('
    ' + - '

    ' + t('files_sharing', 'Nothing shared yet') + '

    ' + - '

    ' + t('files_sharing', 'Files and folders you share will show up here') + '

    '); - return this._outFileList; + this._extendFileList(this._outFileList) + this._outFileList.appName = t('files_sharing', 'Shared with others') + this._outFileList.$el.find('#emptycontent').html('
    ' + + '

    ' + t('files_sharing', 'Nothing shared yet') + '

    ' + + '

    ' + t('files_sharing', 'Files and folders you share will show up here') + '

    ') + return this._outFileList }, initSharingLinks: function($el) { if (this._linkFileList) { - return this._linkFileList; + return this._linkFileList } this._linkFileList = new OCA.Sharing.FileList( $el, @@ -92,19 +92,19 @@ OCA.Sharing.App = { // if handling the event with the file list already created. shown: true } - ); + ) - this._extendFileList(this._linkFileList); - this._linkFileList.appName = t('files_sharing', 'Shared by link'); - this._linkFileList.$el.find('#emptycontent').html('
    ' + - '

    ' + t('files_sharing', 'No shared links') + '

    ' + - '

    ' + t('files_sharing', 'Files and folders you share by link will show up here') + '

    '); - return this._linkFileList; + this._extendFileList(this._linkFileList) + this._linkFileList.appName = t('files_sharing', 'Shared by link') + this._linkFileList.$el.find('#emptycontent').html('
    ' + + '

    ' + t('files_sharing', 'No shared links') + '

    ' + + '

    ' + t('files_sharing', 'Files and folders you share by link will show up here') + '

    ') + return this._linkFileList }, initSharingDeleted: function($el) { if (this._deletedFileList) { - return this._deletedFileList; + return this._deletedFileList } this._deletedFileList = new OCA.Sharing.FileList( $el, @@ -119,19 +119,19 @@ OCA.Sharing.App = { // if handling the event with the file list already created. shown: true } - ); + ) - this._extendFileList(this._deletedFileList); - this._deletedFileList.appName = t('files_sharing', 'Deleted shares'); - this._deletedFileList.$el.find('#emptycontent').html('
    ' + - '

    ' + t('files_sharing', 'No deleted shares') + '

    ' + - '

    ' + t('files_sharing', 'Shares you deleted will show up here') + '

    '); - return this._deletedFileList; + this._extendFileList(this._deletedFileList) + this._deletedFileList.appName = t('files_sharing', 'Deleted shares') + this._deletedFileList.$el.find('#emptycontent').html('
    ' + + '

    ' + t('files_sharing', 'No deleted shares') + '

    ' + + '

    ' + t('files_sharing', 'Shares you deleted will show up here') + '

    ') + return this._deletedFileList }, initShareingOverview: function($el) { if (this._overviewFileList) { - return this._overviewFileList; + return this._overviewFileList } this._overviewFileList = new OCA.Sharing.FileList( $el, @@ -144,43 +144,43 @@ OCA.Sharing.App = { // if handling the event with the file list already created. shown: true } - ); + ) - this._extendFileList(this._overviewFileList); - this._overviewFileList.appName = t('files_sharing', 'Shares'); - this._overviewFileList.$el.find('#emptycontent').html('
    ' + - '

    ' + t('files_sharing', 'No shares') + '

    ' + - '

    ' + t('files_sharing', 'Shares will show up here') + '

    '); - return this._overviewFileList; + this._extendFileList(this._overviewFileList) + this._overviewFileList.appName = t('files_sharing', 'Shares') + this._overviewFileList.$el.find('#emptycontent').html('
    ' + + '

    ' + t('files_sharing', 'No shares') + '

    ' + + '

    ' + t('files_sharing', 'Shares will show up here') + '

    ') + return this._overviewFileList }, removeSharingIn: function() { if (this._inFileList) { - this._inFileList.$fileList.empty(); + this._inFileList.$fileList.empty() } }, removeSharingOut: function() { if (this._outFileList) { - this._outFileList.$fileList.empty(); + this._outFileList.$fileList.empty() } }, removeSharingLinks: function() { if (this._linkFileList) { - this._linkFileList.$fileList.empty(); + this._linkFileList.$fileList.empty() } }, removeSharingDeleted: function() { if (this._deletedFileList) { - this._deletedFileList.$fileList.empty(); + this._deletedFileList.$fileList.empty() } }, removeSharingOverview: function() { if (this._overviewFileList) { - this._overviewFileList.$fileList.empty(); + this._overviewFileList.$fileList.empty() } }, @@ -188,46 +188,46 @@ OCA.Sharing.App = { * Destroy the app */ destroy: function() { - OCA.Files.fileActions.off('setDefault.app-sharing', this._onActionsUpdated); - OCA.Files.fileActions.off('registerAction.app-sharing', this._onActionsUpdated); - this.removeSharingIn(); - this.removeSharingOut(); - this.removeSharingLinks(); - this._inFileList = null; - this._outFileList = null; - this._linkFileList = null; - this._overviewFileList = null; - delete this._globalActionsInitialized; + OCA.Files.fileActions.off('setDefault.app-sharing', this._onActionsUpdated) + OCA.Files.fileActions.off('registerAction.app-sharing', this._onActionsUpdated) + this.removeSharingIn() + this.removeSharingOut() + this.removeSharingLinks() + this._inFileList = null + this._outFileList = null + this._linkFileList = null + this._overviewFileList = null + delete this._globalActionsInitialized }, _createFileActions: function() { // inherit file actions from the files app - var fileActions = new OCA.Files.FileActions(); + var fileActions = new OCA.Files.FileActions() // note: not merging the legacy actions because legacy apps are not // compatible with the sharing overview and need to be adapted first - fileActions.registerDefaultActions(); - fileActions.merge(OCA.Files.fileActions); + fileActions.registerDefaultActions() + fileActions.merge(OCA.Files.fileActions) if (!this._globalActionsInitialized) { // in case actions are registered later - this._onActionsUpdated = _.bind(this._onActionsUpdated, this); - OCA.Files.fileActions.on('setDefault.app-sharing', this._onActionsUpdated); - OCA.Files.fileActions.on('registerAction.app-sharing', this._onActionsUpdated); - this._globalActionsInitialized = true; + this._onActionsUpdated = _.bind(this._onActionsUpdated, this) + OCA.Files.fileActions.on('setDefault.app-sharing', this._onActionsUpdated) + OCA.Files.fileActions.on('registerAction.app-sharing', this._onActionsUpdated) + this._globalActionsInitialized = true } // when the user clicks on a folder, redirect to the corresponding // folder in the files app instead of opening it directly - fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) { - OCA.Files.App.setActiveView('files', {silent: true}); - OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true); - }); - fileActions.setDefault('dir', 'Open'); - return fileActions; + fileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename, context) { + OCA.Files.App.setActiveView('files', { silent: true }) + OCA.Files.App.fileList.changeDirectory(OC.joinPaths(context.$file.attr('data-path'), filename), true, true) + }) + fileActions.setDefault('dir', 'Open') + return fileActions }, _restoreShareAction: function() { - var fileActions = new OCA.Files.FileActions(); + var fileActions = new OCA.Files.FileActions() fileActions.registerAction({ name: 'Restore', displayName: '', @@ -237,70 +237,70 @@ OCA.Sharing.App = { iconClass: 'icon-history', type: OCA.Files.FileActions.TYPE_INLINE, actionHandler: function(fileName, context) { - var shareId = context.$file.data('shareId'); + var shareId = context.$file.data('shareId') $.post(OC.linkToOCS('apps/files_sharing/api/v1/deletedshares', 2) + shareId) - .success(function(result) { - context.fileList.remove(context.fileInfoModel.attributes.name); - }).fail(function() { - OC.Notification.showTemporary(t('files_sharing', 'Something happened. Unable to restore the share.')); - }); + .success(function(result) { + context.fileList.remove(context.fileInfoModel.attributes.name) + }).fail(function() { + OC.Notification.showTemporary(t('files_sharing', 'Something happened. Unable to restore the share.')) + }) } - }); - return fileActions; + }) + return fileActions }, _onActionsUpdated: function(ev) { _.each([this._inFileList, this._outFileList, this._linkFileList], function(list) { if (!list) { - return; + return } if (ev.action) { - list.fileActions.registerAction(ev.action); + list.fileActions.registerAction(ev.action) } else if (ev.defaultAction) { list.fileActions.setDefault( ev.defaultAction.mime, ev.defaultAction.name - ); + ) } - }); + }) }, _extendFileList: function(fileList) { // remove size column from summary - fileList.fileSummary.$el.find('.filesize').remove(); + fileList.fileSummary.$el.find('.filesize').remove() } -}; +} $(document).ready(function() { $('#app-content-sharingin').on('show', function(e) { - OCA.Sharing.App.initSharingIn($(e.target)); - }); + OCA.Sharing.App.initSharingIn($(e.target)) + }) $('#app-content-sharingin').on('hide', function() { - OCA.Sharing.App.removeSharingIn(); - }); + OCA.Sharing.App.removeSharingIn() + }) $('#app-content-sharingout').on('show', function(e) { - OCA.Sharing.App.initSharingOut($(e.target)); - }); + OCA.Sharing.App.initSharingOut($(e.target)) + }) $('#app-content-sharingout').on('hide', function() { - OCA.Sharing.App.removeSharingOut(); - }); + OCA.Sharing.App.removeSharingOut() + }) $('#app-content-sharinglinks').on('show', function(e) { - OCA.Sharing.App.initSharingLinks($(e.target)); - }); + OCA.Sharing.App.initSharingLinks($(e.target)) + }) $('#app-content-sharinglinks').on('hide', function() { - OCA.Sharing.App.removeSharingLinks(); - }); + OCA.Sharing.App.removeSharingLinks() + }) $('#app-content-deletedshares').on('show', function(e) { - OCA.Sharing.App.initSharingDeleted($(e.target)); - }); + OCA.Sharing.App.initSharingDeleted($(e.target)) + }) $('#app-content-deletedshares').on('hide', function() { - OCA.Sharing.App.removeSharingDeleted(); - }); + OCA.Sharing.App.removeSharingDeleted() + }) $('#app-content-shareoverview').on('show', function(e) { - OCA.Sharing.App.initShareingOverview($(e.target)); - }); + OCA.Sharing.App.initShareingOverview($(e.target)) + }) $('#app-content-shareoverview').on('hide', function() { - OCA.Sharing.App.removeSharingOverview(); - }); -}); + OCA.Sharing.App.removeSharingOverview() + }) +}) diff --git a/apps/files_sharing/js/dist/additionalScripts.js b/apps/files_sharing/js/dist/additionalScripts.js index 1f93f3d095..79143ae714 100644 Binary files a/apps/files_sharing/js/dist/additionalScripts.js and b/apps/files_sharing/js/dist/additionalScripts.js differ diff --git a/apps/files_sharing/js/dist/additionalScripts.js.map b/apps/files_sharing/js/dist/additionalScripts.js.map index 9db2068bf9..143949c1e3 100644 Binary files a/apps/files_sharing/js/dist/additionalScripts.js.map and b/apps/files_sharing/js/dist/additionalScripts.js.map differ diff --git a/apps/files_sharing/js/dist/collaboration.js b/apps/files_sharing/js/dist/collaboration.js index 22509085e9..5dd0e126a1 100644 Binary files a/apps/files_sharing/js/dist/collaboration.js and b/apps/files_sharing/js/dist/collaboration.js differ diff --git a/apps/files_sharing/js/dist/collaboration.js.map b/apps/files_sharing/js/dist/collaboration.js.map index 0b92d9f393..ddca7ef495 100644 Binary files a/apps/files_sharing/js/dist/collaboration.js.map and b/apps/files_sharing/js/dist/collaboration.js.map differ diff --git a/apps/files_sharing/js/dist/files_sharing.4.js b/apps/files_sharing/js/dist/files_sharing.4.js index 8ac4caf8c2..7929a7a595 100644 Binary files a/apps/files_sharing/js/dist/files_sharing.4.js and b/apps/files_sharing/js/dist/files_sharing.4.js differ diff --git a/apps/files_sharing/js/dist/files_sharing.4.js.map b/apps/files_sharing/js/dist/files_sharing.4.js.map index 8e2fb48987..7ebc04b8cc 100644 Binary files a/apps/files_sharing/js/dist/files_sharing.4.js.map and b/apps/files_sharing/js/dist/files_sharing.4.js.map differ diff --git a/apps/files_sharing/js/dist/files_sharing.js.map b/apps/files_sharing/js/dist/files_sharing.js.map index 8e33e4111a..1cb98bff5e 100644 Binary files a/apps/files_sharing/js/dist/files_sharing.js.map and b/apps/files_sharing/js/dist/files_sharing.js.map differ diff --git a/apps/files_sharing/js/sharedfilelist.js b/apps/files_sharing/js/sharedfilelist.js index 7fa38a58c5..5b19830058 100644 --- a/apps/files_sharing/js/sharedfilelist.js +++ b/apps/files_sharing/js/sharedfilelist.js @@ -1,3 +1,4 @@ +/* eslint-disable */ /* * Copyright (c) 2014 Vincent Petry * @@ -25,428 +26,423 @@ * @param {boolean} [options.linksOnly] true to return only link shares */ var FileList = function($el, options) { - this.initialize($el, options); - }; + this.initialize($el, options) + } FileList.prototype = _.extend({}, OCA.Files.FileList.prototype, /** @lends OCA.Sharing.FileList.prototype */ { - appName: 'Shares', + appName: 'Shares', - /** + /** * Whether the list shows the files shared with the user (true) or * the files that the user shared with others (false). */ - _sharedWithUser: false, - _linksOnly: false, - _showDeleted: false, - _clientSideSort: true, - _allowSelection: false, - _isOverview: false, + _sharedWithUser: false, + _linksOnly: false, + _showDeleted: false, + _clientSideSort: true, + _allowSelection: false, + _isOverview: false, - /** + /** * @private */ - initialize: function($el, options) { - OCA.Files.FileList.prototype.initialize.apply(this, arguments); - if (this.initialized) { - return; - } + initialize: function($el, options) { + OCA.Files.FileList.prototype.initialize.apply(this, arguments) + if (this.initialized) { + return + } - // TODO: consolidate both options - if (options && options.sharedWithUser) { - this._sharedWithUser = true; - } - if (options && options.linksOnly) { - this._linksOnly = true; - } - if (options && options.showDeleted) { - this._showDeleted = true; - } - if (options && options.isOverview) { - this._isOverview = true; - } - }, + // TODO: consolidate both options + if (options && options.sharedWithUser) { + this._sharedWithUser = true + } + if (options && options.linksOnly) { + this._linksOnly = true + } + if (options && options.showDeleted) { + this._showDeleted = true + } + if (options && options.isOverview) { + this._isOverview = true + } + }, - _renderRow: function() { + _renderRow: function() { // HACK: needed to call the overridden _renderRow // this is because at the time this class is created // the overriding hasn't been done yet... - return OCA.Files.FileList.prototype._renderRow.apply(this, arguments); - }, + return OCA.Files.FileList.prototype._renderRow.apply(this, arguments) + }, - _createRow: function(fileData) { + _createRow: function(fileData) { // TODO: hook earlier and render the whole row here - var $tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments); - $tr.find('.filesize').remove(); - $tr.find('td.date').before($tr.children('td:first')); - $tr.find('td.filename input:checkbox').remove(); - $tr.attr('data-share-id', _.pluck(fileData.shares, 'id').join(',')); - if (this._sharedWithUser) { - $tr.attr('data-share-owner', fileData.shareOwner); - $tr.attr('data-mounttype', 'shared-root'); - var permission = parseInt($tr.attr('data-permissions')) | OC.PERMISSION_DELETE; - $tr.attr('data-permissions', permission); - } - if (this._showDeleted) { - var permission = fileData.permissions; - $tr.attr('data-share-permissions', permission); - } - - // add row with expiration date for link only shares - influenced by _createRow of filelist - if (this._linksOnly) { - var expirationTimestamp = 0; - if(fileData.shares && fileData.shares[0].expiration !== null) { - expirationTimestamp = moment(fileData.shares[0].expiration).valueOf(); + var $tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments) + $tr.find('.filesize').remove() + $tr.find('td.date').before($tr.children('td:first')) + $tr.find('td.filename input:checkbox').remove() + $tr.attr('data-share-id', _.pluck(fileData.shares, 'id').join(',')) + if (this._sharedWithUser) { + $tr.attr('data-share-owner', fileData.shareOwner) + $tr.attr('data-mounttype', 'shared-root') + var permission = parseInt($tr.attr('data-permissions')) | OC.PERMISSION_DELETE + $tr.attr('data-permissions', permission) } - $tr.attr('data-expiration', expirationTimestamp); - - // date column (1000 milliseconds to seconds, 60 seconds, 60 minutes, 24 hours) - // difference in days multiplied by 5 - brightest shade for expiry dates in more than 32 days (160/5) - var modifiedColor = Math.round((expirationTimestamp - (new Date()).getTime()) / 1000 / 60 / 60 / 24 * 5); - // ensure that the brightest color is still readable - if (modifiedColor >= 160) { - modifiedColor = 160; + if (this._showDeleted) { + var permission = fileData.permissions + $tr.attr('data-share-permissions', permission) } - var formatted; - var text; - if (expirationTimestamp > 0) { - formatted = OC.Util.formatDate(expirationTimestamp); - text = OC.Util.relativeModifiedDate(expirationTimestamp); - } else { - formatted = t('files_sharing', 'No expiration date set'); - text = ''; - modifiedColor = 160; - } - td = $('').attr({"class": "date"}); - td.append($('').attr({ - "class": "modified", - "title": formatted, - "style": 'color:rgb(' + modifiedColor + ',' + modifiedColor + ',' + modifiedColor + ')' + // add row with expiration date for link only shares - influenced by _createRow of filelist + if (this._linksOnly) { + var expirationTimestamp = 0 + if (fileData.shares && fileData.shares[0].expiration !== null) { + expirationTimestamp = moment(fileData.shares[0].expiration).valueOf() + } + $tr.attr('data-expiration', expirationTimestamp) + + // date column (1000 milliseconds to seconds, 60 seconds, 60 minutes, 24 hours) + // difference in days multiplied by 5 - brightest shade for expiry dates in more than 32 days (160/5) + var modifiedColor = Math.round((expirationTimestamp - (new Date()).getTime()) / 1000 / 60 / 60 / 24 * 5) + // ensure that the brightest color is still readable + if (modifiedColor >= 160) { + modifiedColor = 160 + } + + var formatted + var text + if (expirationTimestamp > 0) { + formatted = OC.Util.formatDate(expirationTimestamp) + text = OC.Util.relativeModifiedDate(expirationTimestamp) + } else { + formatted = t('files_sharing', 'No expiration date set') + text = '' + modifiedColor = 160 + } + td = $('').attr({ 'class': 'date' }) + td.append($('').attr({ + 'class': 'modified', + 'title': formatted, + 'style': 'color:rgb(' + modifiedColor + ',' + modifiedColor + ',' + modifiedColor + ')' }).text(text) - .tooltip({placement: 'top'}) - ); + .tooltip({ placement: 'top' }) + ) - $tr.append(td); - } - return $tr; - }, + $tr.append(td) + } + return $tr + }, - /** + /** * Set whether the list should contain outgoing shares * or incoming shares. * * @param state true for incoming shares, false otherwise */ - setSharedWithUser: function(state) { - this._sharedWithUser = !!state; - }, + setSharedWithUser: function(state) { + this._sharedWithUser = !!state + }, - updateEmptyContent: function() { - var dir = this.getCurrentDirectory(); - if (dir === '/') { + updateEmptyContent: function() { + var dir = this.getCurrentDirectory() + if (dir === '/') { // root has special permissions - this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty); - this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty); + this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty) + this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty) - // hide expiration date header for non link only shares - if (!this._linksOnly) { - this.$el.find('th.column-expiration').addClass('hidden'); + // hide expiration date header for non link only shares + if (!this._linksOnly) { + this.$el.find('th.column-expiration').addClass('hidden') + } + } else { + OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments) } - } - else { - OCA.Files.FileList.prototype.updateEmptyContent.apply(this, arguments); - } - }, + }, - getDirectoryPermissions: function() { - return OC.PERMISSION_READ | OC.PERMISSION_DELETE; - }, + getDirectoryPermissions: function() { + return OC.PERMISSION_READ | OC.PERMISSION_DELETE + }, - updateStorageStatistics: function() { + updateStorageStatistics: function() { // no op because it doesn't have // storage info like free space / used space - }, + }, - updateRow: function($tr, fileInfo, options) { + updateRow: function($tr, fileInfo, options) { // no-op, suppress re-rendering - return $tr; - }, + return $tr + }, - reload: function() { - this.showMask(); - if (this._reloadCall) { - this._reloadCall.abort(); - } - - // there is only root - this._setCurrentDir('/', false); - - var promises = []; - - var deletedShares = { - url: OC.linkToOCS('apps/files_sharing/api/v1', 2) + 'deletedshares', - /* jshint camelcase: false */ - data: { - format: 'json', - include_tags: true - }, - type: 'GET', - beforeSend: function (xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true'); - }, - }; - - var shares = { - url: OC.linkToOCS('apps/files_sharing/api/v1') + 'shares', - /* jshint camelcase: false */ - data: { - format: 'json', - shared_with_me: this._sharedWithUser !== false, - include_tags: true - }, - type: 'GET', - beforeSend: function (xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true'); - }, - }; - - var remoteShares = { - url: OC.linkToOCS('apps/files_sharing/api/v1') + 'remote_shares', - /* jshint camelcase: false */ - data: { - format: 'json', - include_tags: true - }, - type: 'GET', - beforeSend: function (xhr) { - xhr.setRequestHeader('OCS-APIREQUEST', 'true'); - }, - }; - - // Add the proper ajax requests to the list and run them - // and make sure we have 2 promises - if (this._showDeleted) { - promises.push($.ajax(deletedShares)); - } else { - promises.push($.ajax(shares)); - - if (this._sharedWithUser !== false || this._isOverview) { - promises.push($.ajax(remoteShares)); + reload: function() { + this.showMask() + if (this._reloadCall) { + this._reloadCall.abort() } - if (this._isOverview) { - shares.data.shared_with_me = !shares.data.shared_with_me; - promises.push($.ajax(shares)); + + // there is only root + this._setCurrentDir('/', false) + + var promises = [] + + var deletedShares = { + url: OC.linkToOCS('apps/files_sharing/api/v1', 2) + 'deletedshares', + /* jshint camelcase: false */ + data: { + format: 'json', + include_tags: true + }, + type: 'GET', + beforeSend: function(xhr) { + xhr.setRequestHeader('OCS-APIREQUEST', 'true') + } } - } - this._reloadCall = $.when.apply($, promises); - var callBack = this.reloadCallback.bind(this); - return this._reloadCall.then(callBack, callBack); - }, + var shares = { + url: OC.linkToOCS('apps/files_sharing/api/v1') + 'shares', + /* jshint camelcase: false */ + data: { + format: 'json', + shared_with_me: this._sharedWithUser !== false, + include_tags: true + }, + type: 'GET', + beforeSend: function(xhr) { + xhr.setRequestHeader('OCS-APIREQUEST', 'true') + } + } - reloadCallback: function(shares, remoteShares, additionalShares) { - delete this._reloadCall; - this.hideMask(); + var remoteShares = { + url: OC.linkToOCS('apps/files_sharing/api/v1') + 'remote_shares', + /* jshint camelcase: false */ + data: { + format: 'json', + include_tags: true + }, + type: 'GET', + beforeSend: function(xhr) { + xhr.setRequestHeader('OCS-APIREQUEST', 'true') + } + } - this.$el.find('#headerSharedWith').text( - t('files_sharing', this._sharedWithUser ? 'Shared by' : 'Shared with') - ); + // Add the proper ajax requests to the list and run them + // and make sure we have 2 promises + if (this._showDeleted) { + promises.push($.ajax(deletedShares)) + } else { + promises.push($.ajax(shares)) - var files = []; + if (this._sharedWithUser !== false || this._isOverview) { + promises.push($.ajax(remoteShares)) + } + if (this._isOverview) { + shares.data.shared_with_me = !shares.data.shared_with_me + promises.push($.ajax(shares)) + } + } - // make sure to use the same format - if (shares[0] && shares[0].ocs) { - shares = shares[0]; - } - if (remoteShares && remoteShares[0] && remoteShares[0].ocs) { - remoteShares = remoteShares[0]; - } - if (additionalShares && additionalShares[0] && additionalShares[0].ocs) { - additionalShares = additionalShares[0]; - } + this._reloadCall = $.when.apply($, promises) + var callBack = this.reloadCallback.bind(this) + return this._reloadCall.then(callBack, callBack) + }, - if (shares.ocs && shares.ocs.data) { - files = files.concat(this._makeFilesFromShares(shares.ocs.data, this._sharedWithUser)); - } + reloadCallback: function(shares, remoteShares, additionalShares) { + delete this._reloadCall + this.hideMask() - if (remoteShares && remoteShares.ocs && remoteShares.ocs.data) { - files = files.concat(this._makeFilesFromRemoteShares(remoteShares.ocs.data)); - } + this.$el.find('#headerSharedWith').text( + t('files_sharing', this._sharedWithUser ? 'Shared by' : 'Shared with') + ) - if (additionalShares && additionalShares.ocs && additionalShares.ocs.data) { - files = files.concat(this._makeFilesFromShares(additionalShares.ocs.data, !this._sharedWithUser)); - } + var files = [] + // make sure to use the same format + if (shares[0] && shares[0].ocs) { + shares = shares[0] + } + if (remoteShares && remoteShares[0] && remoteShares[0].ocs) { + remoteShares = remoteShares[0] + } + if (additionalShares && additionalShares[0] && additionalShares[0].ocs) { + additionalShares = additionalShares[0] + } - this.setFiles(files); - return true; - }, + if (shares.ocs && shares.ocs.data) { + files = files.concat(this._makeFilesFromShares(shares.ocs.data, this._sharedWithUser)) + } - _makeFilesFromRemoteShares: function(data) { - var files = data; + if (remoteShares && remoteShares.ocs && remoteShares.ocs.data) { + files = files.concat(this._makeFilesFromRemoteShares(remoteShares.ocs.data)) + } - files = _.chain(files) + if (additionalShares && additionalShares.ocs && additionalShares.ocs.data) { + files = files.concat(this._makeFilesFromShares(additionalShares.ocs.data, !this._sharedWithUser)) + } + + this.setFiles(files) + return true + }, + + _makeFilesFromRemoteShares: function(data) { + var files = data + + files = _.chain(files) // convert share data to file data - .map(function(share) { - var file = { - shareOwner: share.owner + '@' + share.remote.replace(/.*?:\/\//g, ""), - name: OC.basename(share.mountpoint), - mtime: share.mtime * 1000, - mimetype: share.mimetype, - type: share.type, - id: share.file_id, - path: OC.dirname(share.mountpoint), - permissions: share.permissions, - tags: share.tags || [] - }; + .map(function(share) { + var file = { + shareOwner: share.owner + '@' + share.remote.replace(/.*?:\/\//g, ''), + name: OC.basename(share.mountpoint), + mtime: share.mtime * 1000, + mimetype: share.mimetype, + type: share.type, + id: share.file_id, + path: OC.dirname(share.mountpoint), + permissions: share.permissions, + tags: share.tags || [] + } - file.shares = [{ - id: share.id, - type: OC.Share.SHARE_TYPE_REMOTE - }]; - return file; - }) - .value(); - return files; - }, + file.shares = [{ + id: share.id, + type: OC.Share.SHARE_TYPE_REMOTE + }] + return file + }) + .value() + return files + }, - /** + /** * Converts the OCS API share response data to a file info * list * @param {Array} data OCS API share array * @param {bool} sharedWithUser - * @return {Array.} array of shared file info + * @returns {Array.} array of shared file info */ - _makeFilesFromShares: function(data, sharedWithUser) { + _makeFilesFromShares: function(data, sharedWithUser) { /* jshint camelcase: false */ - var files = data; + var files = data - if (this._linksOnly) { - files = _.filter(data, function(share) { - return share.share_type === OC.Share.SHARE_TYPE_LINK; - }); - } + if (this._linksOnly) { + files = _.filter(data, function(share) { + return share.share_type === OC.Share.SHARE_TYPE_LINK + }) + } - // OCS API uses non-camelcased names - files = _.chain(files) + // OCS API uses non-camelcased names + files = _.chain(files) // convert share data to file data - .map(function(share) { + .map(function(share) { // TODO: use OC.Files.FileInfo - var file = { - id: share.file_source, - icon: OC.MimeType.getIconUrl(share.mimetype), - mimetype: share.mimetype, - tags: share.tags || [] - }; - if (share.item_type === 'folder') { - file.type = 'dir'; - file.mimetype = 'httpd/unix-directory'; - } - else { - file.type = 'file'; - } - file.share = { - id: share.id, - type: share.share_type, - target: share.share_with, - stime: share.stime * 1000, - expiration: share.expiration, - }; - if (sharedWithUser) { - file.shareOwner = share.displayname_owner; - file.shareOwnerId = share.uid_owner; - file.name = OC.basename(share.file_target); - file.path = OC.dirname(share.file_target); - file.permissions = share.permissions; - if (file.path) { - file.extraData = share.file_target; + var file = { + id: share.file_source, + icon: OC.MimeType.getIconUrl(share.mimetype), + mimetype: share.mimetype, + tags: share.tags || [] } - } - else { - if (share.share_type !== OC.Share.SHARE_TYPE_LINK) { - file.share.targetDisplayName = share.share_with_displayname; - file.share.targetShareWithId = share.share_with; + if (share.item_type === 'folder') { + file.type = 'dir' + file.mimetype = 'httpd/unix-directory' + } else { + file.type = 'file' } - file.name = OC.basename(share.path); - file.path = OC.dirname(share.path); - file.permissions = OC.PERMISSION_ALL; - if (file.path) { - file.extraData = share.path; + file.share = { + id: share.id, + type: share.share_type, + target: share.share_with, + stime: share.stime * 1000, + expiration: share.expiration } - } - return file; - }) + if (sharedWithUser) { + file.shareOwner = share.displayname_owner + file.shareOwnerId = share.uid_owner + file.name = OC.basename(share.file_target) + file.path = OC.dirname(share.file_target) + file.permissions = share.permissions + if (file.path) { + file.extraData = share.file_target + } + } else { + if (share.share_type !== OC.Share.SHARE_TYPE_LINK) { + file.share.targetDisplayName = share.share_with_displayname + file.share.targetShareWithId = share.share_with + } + file.name = OC.basename(share.path) + file.path = OC.dirname(share.path) + file.permissions = OC.PERMISSION_ALL + if (file.path) { + file.extraData = share.path + } + } + return file + }) // Group all files and have a "shares" array with // the share info for each file. // // This uses a hash memo to cumulate share information // inside the same file object (by file id). - .reduce(function(memo, file) { - var data = memo[file.id]; - var recipient = file.share.targetDisplayName; - var recipientId = file.share.targetShareWithId; - if (!data) { - data = memo[file.id] = file; - data.shares = [file.share]; - // using a hash to make them unique, - // this is only a list to be displayed - data.recipients = {}; - data.recipientData = {}; - // share types - data.shareTypes = {}; - // counter is cheaper than calling _.keys().length - data.recipientsCount = 0; - data.mtime = file.share.stime; - } - else { + .reduce(function(memo, file) { + var data = memo[file.id] + var recipient = file.share.targetDisplayName + var recipientId = file.share.targetShareWithId + if (!data) { + data = memo[file.id] = file + data.shares = [file.share] + // using a hash to make them unique, + // this is only a list to be displayed + data.recipients = {} + data.recipientData = {} + // share types + data.shareTypes = {} + // counter is cheaper than calling _.keys().length + data.recipientsCount = 0 + data.mtime = file.share.stime + } else { // always take the most recent stime - if (file.share.stime > data.mtime) { - data.mtime = file.share.stime; + if (file.share.stime > data.mtime) { + data.mtime = file.share.stime + } + data.shares.push(file.share) } - data.shares.push(file.share); - } - if (recipient) { + if (recipient) { // limit counterparts for output - if (data.recipientsCount < 4) { + if (data.recipientsCount < 4) { // only store the first ones, they will be the only ones // displayed - data.recipients[recipient] = true; - data.recipientData[data.recipientsCount] = { - 'shareWith': recipientId, - 'shareWithDisplayName': recipient - }; + data.recipients[recipient] = true + data.recipientData[data.recipientsCount] = { + 'shareWith': recipientId, + 'shareWithDisplayName': recipient + } + } + data.recipientsCount++ } - data.recipientsCount++; - } - data.shareTypes[file.share.type] = true; + data.shareTypes[file.share.type] = true - delete file.share; - return memo; - }, {}) + delete file.share + return memo + }, {}) // Retrieve only the values of the returned hash - .values() + .values() // Clean up - .each(function(data) { + .each(function(data) { // convert the recipients map to a flat // array of sorted names - data.mountType = 'shared'; - delete data.recipientsCount; - if (sharedWithUser) { + data.mountType = 'shared' + delete data.recipientsCount + if (sharedWithUser) { // only for outgoing shares - delete data.shareTypes; - } else { - data.shareTypes = _.keys(data.shareTypes); - } - }) + delete data.shareTypes + } else { + data.shareTypes = _.keys(data.shareTypes) + } + }) // Finish the chain by getting the result - .value(); + .value() - // Sort by expected sort comparator - return files.sort(this._sortComparator); - }, - }); + // Sort by expected sort comparator + return files.sort(this._sortComparator) + } + }) /** * Share info attributes. @@ -486,5 +482,5 @@ * passing to HTML data attributes with jQuery) */ - OCA.Sharing.FileList = FileList; -})(); + OCA.Sharing.FileList = FileList +})() diff --git a/apps/files_sharing/src/additionalScripts.js b/apps/files_sharing/src/additionalScripts.js index b0525a64a1..db65a2d208 100644 --- a/apps/files_sharing/src/additionalScripts.js +++ b/apps/files_sharing/src/additionalScripts.js @@ -1,6 +1,3 @@ -__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/'); -__webpack_nonce__ = btoa(OC.requestToken); - import './share' import './sharetabview' import './sharebreadcrumbview' @@ -10,4 +7,9 @@ import './style/sharebreadcrumb.scss' import './collaborationresourceshandler.js' -window.OCA.Sharing = OCA.Sharing; +// eslint-disable-next-line camelcase +__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/') +// eslint-disable-next-line camelcase +__webpack_nonce__ = btoa(OC.requestToken) + +window.OCA.Sharing = OCA.Sharing diff --git a/apps/files_sharing/src/collaborationresources.js b/apps/files_sharing/src/collaborationresources.js index 27f268be85..9c31f21bee 100644 --- a/apps/files_sharing/src/collaborationresources.js +++ b/apps/files_sharing/src/collaborationresources.js @@ -1,4 +1,4 @@ -/* +/** * @copyright Copyright (c) 2019 Julius Härtl * * @author Julius Härtl @@ -20,21 +20,23 @@ * */ -import Vue from 'vue'; -import Vuex from 'vuex'; -import { Tooltip, PopoverMenu } from 'nextcloud-vue'; -import ClickOutside from 'vue-click-outside'; +import Vue from 'vue' +import Vuex from 'vuex' +import { Tooltip, PopoverMenu } from 'nextcloud-vue' +import ClickOutside from 'vue-click-outside' -Vue.prototype.t = t; -Vue.component('PopoverMenu', PopoverMenu); -Vue.directive('ClickOutside', ClickOutside); +import View from './views/CollaborationView' + +Vue.prototype.t = t Tooltip.options.defaultHtml = false -Vue.directive('Tooltip', Tooltip); -Vue.use(Vuex); -import View from './views/CollaborationView'; +// eslint-disable-next-line vue/match-component-file-name +Vue.component('PopoverMenu', PopoverMenu) +Vue.directive('ClickOutside', ClickOutside) +Vue.directive('Tooltip', Tooltip) +Vue.use(Vuex) export { Vue, View -}; +} diff --git a/apps/files_sharing/src/collaborationresourceshandler.js b/apps/files_sharing/src/collaborationresourceshandler.js index 32e9f17ad7..1e1ebe5b54 100644 --- a/apps/files_sharing/src/collaborationresourceshandler.js +++ b/apps/files_sharing/src/collaborationresourceshandler.js @@ -1,19 +1,21 @@ -__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/'); -__webpack_nonce__ = btoa(OC.requestToken); +// eslint-disable-next-line camelcase +__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/') +// eslint-disable-next-line camelcase +__webpack_nonce__ = btoa(OC.requestToken) window.OCP.Collaboration.registerType('file', { action: () => { return new Promise((resolve, reject) => { - OC.dialogs.filepicker(t('files_sharing', 'Link to a file'), function (f) { - const client = OC.Files.getClient(); + OC.dialogs.filepicker(t('files_sharing', 'Link to a file'), function(f) { + const client = OC.Files.getClient() client.getFileInfo(f).then((status, fileInfo) => { - resolve(fileInfo.id); + resolve(fileInfo.id) }).fail(() => { - reject(); - }); - }, false, null, false, OC.dialogs.FILEPICKER_TYPE_CHOOSE, '', { allowDirectoryChooser: true }); - }); + reject(new Error('Cannot get fileinfo')) + }) + }, false, null, false, OC.dialogs.FILEPICKER_TYPE_CHOOSE, '', { allowDirectoryChooser: true }) + }) }, typeString: t('files_sharing', 'Link to a file'), typeIconClass: 'icon-files-dark' -}); +}) diff --git a/apps/files_sharing/src/files_sharing.js b/apps/files_sharing/src/files_sharing.js index 0bf695a72c..c521bb1141 100644 --- a/apps/files_sharing/src/files_sharing.js +++ b/apps/files_sharing/src/files_sharing.js @@ -1,5 +1,7 @@ -__webpack_nonce__ = btoa(OC.requestToken); -__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/'); +import '../js/app' +import '../js/sharedfilelist' -import '../js/app'; -import '../js/sharedfilelist'; +// eslint-disable-next-line camelcase +__webpack_nonce__ = btoa(OC.requestToken) +// eslint-disable-next-line camelcase +__webpack_public_path__ = OC.linkTo('files_sharing', 'js/dist/') diff --git a/apps/files_sharing/src/share.js b/apps/files_sharing/src/share.js index 32ca20f3e6..a66f166759 100644 --- a/apps/files_sharing/src/share.js +++ b/apps/files_sharing/src/share.js @@ -1,3 +1,4 @@ +/* eslint-disable */ /* * Copyright (c) 2014 * @@ -14,10 +15,10 @@ PROPERTY_SHARE_TYPES: '{' + OC.Files.Client.NS_OWNCLOUD + '}share-types', PROPERTY_OWNER_ID: '{' + OC.Files.Client.NS_OWNCLOUD + '}owner-id', PROPERTY_OWNER_DISPLAY_NAME: '{' + OC.Files.Client.NS_OWNCLOUD + '}owner-display-name' - }); + }) if (!OCA.Sharing) { - OCA.Sharing = {}; + OCA.Sharing = {} } /** * @namespace @@ -34,131 +35,130 @@ attach: function(fileList) { // core sharing is disabled/not loaded if (!OC.Share) { - return; + return } if (fileList.id === 'trashbin' || fileList.id === 'files.public') { - return; + return } - var fileActions = fileList.fileActions; - var oldCreateRow = fileList._createRow; + var fileActions = fileList.fileActions + var oldCreateRow = fileList._createRow fileList._createRow = function(fileData) { - var tr = oldCreateRow.apply(this, arguments); - var sharePermissions = OCA.Sharing.Util.getSharePermissions(fileData); - + var tr = oldCreateRow.apply(this, arguments) + var sharePermissions = OCA.Sharing.Util.getSharePermissions(fileData) + if (fileData.permissions === 0) { // no permission, disabling sidebar - delete fileActions.actions.all.Comment; - delete fileActions.actions.all.Details; - delete fileActions.actions.all.Goto; + delete fileActions.actions.all.Comment + delete fileActions.actions.all.Details + delete fileActions.actions.all.Goto } - tr.attr('data-share-permissions', sharePermissions); + tr.attr('data-share-permissions', sharePermissions) if (fileData.shareOwner) { - tr.attr('data-share-owner', fileData.shareOwner); - tr.attr('data-share-owner-id', fileData.shareOwnerId); + tr.attr('data-share-owner', fileData.shareOwner) + tr.attr('data-share-owner-id', fileData.shareOwnerId) // user should always be able to rename a mount point if (fileData.mountType === 'shared-root') { - tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE); + tr.attr('data-permissions', fileData.permissions | OC.PERMISSION_UPDATE) } } if (fileData.recipientData && !_.isEmpty(fileData.recipientData)) { - tr.attr('data-share-recipient-data', JSON.stringify(fileData.recipientData)); + tr.attr('data-share-recipient-data', JSON.stringify(fileData.recipientData)) } if (fileData.shareTypes) { - tr.attr('data-share-types', fileData.shareTypes.join(',')); + tr.attr('data-share-types', fileData.shareTypes.join(',')) } - return tr; - }; + return tr + } - var oldElementToFile = fileList.elementToFile; + var oldElementToFile = fileList.elementToFile fileList.elementToFile = function($el) { - var fileInfo = oldElementToFile.apply(this, arguments); - fileInfo.sharePermissions = $el.attr('data-share-permissions') || undefined; - fileInfo.shareOwner = $el.attr('data-share-owner') || undefined; - fileInfo.shareOwnerId = $el.attr('data-share-owner-id') || undefined; + var fileInfo = oldElementToFile.apply(this, arguments) + fileInfo.sharePermissions = $el.attr('data-share-permissions') || undefined + fileInfo.shareOwner = $el.attr('data-share-owner') || undefined + fileInfo.shareOwnerId = $el.attr('data-share-owner-id') || undefined - if( $el.attr('data-share-types')){ - fileInfo.shareTypes = $el.attr('data-share-types').split(','); + if ($el.attr('data-share-types')) { + fileInfo.shareTypes = $el.attr('data-share-types').split(',') } - if( $el.attr('data-expiration')){ - var expirationTimestamp = parseInt($el.attr('data-expiration')); - fileInfo.shares = []; - fileInfo.shares.push({expiration: expirationTimestamp}); + if ($el.attr('data-expiration')) { + var expirationTimestamp = parseInt($el.attr('data-expiration')) + fileInfo.shares = [] + fileInfo.shares.push({ expiration: expirationTimestamp }) } - return fileInfo; - }; + return fileInfo + } - var oldGetWebdavProperties = fileList._getWebdavProperties; + var oldGetWebdavProperties = fileList._getWebdavProperties fileList._getWebdavProperties = function() { - var props = oldGetWebdavProperties.apply(this, arguments); - props.push(OC.Files.Client.PROPERTY_OWNER_ID); - props.push(OC.Files.Client.PROPERTY_OWNER_DISPLAY_NAME); - props.push(OC.Files.Client.PROPERTY_SHARE_TYPES); - return props; - }; + var props = oldGetWebdavProperties.apply(this, arguments) + props.push(OC.Files.Client.PROPERTY_OWNER_ID) + props.push(OC.Files.Client.PROPERTY_OWNER_DISPLAY_NAME) + props.push(OC.Files.Client.PROPERTY_SHARE_TYPES) + return props + } fileList.filesClient.addFileInfoParser(function(response) { - var data = {}; - var props = response.propStat[0].properties; - var permissionsProp = props[OC.Files.Client.PROPERTY_PERMISSIONS]; + var data = {} + var props = response.propStat[0].properties + var permissionsProp = props[OC.Files.Client.PROPERTY_PERMISSIONS] if (permissionsProp && permissionsProp.indexOf('S') >= 0) { - data.shareOwner = props[OC.Files.Client.PROPERTY_OWNER_DISPLAY_NAME]; - data.shareOwnerId = props[OC.Files.Client.PROPERTY_OWNER_ID]; + data.shareOwner = props[OC.Files.Client.PROPERTY_OWNER_DISPLAY_NAME] + data.shareOwnerId = props[OC.Files.Client.PROPERTY_OWNER_ID] } - var shareTypesProp = props[OC.Files.Client.PROPERTY_SHARE_TYPES]; + var shareTypesProp = props[OC.Files.Client.PROPERTY_SHARE_TYPES] if (shareTypesProp) { data.shareTypes = _.chain(shareTypesProp).filter(function(xmlvalue) { - return (xmlvalue.namespaceURI === OC.Files.Client.NS_OWNCLOUD && xmlvalue.nodeName.split(':')[1] === 'share-type'); + return (xmlvalue.namespaceURI === OC.Files.Client.NS_OWNCLOUD && xmlvalue.nodeName.split(':')[1] === 'share-type') }).map(function(xmlvalue) { - return parseInt(xmlvalue.textContent || xmlvalue.text, 10); - }).value(); + return parseInt(xmlvalue.textContent || xmlvalue.text, 10) + }).value() } - return data; - }); + return data + }) // use delegate to catch the case with multiple file lists - fileList.$el.on('fileActionsReady', function(ev){ - var $files = ev.$files; + fileList.$el.on('fileActionsReady', function(ev) { + var $files = ev.$files _.each($files, function(file) { - var $tr = $(file); - var shareTypes = $tr.attr('data-share-types') || ''; - var shareOwner = $tr.attr('data-share-owner'); + var $tr = $(file) + var shareTypes = $tr.attr('data-share-types') || '' + var shareOwner = $tr.attr('data-share-owner') if (shareTypes || shareOwner) { - var hasLink = false; - var hasShares = false; + var hasLink = false + var hasShares = false _.each(shareTypes.split(',') || [], function(shareType) { - shareType = parseInt(shareType, 10); + shareType = parseInt(shareType, 10) if (shareType === OC.Share.SHARE_TYPE_LINK) { - hasLink = true; + hasLink = true } else if (shareType === OC.Share.SHARE_TYPE_EMAIL) { - hasLink = true; + hasLink = true } else if (shareType === OC.Share.SHARE_TYPE_USER) { - hasShares = true; + hasShares = true } else if (shareType === OC.Share.SHARE_TYPE_GROUP) { - hasShares = true; + hasShares = true } else if (shareType === OC.Share.SHARE_TYPE_REMOTE) { - hasShares = true; + hasShares = true } else if (shareType === OC.Share.SHARE_TYPE_CIRCLE) { - hasShares = true; + hasShares = true } else if (shareType === OC.Share.SHARE_TYPE_ROOM) { - hasShares = true; + hasShares = true } - }); - OCA.Sharing.Util._updateFileActionIcon($tr, hasShares, hasLink); + }) + OCA.Sharing.Util._updateFileActionIcon($tr, hasShares, hasLink) } - }); - }); - + }) + }) fileList.$el.on('changeDirectory', function() { - OCA.Sharing.sharesLoaded = false; - }); + OCA.Sharing.sharesLoaded = false + }) fileActions.registerAction({ name: 'Share', @@ -193,40 +193,40 @@ type: OCA.Files.FileActions.TYPE_INLINE, actionHandler: function(fileName, context) { // do not open sidebar if permission is set and equal to 0 - var permissions = parseInt(context.$file.data('share-permissions'), 10); + var permissions = parseInt(context.$file.data('share-permissions'), 10) if (isNaN(permissions) || permissions > 0) { - fileList.showDetailsView(fileName, 'shareTabView'); + fileList.showDetailsView(fileName, 'shareTabView') } }, render: function(actionSpec, isDefault, context) { - var permissions = parseInt(context.$file.data('permissions'), 10); + var permissions = parseInt(context.$file.data('permissions'), 10) // if no share permissions but share owner exists, still show the link if ((permissions & OC.PERMISSION_SHARE) !== 0 || context.$file.attr('data-share-owner')) { - return fileActions._defaultRenderAction.call(fileActions, actionSpec, isDefault, context); + return fileActions._defaultRenderAction.call(fileActions, actionSpec, isDefault, context) } // don't render anything - return null; + return null } - }); + }) - var shareTab = new OCA.Sharing.ShareTabView('shareTabView', {order: -20}); + var shareTab = new OCA.Sharing.ShareTabView('shareTabView', { order: -20 }) // detect changes and change the matching list entry shareTab.on('sharesChanged', function(shareModel) { - var fileInfoModel = shareModel.fileInfoModel; - var $tr = fileList.findFileEl(fileInfoModel.get('name')); + var fileInfoModel = shareModel.fileInfoModel + var $tr = fileList.findFileEl(fileInfoModel.get('name')) // We count email shares as link share - var hasLinkShares = shareModel.hasLinkShares(); - shareModel.get('shares').forEach(function (share) { + var hasLinkShares = shareModel.hasLinkShares() + shareModel.get('shares').forEach(function(share) { if (share.share_type === OC.Share.SHARE_TYPE_EMAIL) { - hasLinkShares = true; + hasLinkShares = true } - }); + }) - OCA.Sharing.Util._updateFileListDataAttributes(fileList, $tr, shareModel); + OCA.Sharing.Util._updateFileListDataAttributes(fileList, $tr, shareModel) if (!OCA.Sharing.Util._updateFileActionIcon($tr, shareModel.hasUserShares(), hasLinkShares)) { // remove icon, if applicable - OC.Share.markFileAsShared($tr, false, false); + OC.Share.markFileAsShared($tr, false, false) } // FIXME: this is too convoluted. We need to get rid of the above updates @@ -237,12 +237,12 @@ // we need to modify the model // (FIXME: yes, this is hacky) icon: $tr.attr('data-icon') - }); - }); - fileList.registerTabView(shareTab); + }) + }) + fileList.registerTabView(shareTab) - var breadCrumbSharingDetailView = new OCA.Sharing.ShareBreadCrumbView({shareTab: shareTab}); - fileList.registerBreadCrumbDetailView(breadCrumbSharingDetailView); + var breadCrumbSharingDetailView = new OCA.Sharing.ShareBreadCrumbView({ shareTab: shareTab }) + fileList.registerBreadCrumbDetailView(breadCrumbSharingDetailView) }, /** @@ -252,18 +252,17 @@ // files app current cannot show recipients on load, so we don't update the // icon when changed for consistency if (fileList.id === 'files') { - return; + return } - var recipients = _.pluck(shareModel.get('shares'), 'share_with_displayname'); + var recipients = _.pluck(shareModel.get('shares'), 'share_with_displayname') // note: we only update the data attribute because updateIcon() if (recipients.length) { - var recipientData = _.mapObject(shareModel.get('shares'), function (share) { - return {shareWith: share.share_with, shareWithDisplayName: share.share_with_displayname}; - }); - $tr.attr('data-share-recipient-data', JSON.stringify(recipientData)); - } - else { - $tr.removeAttr('data-share-recipient-data'); + var recipientData = _.mapObject(shareModel.get('shares'), function(share) { + return { shareWith: share.share_with, shareWithDisplayName: share.share_with_displayname } + }) + $tr.attr('data-share-recipient-data', JSON.stringify(recipientData)) + } else { + $tr.removeAttr('data-share-recipient-data') } }, @@ -274,16 +273,16 @@ * @param {boolean} hasUserShares true if a user share exists * @param {boolean} hasLinkShares true if a link share exists * - * @return {boolean} true if the icon was set, false otherwise + * @returns {boolean} true if the icon was set, false otherwise */ _updateFileActionIcon: function($tr, hasUserShares, hasLinkShares) { // if the statuses are loaded already, use them for the icon // (needed when scrolling to the next page) if (hasUserShares || hasLinkShares || $tr.attr('data-share-recipient-data') || $tr.attr('data-share-owner')) { - OC.Share.markFileAsShared($tr, true, hasLinkShares); - return true; + OC.Share.markFileAsShared($tr, true, hasLinkShares) + return true } - return false; + return false }, /** @@ -291,9 +290,9 @@ * @returns {String} */ getSharePermissions: function(fileData) { - return fileData.sharePermissions; + return fileData.sharePermissions } - }; -})(); + } +})() -OC.Plugins.register('OCA.Files.FileList', OCA.Sharing.Util); +OC.Plugins.register('OCA.Files.FileList', OCA.Sharing.Util) diff --git a/apps/files_sharing/src/sharebreadcrumbview.js b/apps/files_sharing/src/sharebreadcrumbview.js index 17e3eae0bf..a90c94b6d7 100644 --- a/apps/files_sharing/src/sharebreadcrumbview.js +++ b/apps/files_sharing/src/sharebreadcrumbview.js @@ -1,5 +1,3 @@ -/* global Handlebars, OC */ - /** * @copyright 2016 Christoph Wurst * @@ -23,7 +21,7 @@ */ (function() { - 'use strict'; + 'use strict' var BreadCrumbView = OC.Backbone.View.extend({ tagName: 'span', @@ -36,68 +34,68 @@ _shareTab: undefined, initialize: function(options) { - this._shareTab = options.shareTab; + this._shareTab = options.shareTab }, render: function(data) { - this._dirInfo = data.dirInfo || null; + this._dirInfo = data.dirInfo || null if (this._dirInfo !== null && (this._dirInfo.path !== '/' || this._dirInfo.name !== '')) { - var isShared = data.dirInfo && data.dirInfo.shareTypes && data.dirInfo.shareTypes.length > 0; - this.$el.removeClass('shared icon-public icon-shared'); + var isShared = data.dirInfo && data.dirInfo.shareTypes && data.dirInfo.shareTypes.length > 0 + this.$el.removeClass('shared icon-public icon-shared') if (isShared) { - this.$el.addClass('shared'); + this.$el.addClass('shared') if (data.dirInfo.shareTypes.indexOf(OC.Share.SHARE_TYPE_LINK) !== -1) { - this.$el.addClass('icon-public'); + this.$el.addClass('icon-public') } else { - this.$el.addClass('icon-shared'); + this.$el.addClass('icon-shared') } } else { - this.$el.addClass('icon-shared'); + this.$el.addClass('icon-shared') } - this.$el.show(); - this.delegateEvents(); + this.$el.show() + this.delegateEvents() } else { - this.$el.removeClass('shared icon-public icon-shared'); - this.$el.hide(); + this.$el.removeClass('shared icon-public icon-shared') + this.$el.hide() } - return this; + return this }, _onClick: function(e) { - e.preventDefault(); + e.preventDefault() - var fileInfoModel = new OCA.Files.FileInfoModel(this._dirInfo); - var self = this; + var fileInfoModel = new OCA.Files.FileInfoModel(this._dirInfo) + var self = this fileInfoModel.on('change', function() { self.render({ dirInfo: self._dirInfo - }); - }); + }) + }) this._shareTab.on('sharesChanged', function(shareModel) { - var shareTypes = []; - var shares = shareModel.getSharesWithCurrentItem(); + var shareTypes = [] + var shares = shareModel.getSharesWithCurrentItem() - for(var i = 0; i < shares.length; i++) { + for (var i = 0; i < shares.length; i++) { if (shareTypes.indexOf(shares[i].share_type) === -1) { - shareTypes.push(shares[i].share_type); + shareTypes.push(shares[i].share_type) } } if (shareModel.hasLinkShares()) { - shareTypes.push(OC.Share.SHARE_TYPE_LINK); + shareTypes.push(OC.Share.SHARE_TYPE_LINK) } // Since the dirInfo isn't updated we need to do this dark hackery - self._dirInfo.shareTypes = shareTypes; + self._dirInfo.shareTypes = shareTypes self.render({ dirInfo: self._dirInfo - }); - }); - OCA.Files.App.fileList.showDetailsView(fileInfoModel, 'shareTabView'); + }) + }) + OCA.Files.App.fileList.showDetailsView(fileInfoModel, 'shareTabView') } - }); + }) - OCA.Sharing.ShareBreadCrumbView = BreadCrumbView; -})(); + OCA.Sharing.ShareBreadCrumbView = BreadCrumbView +})() diff --git a/apps/files_sharing/src/sharetabview.js b/apps/files_sharing/src/sharetabview.js index 44c863fbe9..da0708b85a 100644 --- a/apps/files_sharing/src/sharetabview.js +++ b/apps/files_sharing/src/sharetabview.js @@ -11,77 +11,77 @@ /* @global Handlebars */ (function() { - var TEMPLATE = - '
    ' + - '
    ' + - '
    ' + - '
    '; + var TEMPLATE + = '
    ' + + '
    ' + + '
    ' + + '
    ' /** * @memberof OCA.Sharing */ var ShareTabView = OCA.Files.DetailTabView.extend( /** @lends OCA.Sharing.ShareTabView.prototype */ { - id: 'shareTabView', - className: 'tab shareTabView', + id: 'shareTabView', + className: 'tab shareTabView', - initialize: function(name, options) { - OCA.Files.DetailTabView.prototype.initialize.call(this, name, options); - OC.Plugins.attach('OCA.Sharing.ShareTabView', this); - }, + initialize: function(name, options) { + OCA.Files.DetailTabView.prototype.initialize.call(this, name, options) + OC.Plugins.attach('OCA.Sharing.ShareTabView', this) + }, - template: function(params) { - return TEMPLATE; - }, + template: function(params) { + return TEMPLATE + }, - getLabel: function() { - return t('files_sharing', 'Sharing'); - }, + getLabel: function() { + return t('files_sharing', 'Sharing') + }, - getIcon: function() { - return 'icon-shared'; - }, + getIcon: function() { + return 'icon-shared' + }, - /** + /** * Renders this details view */ - render: function() { - var self = this; - if (this._dialog) { + render: function() { + var self = this + if (this._dialog) { // remove/destroy older instance - this._dialog.model.off(); - this._dialog.remove(); - this._dialog = null; - } - - if (this.model) { - this.$el.html(this.template()); - - if (_.isUndefined(this.model.get('sharePermissions'))) { - this.model.set('sharePermissions', OCA.Sharing.Util.getSharePermissions(this.model.attributes)); + this._dialog.model.off() + this._dialog.remove() + this._dialog = null } - // TODO: the model should read these directly off the passed fileInfoModel - var attributes = { - itemType: this.model.isDirectory() ? 'folder' : 'file', - itemSource: this.model.get('id'), - possiblePermissions: this.model.get('sharePermissions') - }; - var configModel = new OC.Share.ShareConfigModel(); - var shareModel = new OC.Share.ShareItemModel(attributes, { - configModel: configModel, - fileInfoModel: this.model - }); - this._dialog = new OC.Share.ShareDialogView({ - configModel: configModel, - model: shareModel - }); - this.$el.find('.dialogContainer').append(this._dialog.$el); - this._dialog.render(); - this._dialog.model.fetch(); - this._dialog.model.on('change', function() { - self.trigger('sharesChanged', shareModel); - }); + if (this.model) { + this.$el.html(this.template()) + + if (_.isUndefined(this.model.get('sharePermissions'))) { + this.model.set('sharePermissions', OCA.Sharing.Util.getSharePermissions(this.model.attributes)) + } + + // TODO: the model should read these directly off the passed fileInfoModel + var attributes = { + itemType: this.model.isDirectory() ? 'folder' : 'file', + itemSource: this.model.get('id'), + possiblePermissions: this.model.get('sharePermissions') + } + var configModel = new OC.Share.ShareConfigModel() + var shareModel = new OC.Share.ShareItemModel(attributes, { + configModel: configModel, + fileInfoModel: this.model + }) + this._dialog = new OC.Share.ShareDialogView({ + configModel: configModel, + model: shareModel + }) + this.$el.find('.dialogContainer').append(this._dialog.$el) + this._dialog.render() + this._dialog.model.fetch() + this._dialog.model.on('change', function() { + self.trigger('sharesChanged', shareModel) + }) import('./collaborationresources').then((Resources) => { var vm = new Resources.Vue({ @@ -89,20 +89,19 @@ render: h => h(Resources.View), data: { model: this.model.toJSON() - }, - }); + } + }) this.model.on('change', () => { vm.data = this.model.toJSON() }) }) - } else { - this.$el.empty(); + } else { + this.$el.empty() // TODO: render placeholder text? + } + this.trigger('rendered') } - this.trigger('rendered'); - } - }); - - OCA.Sharing.ShareTabView = ShareTabView; -})(); + }) + OCA.Sharing.ShareTabView = ShareTabView +})() diff --git a/apps/files_sharing/src/views/CollaborationView.vue b/apps/files_sharing/src/views/CollaborationView.vue index 0307488b5a..5cfcd299cc 100644 --- a/apps/files_sharing/src/views/CollaborationView.vue +++ b/apps/files_sharing/src/views/CollaborationView.vue @@ -21,7 +21,10 @@ --> diff --git a/apps/files_trashbin/js/files_trashbin.js b/apps/files_trashbin/js/files_trashbin.js index ceab18813b..d381919b0a 100644 --- a/apps/files_trashbin/js/files_trashbin.js +++ b/apps/files_trashbin/js/files_trashbin.js @@ -1,2 +1,2 @@ -!function(e){var t={};function i(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.m=e,i.c=t,i.d=function(e,t,n){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(i.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)i.d(n,r,function(t){return e[t]}.bind(null,r));return n},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/js/",i(i.s=0)}([function(e,t,i){"use strict";i.r(t);i(1),i(2),i(3);window.OCA.Trashbin=OCA.Trashbin},function(e,i){OCA.Trashbin={},OCA.Trashbin.App={_initialized:!1,client:null,initialize:function(e){if(!this._initialized){this._initialized=!0,this.client=new OC.Files.Client({host:OC.getHost(),port:OC.getPort(),root:OC.linkToRemoteBase("dav")+"/trashbin/"+OC.getCurrentUser().uid,useHTTPS:"https"===OC.getProtocol()});var i=OC.Util.History.parseUrlQuery();this.fileList=new OCA.Trashbin.FileList($("#app-content-trashbin"),{fileActions:this._createFileActions(),detailsViewEnabled:!1,scrollTo:i.scrollto,config:OCA.Files.App.getFilesConfig(),multiSelectMenu:[{name:"restore",displayName:t("files_trashbin","Restore"),iconClass:"icon-history"},{name:"delete",displayName:t("files_trashbin","Delete permanently"),iconClass:"icon-delete"}],client:this.client,shown:!0})}},_createFileActions:function(){var e=this.client,i=new OCA.Files.FileActions;return i.register("dir","Open",OC.PERMISSION_READ,"",(function(e,t){var i=t.fileList.getCurrentDirectory();t.fileList.changeDirectory(OC.joinPaths(i,e))})),i.setDefault("dir","Open"),i.registerAction({name:"Restore",displayName:t("files_trashbin","Restore"),type:OCA.Files.FileActions.TYPE_INLINE,mime:"all",permissions:OC.PERMISSION_READ,iconClass:"icon-history",actionHandler:function(i,n){var r=n.fileList,a=r.findFileEl(i);r.showFileBusyState(a,!0);var o=n.fileList.getCurrentDirectory();e.move(OC.joinPaths("trash",o,i),OC.joinPaths("restore",i),!0).then(r._removeCallback.bind(r,[i]),(function(){r.showFileBusyState(a,!1),OC.Notification.show(t("files_trashbin","Error while restoring file from trashbin"))}))}}),i.registerAction({name:"Delete",displayName:t("files_trashbin","Delete permanently"),mime:"all",permissions:OC.PERMISSION_READ,iconClass:"icon-delete",render:function(e,n,r){var a=i._makeActionLink(e,r);return a.attr("original-title",t("files_trashbin","Delete permanently")),a.children("img").attr("alt",t("files_trashbin","Delete permanently")),r.$file.find("td:last").append(a),a},actionHandler:function(i,n){var r=n.fileList;$(".tipsy").remove();var a=r.findFileEl(i);r.showFileBusyState(a,!0);var o=n.fileList.getCurrentDirectory();e.remove(OC.joinPaths("trash",o,i)).then(r._removeCallback.bind(r,[i]),(function(){r.showFileBusyState(a,!1),OC.Notification.show(t("files_trashbin","Error while removing file from trashbin"))}))}}),i}},$(document).ready((function(){$("#app-content-trashbin").one("show",(function(){OCA.Trashbin.App.initialize($("#app-content-trashbin"))}))}))},function(e,i){!function(){var e=new RegExp(/^(.+)\.d[0-9]+$/),i="{http://nextcloud.org/ns}trashbin-filename",n="{http://nextcloud.org/ns}trashbin-deletion-time",r="{http://nextcloud.org/ns}trashbin-original-location";function a(t){t=OC.basename(t);var i=e.exec(t);return i&&i.length>1&&(t=i[1]),t}var o=function(e,t){this.client=t.client,this.initialize(e,t)};o.prototype=_.extend({},OCA.Files.FileList.prototype,{id:"trashbin",appName:t("files_trashbin","Deleted files"),client:null,initialize:function(){this.client.addFileInfoParser((function(e,t){var a=e.propStat[0].properties,o=a[r];return{displayName:a[i],mtime:1e3*parseInt(a[n],10),hasPreview:!0,path:o,extraData:o}}));var e=OCA.Files.FileList.prototype.initialize.apply(this,arguments);return this.$el.find(".undelete").click("click",_.bind(this._onClickRestoreSelected,this)),this.setSort("mtime","desc"),this.breadcrumb._makeCrumbs=function(){for(var e=OCA.Files.BreadCrumb.prototype._makeCrumbs.apply(this,arguments),t=1;t1&&(t=i[1]),t}var o=function(e,t){this.client=t.client,this.initialize(e,t)};o.prototype=_.extend({},OCA.Files.FileList.prototype,{id:"trashbin",appName:t("files_trashbin","Deleted files"),client:null,initialize:function(){this.client.addFileInfoParser((function(e,t){var a=e.propStat[0].properties,o=a[r];return{displayName:a[i],mtime:1e3*parseInt(a[n],10),hasPreview:!0,path:o,extraData:o}}));var e=OCA.Files.FileList.prototype.initialize.apply(this,arguments);return this.$el.find(".undelete").click("click",_.bind(this._onClickRestoreSelected,this)),this.setSort("mtime","desc"),this.breadcrumb._makeCrumbs=function(){for(var e=OCA.Files.BreadCrumb.prototype._makeCrumbs.apply(this,arguments),t=1;ti.parts.length&&(n.parts.length=i.parts.length)}else{var o=[];for(r=0;r 1) {\n\t\t\tname = match[1];\n\t\t}\n\t\treturn name;\n\t}\n\n\t/**\n\t * @class OCA.Trashbin.FileList\n\t * @augments OCA.Files.FileList\n\t * @classdesc List of deleted files\n\t *\n\t * @param $el container element with existing markup for the #controls\n\t * and a table\n\t * @param [options] map of options\n\t */\n\tvar FileList = function($el, options) {\n\t\tthis.client = options.client;\n\t\tthis.initialize($el, options);\n\t};\n\tFileList.prototype = _.extend({}, OCA.Files.FileList.prototype,\n\t\t/** @lends OCA.Trashbin.FileList.prototype */ {\n\t\tid: 'trashbin',\n\t\tappName: t('files_trashbin', 'Deleted files'),\n\t\t/** @type {OC.Files.Client} */\n\t\tclient: null,\n\n\t\t/**\n\t\t * @private\n\t\t */\n\t\tinitialize: function() {\n\t\t\tthis.client.addFileInfoParser(function(response, data) {\n\t\t\t\tvar props = response.propStat[0].properties;\n\t\t\t\tvar path = props[TRASHBIN_ORIGINAL_LOCATION];\n\t\t\t\treturn {\n\t\t\t\t\tdisplayName: props[FILENAME_PROP],\n\t\t\t\t\tmtime: parseInt(props[DELETION_TIME_PROP], 10) * 1000,\n\t\t\t\t\thasPreview: true,\n\t\t\t\t\tpath: path,\n\t\t\t\t\textraData: path\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tvar result = OCA.Files.FileList.prototype.initialize.apply(this, arguments);\n\t\t\tthis.$el.find('.undelete').click('click', _.bind(this._onClickRestoreSelected, this));\n\n\t\t\tthis.setSort('mtime', 'desc');\n\t\t\t/**\n\t\t\t * Override crumb making to add \"Deleted Files\" entry\n\t\t\t * and convert files with \".d\" extensions to a more\n\t\t\t * user friendly name.\n\t\t\t */\n\t\t\tthis.breadcrumb._makeCrumbs = function() {\n\t\t\t\tvar parts = OCA.Files.BreadCrumb.prototype._makeCrumbs.apply(this, arguments);\n\t\t\t\tfor (var i = 1; i < parts.length; i++) {\n\t\t\t\t\tparts[i].name = getDeletedFileName(parts[i].name);\n\t\t\t\t}\n\t\t\t\treturn parts;\n\t\t\t};\n\n\t\t\tOC.Plugins.attach('OCA.Trashbin.FileList', this);\n\t\t\treturn result;\n\t\t},\n\n\t\t/**\n\t\t * Override to only return read permissions\n\t\t */\n\t\tgetDirectoryPermissions: function() {\n\t\t\treturn OC.PERMISSION_READ | OC.PERMISSION_DELETE;\n\t\t},\n\n\t\t_setCurrentDir: function(targetDir) {\n\t\t\tOCA.Files.FileList.prototype._setCurrentDir.apply(this, arguments);\n\n\t\t\tvar baseDir = OC.basename(targetDir);\n\t\t\tif (baseDir !== '') {\n\t\t\t\tthis.setPageTitle(getDeletedFileName(baseDir));\n\t\t\t}\n\t\t},\n\n\t\t_createRow: function() {\n\t\t\t// FIXME: MEGAHACK until we find a better solution\n\t\t\tvar tr = OCA.Files.FileList.prototype._createRow.apply(this, arguments);\n\t\t\ttr.find('td.filesize').remove();\n\t\t\treturn tr;\n\t\t},\n\n\t\tgetAjaxUrl: function(action, params) {\n\t\t\tvar q = '';\n\t\t\tif (params) {\n\t\t\t\tq = '?' + OC.buildQueryString(params);\n\t\t\t}\n\t\t\treturn OC.filePath('files_trashbin', 'ajax', action + '.php') + q;\n\t\t},\n\n\t\tsetupUploadEvents: function() {\n\t\t\t// override and do nothing\n\t\t},\n\n\t\tlinkTo: function(dir){\n\t\t\treturn OC.linkTo('files', 'index.php')+\"?view=trashbin&dir=\"+ encodeURIComponent(dir).replace(/%2F/g, '/');\n\t\t},\n\n\t\telementToFile: function($el) {\n\t\t\tvar fileInfo = OCA.Files.FileList.prototype.elementToFile($el);\n\t\t\tif (this.getCurrentDirectory() === '/') {\n\t\t\t\tfileInfo.displayName = getDeletedFileName(fileInfo.name);\n\t\t\t}\n\t\t\t// no size available\n\t\t\tdelete fileInfo.size;\n\t\t\treturn fileInfo;\n\t\t},\n\n\t\tupdateEmptyContent: function(){\n\t\t\tvar exists = this.$fileList.find('tr:first').exists();\n\t\t\tthis.$el.find('#emptycontent').toggleClass('hidden', exists);\n\t\t\tthis.$el.find('#filestable th').toggleClass('hidden', !exists);\n\t\t},\n\n\t\t_removeCallback: function(files) {\n\t\t\tvar $el;\n\t\t\tfor (var i = 0; i < files.length; i++) {\n\t\t\t\t$el = this.remove(OC.basename(files[i]), {updateSummary: false});\n\t\t\t\tthis.fileSummary.remove({type: $el.attr('data-type'), size: $el.attr('data-size')});\n\t\t\t}\n\t\t\tthis.fileSummary.update();\n\t\t\tthis.updateEmptyContent();\n\t\t},\n\n\t\t_onClickRestoreSelected: function(event) {\n\t\t\tevent.preventDefault();\n\t\t\tvar self = this;\n\t\t\tvar files = _.pluck(this.getSelectedFiles(), 'name');\n\t\t\tfor (var i = 0; i < files.length; i++) {\n\t\t\t\tvar tr = this.findFileEl(files[i]);\n\t\t\t\tthis.showFileBusyState(tr, true);\n\t\t\t}\n\n\t\t\tthis.fileMultiSelectMenu.toggleLoading('restore', true);\n\t\t\tvar restorePromises = files.map(function(file) {\n\t\t\t\treturn self.client.move(OC.joinPaths('trash', self.getCurrentDirectory(), file), OC.joinPaths('restore', file), true)\n\t\t\t\t\t.then(\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\tself._removeCallback([file]);\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t});\n\t\t\treturn Promise.all(restorePromises).then(\n\t\t\t\tfunction() {\n\t\t\t\t\tself.fileMultiSelectMenu.toggleLoading('restore', false);\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tOC.Notification.show(t('files_trashbin', 'Error while restoring files from trashbin'));\n\t\t\t\t}\n\t\t\t);\n\t\t},\n\n\t\t_onClickDeleteSelected: function(event) {\n\t\t\tevent.preventDefault();\n\t\t\tvar self = this;\n\t\t\tvar allFiles = this.$el.find('.select-all').is(':checked');\n\t\t\tvar files = _.pluck(this.getSelectedFiles(), 'name');\n\t\t\tfor (var i = 0; i < files.length; i++) {\n\t\t\t\tvar tr = this.findFileEl(files[i]);\n\t\t\t\tthis.showFileBusyState(tr, true);\n\t\t\t}\n\n\t\t\tif (allFiles) {\n\t\t\t\treturn this.client.remove(OC.joinPaths('trash', this.getCurrentDirectory()))\n\t\t\t\t\t.then(\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\tself.hideMask();\n\t\t\t\t\t\t\tself.setFiles([]);\n\t\t\t\t\t\t},\n\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\tOC.Notification.show(t('files_trashbin', 'Error while emptying trashbin'));\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.fileMultiSelectMenu.toggleLoading('delete', true);\n\t\t\t\tvar deletePromises = files.map(function(file) {\n\t\t\t\t\treturn self.client.remove(OC.joinPaths('trash', self.getCurrentDirectory(), file))\n\t\t\t\t\t\t.then(\n\t\t\t\t\t\t\tfunction() {\n\t\t\t\t\t\t\t\tself._removeCallback([file]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\treturn Promise.all(deletePromises).then(\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\tself.fileMultiSelectMenu.toggleLoading('delete', false);\n\t\t\t\t\t},\n\t\t\t\t\tfunction() {\n\t\t\t\t\t\tOC.Notification.show(t('files_trashbin', 'Error while removing files from trashbin'));\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\t\t},\n\n\t\t_onClickFile: function(event) {\n\t\t\tvar mime = $(this).parent().parent().data('mime');\n\t\t\tif (mime !== 'httpd/unix-directory') {\n\t\t\t\tevent.preventDefault();\n\t\t\t}\n\t\t\treturn OCA.Files.FileList.prototype._onClickFile.apply(this, arguments);\n\t\t},\n\n\t\tgeneratePreviewUrl: function(urlSpec) {\n\t\t\treturn OC.generateUrl('/apps/files_trashbin/preview?') + $.param(urlSpec);\n\t\t},\n\n\t\tgetDownloadUrl: function() {\n\t\t\t// no downloads\n\t\t\treturn '#';\n\t\t},\n\n\t\tupdateStorageStatistics: function() {\n\t\t\t// no op because the trashbin doesn't have\n\t\t\t// storage info like free space / used space\n\t\t},\n\n\t\tisSelectedDeletable: function() {\n\t\t\treturn true;\n\t\t},\n\n\t\t/**\n\t\t * Returns list of webdav properties to request\n\t\t */\n\t\t_getWebdavProperties: function() {\n\t\t\treturn [FILENAME_PROP, DELETION_TIME_PROP, TRASHBIN_ORIGINAL_LOCATION].concat(this.filesClient.getPropfindProperties());\n\t\t},\n\n\t\t/**\n\t\t * Reloads the file list using ajax call\n\t\t *\n\t\t * @return ajax call object\n\t\t */\n\t\treload: function() {\n\t\t\tthis._selectedFiles = {};\n\t\t\tthis._selectionSummary.clear();\n\t\t\tthis.$el.find('.select-all').prop('checked', false);\n\t\t\tthis.showMask();\n\t\t\tif (this._reloadCall) {\n\t\t\t\tthis._reloadCall.abort();\n\t\t\t}\n\t\t\tthis._reloadCall = this.client.getFolderContents(\n\t\t\t\t'trash/' + this.getCurrentDirectory(), {\n\t\t\t\t\tincludeParent: false,\n\t\t\t\t\tproperties: this._getWebdavProperties()\n\t\t\t\t}\n\t\t\t);\n\t\t\tvar callBack = this.reloadCallback.bind(this);\n\t\t\treturn this._reloadCall.then(callBack, callBack);\n\t\t},\n\t\treloadCallback: function(status, result) {\n\t\t\tdelete this._reloadCall;\n\t\t\tthis.hideMask();\n\n\t\t\tif (status === 401) {\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Firewall Blocked request?\n\t\t\tif (status === 403) {\n\t\t\t\t// Go home\n\t\t\t\tthis.changeDirectory('/');\n\t\t\t\tOC.Notification.show(t('files', 'This operation is forbidden'));\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\t// Did share service die or something else fail?\n\t\t\tif (status === 500) {\n\t\t\t\t// Go home\n\t\t\t\tthis.changeDirectory('/');\n\t\t\t\tOC.Notification.show(t('files', 'This directory is unavailable, please check the logs or contact the administrator'));\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tif (status === 404) {\n\t\t\t\t// go back home\n\t\t\t\tthis.changeDirectory('/');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// aborted ?\n\t\t\tif (status === 0){\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tthis.setFiles(result);\n\t\t\treturn true;\n\t\t},\n\n\t});\n\n\tOCA.Trashbin.FileList = FileList;\n})();\n\n","var content = require(\"!!../../../node_modules/css-loader/dist/cjs.js!../../../node_modules/sass-loader/dist/cjs.js!./trash.scss\");\n\nif (typeof content === 'string') {\n content = [[module.id, content, '']];\n}\n\nvar options = {}\n\noptions.insert = \"head\";\noptions.singleton = false;\n\nvar update = require(\"!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\")(content, options);\n\nif (content.locals) {\n module.exports = content.locals;\n}\n","exports = module.exports = require(\"../../../node_modules/css-loader/dist/runtime/api.js\")(false);\n// Module\nexports.push([module.id, \"#app-content-trashbin tbody tr[data-type=\\\"file\\\"] td a.name,#app-content-trashbin tbody tr[data-type=\\\"file\\\"] td a.name span.nametext,#app-content-trashbin tbody tr[data-type=\\\"file\\\"] td a.name span.nametext span{cursor:default}#app-content-trashbin .summary :last-child{padding:0}#app-content-trashbin #filestable .summary .filesize{display:none}\\n\", \"\"]);\n","\"use strict\";\n\n/*\n MIT License http://www.opensource.org/licenses/mit-license.php\n Author Tobias Koppers @sokra\n*/\n// css base code, injected by the css-loader\n// eslint-disable-next-line func-names\nmodule.exports = function (useSourceMap) {\n var list = []; // return the list of modules as css string\n\n list.toString = function toString() {\n return this.map(function (item) {\n var content = cssWithMappingToString(item, useSourceMap);\n\n if (item[2]) {\n return \"@media \".concat(item[2], \"{\").concat(content, \"}\");\n }\n\n return content;\n }).join('');\n }; // import a list of modules into the list\n // eslint-disable-next-line func-names\n\n\n list.i = function (modules, mediaQuery) {\n if (typeof modules === 'string') {\n // eslint-disable-next-line no-param-reassign\n modules = [[null, modules, '']];\n }\n\n var alreadyImportedModules = {};\n\n for (var i = 0; i < this.length; i++) {\n // eslint-disable-next-line prefer-destructuring\n var id = this[i][0];\n\n if (id != null) {\n alreadyImportedModules[id] = true;\n }\n }\n\n for (var _i = 0; _i < modules.length; _i++) {\n var item = modules[_i]; // skip already imported module\n // this implementation is not 100% perfect for weird media query combinations\n // when a module is imported multiple times with different media queries.\n // I hope this will never occur (Hey this way we have smaller bundles)\n\n if (item[0] == null || !alreadyImportedModules[item[0]]) {\n if (mediaQuery && !item[2]) {\n item[2] = mediaQuery;\n } else if (mediaQuery) {\n item[2] = \"(\".concat(item[2], \") and (\").concat(mediaQuery, \")\");\n }\n\n list.push(item);\n }\n }\n };\n\n return list;\n};\n\nfunction cssWithMappingToString(item, useSourceMap) {\n var content = item[1] || ''; // eslint-disable-next-line prefer-destructuring\n\n var cssMapping = item[3];\n\n if (!cssMapping) {\n return content;\n }\n\n if (useSourceMap && typeof btoa === 'function') {\n var sourceMapping = toComment(cssMapping);\n var sourceURLs = cssMapping.sources.map(function (source) {\n return \"/*# sourceURL=\".concat(cssMapping.sourceRoot).concat(source, \" */\");\n });\n return [content].concat(sourceURLs).concat([sourceMapping]).join('\\n');\n }\n\n return [content].join('\\n');\n} // Adapted from convert-source-map (MIT)\n\n\nfunction toComment(sourceMap) {\n // eslint-disable-next-line no-undef\n var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));\n var data = \"sourceMappingURL=data:application/json;charset=utf-8;base64,\".concat(base64);\n return \"/*# \".concat(data, \" */\");\n}","\"use strict\";\n\nvar stylesInDom = {};\n\nvar isOldIE = function isOldIE() {\n var memo;\n return function memorize() {\n if (typeof memo === 'undefined') {\n // Test for IE <= 9 as proposed by Browserhacks\n // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805\n // Tests for existence of standard globals is to allow style-loader\n // to operate correctly into non-standard environments\n // @see https://github.com/webpack-contrib/style-loader/issues/177\n memo = Boolean(window && document && document.all && !window.atob);\n }\n\n return memo;\n };\n}();\n\nvar getTarget = function getTarget() {\n var memo = {};\n return function memorize(target) {\n if (typeof memo[target] === 'undefined') {\n var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself\n\n if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {\n try {\n // This will throw an exception if access to iframe is blocked\n // due to cross-origin restrictions\n styleTarget = styleTarget.contentDocument.head;\n } catch (e) {\n // istanbul ignore next\n styleTarget = null;\n }\n }\n\n memo[target] = styleTarget;\n }\n\n return memo[target];\n };\n}();\n\nfunction listToStyles(list, options) {\n var styles = [];\n var newStyles = {};\n\n for (var i = 0; i < list.length; i++) {\n var item = list[i];\n var id = options.base ? item[0] + options.base : item[0];\n var css = item[1];\n var media = item[2];\n var sourceMap = item[3];\n var part = {\n css: css,\n media: media,\n sourceMap: sourceMap\n };\n\n if (!newStyles[id]) {\n styles.push(newStyles[id] = {\n id: id,\n parts: [part]\n });\n } else {\n newStyles[id].parts.push(part);\n }\n }\n\n return styles;\n}\n\nfunction addStylesToDom(styles, options) {\n for (var i = 0; i < styles.length; i++) {\n var item = styles[i];\n var domStyle = stylesInDom[item.id];\n var j = 0;\n\n if (domStyle) {\n domStyle.refs++;\n\n for (; j < domStyle.parts.length; j++) {\n domStyle.parts[j](item.parts[j]);\n }\n\n for (; j < item.parts.length; j++) {\n domStyle.parts.push(addStyle(item.parts[j], options));\n }\n } else {\n var parts = [];\n\n for (; j < item.parts.length; j++) {\n parts.push(addStyle(item.parts[j], options));\n }\n\n stylesInDom[item.id] = {\n id: item.id,\n refs: 1,\n parts: parts\n };\n }\n }\n}\n\nfunction insertStyleElement(options) {\n var style = document.createElement('style');\n\n if (typeof options.attributes.nonce === 'undefined') {\n var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;\n\n if (nonce) {\n options.attributes.nonce = nonce;\n }\n }\n\n Object.keys(options.attributes).forEach(function (key) {\n style.setAttribute(key, options.attributes[key]);\n });\n\n if (typeof options.insert === 'function') {\n options.insert(style);\n } else {\n var target = getTarget(options.insert || 'head');\n\n if (!target) {\n throw new Error(\"Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.\");\n }\n\n target.appendChild(style);\n }\n\n return style;\n}\n\nfunction removeStyleElement(style) {\n // istanbul ignore if\n if (style.parentNode === null) {\n return false;\n }\n\n style.parentNode.removeChild(style);\n}\n/* istanbul ignore next */\n\n\nvar replaceText = function replaceText() {\n var textStore = [];\n return function replace(index, replacement) {\n textStore[index] = replacement;\n return textStore.filter(Boolean).join('\\n');\n };\n}();\n\nfunction applyToSingletonTag(style, index, remove, obj) {\n var css = remove ? '' : obj.css; // For old IE\n\n /* istanbul ignore if */\n\n if (style.styleSheet) {\n style.styleSheet.cssText = replaceText(index, css);\n } else {\n var cssNode = document.createTextNode(css);\n var childNodes = style.childNodes;\n\n if (childNodes[index]) {\n style.removeChild(childNodes[index]);\n }\n\n if (childNodes.length) {\n style.insertBefore(cssNode, childNodes[index]);\n } else {\n style.appendChild(cssNode);\n }\n }\n}\n\nfunction applyToTag(style, options, obj) {\n var css = obj.css;\n var media = obj.media;\n var sourceMap = obj.sourceMap;\n\n if (media) {\n style.setAttribute('media', media);\n }\n\n if (sourceMap && btoa) {\n css += \"\\n/*# sourceMappingURL=data:application/json;base64,\".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), \" */\");\n } // For old IE\n\n /* istanbul ignore if */\n\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n while (style.firstChild) {\n style.removeChild(style.firstChild);\n }\n\n style.appendChild(document.createTextNode(css));\n }\n}\n\nvar singleton = null;\nvar singletonCounter = 0;\n\nfunction addStyle(obj, options) {\n var style;\n var update;\n var remove;\n\n if (options.singleton) {\n var styleIndex = singletonCounter++;\n style = singleton || (singleton = insertStyleElement(options));\n update = applyToSingletonTag.bind(null, style, styleIndex, false);\n remove = applyToSingletonTag.bind(null, style, styleIndex, true);\n } else {\n style = insertStyleElement(options);\n update = applyToTag.bind(null, style, options);\n\n remove = function remove() {\n removeStyleElement(style);\n };\n }\n\n update(obj);\n return function updateStyle(newObj) {\n if (newObj) {\n if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {\n return;\n }\n\n update(obj = newObj);\n } else {\n remove();\n }\n };\n}\n\nmodule.exports = function (list, options) {\n options = options || {};\n options.attributes = typeof options.attributes === 'object' ? options.attributes : {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of diff --git a/apps/settings/src/components/AppList.vue b/apps/settings/src/components/AppList.vue new file mode 100644 index 0000000000..3e40eeb5fb --- /dev/null +++ b/apps/settings/src/components/AppList.vue @@ -0,0 +1,201 @@ + + + + + diff --git a/apps/settings/src/components/AppList/AppItem.vue b/apps/settings/src/components/AppList/AppItem.vue new file mode 100644 index 0000000000..6b66163cfe --- /dev/null +++ b/apps/settings/src/components/AppList/AppItem.vue @@ -0,0 +1,179 @@ + + + + + + + diff --git a/apps/settings/src/components/AppList/AppScore.vue b/apps/settings/src/components/AppList/AppScore.vue new file mode 100644 index 0000000000..810a8b54e8 --- /dev/null +++ b/apps/settings/src/components/AppList/AppScore.vue @@ -0,0 +1,38 @@ + + + + diff --git a/apps/settings/src/components/AppManagement.vue b/apps/settings/src/components/AppManagement.vue new file mode 100644 index 0000000000..4de40728c5 --- /dev/null +++ b/apps/settings/src/components/AppManagement.vue @@ -0,0 +1,138 @@ + + + diff --git a/apps/settings/src/components/AuthToken.vue b/apps/settings/src/components/AuthToken.vue index fb5a331b72..034efc4b6a 100644 --- a/apps/settings/src/components/AuthToken.vue +++ b/apps/settings/src/components/AuthToken.vue @@ -23,31 +23,29 @@ -
    +
    - {{iconName.name}} - ({{ t('settings', 'Marked for remote wipe') }}) + ref="input" + v-model="newName" + type="text" + @keyup.enter="rename" + @blur="cancelRename" + @keyup.esc="cancelRename"> + {{ iconName.name }} + ({{ t('settings', 'Marked for remote wipe') }}) - {{lastActivityRelative}} + {{ lastActivityRelative }} + }" + :open.sync="actionOpen"> @@ -91,7 +89,7 @@ import { Actions, ActionButton, ActionCheckbox -} from 'nextcloud-vue'; +} from 'nextcloud-vue' const userAgentMap = { ie: /(?:MSIE|Trident|Trident\/7.0; rv)[ :](\d+)/, @@ -106,18 +104,18 @@ const userAgentMap = { // Android Chrome user agent: https://developers.google.com/chrome/mobile/docs/user-agent androidChrome: /Android.*(?:; (.*) Build\/).*Chrome\/(\d+)[0-9.]+/, iphone: / *CPU +iPhone +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */, - ipad: /\(iPad\; *CPU +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */, - iosClient: /^Mozilla\/5\.0 \(iOS\) (ownCloud|Nextcloud)\-iOS.*$/, - androidClient: /^Mozilla\/5\.0 \(Android\) ownCloud\-android.*$/, - iosTalkClient: /^Mozilla\/5\.0 \(iOS\) Nextcloud\-Talk.*$/, - androidTalkClient: /^Mozilla\/5\.0 \(Android\) Nextcloud\-Talk.*$/, + ipad: /\(iPad; *CPU +OS +([0-9]+)_(?:[0-9_])+ +like +Mac +OS +X */, + iosClient: /^Mozilla\/5\.0 \(iOS\) (ownCloud|Nextcloud)-iOS.*$/, + androidClient: /^Mozilla\/5\.0 \(Android\) ownCloud-android.*$/, + iosTalkClient: /^Mozilla\/5\.0 \(iOS\) Nextcloud-Talk.*$/, + androidTalkClient: /^Mozilla\/5\.0 \(Android\) Nextcloud-Talk.*$/, // DAVdroid/1.2 (2016/07/03; dav4android; okhttp3) Android/6.0.1 davDroid: /DAV(droid|x5)\/([0-9.]+)/, // Mozilla/5.0 (U; Linux; Maemo; Jolla; Sailfish; like Android 4.3) AppleWebKit/538.1 (KHTML, like Gecko) WebPirate/2.0 like Mobile Safari/538.1 (compatible) webPirate: /(Sailfish).*WebPirate\/(\d+)/, // Mozilla/5.0 (Maemo; Linux; U; Jolla; Sailfish; Mobile; rv:31.0) Gecko/31.0 Firefox/31.0 SailfishBrowser/1.0 sailfishBrowser: /(Sailfish).*SailfishBrowser\/(\d+)/ -}; +} const nameMap = { ie: t('setting', 'Internet Explorer'), edge: t('setting', 'Edge'), @@ -134,7 +132,7 @@ const nameMap = { davDroid: 'DAVdroid', webPirate: 'WebPirate', sailfishBrowser: 'SailfishBrowser' -}; +} const iconMap = { ie: 'icon-desktop', edge: 'icon-desktop', @@ -151,10 +149,10 @@ const iconMap = { davDroid: 'icon-phone', webPirate: 'icon-link', sailfishBrowser: 'icon-link' -}; +} export default { - name: "AuthToken", + name: 'AuthToken', components: { Actions, ActionButton, @@ -163,91 +161,93 @@ export default { props: { token: { type: Object, - required: true, + required: true } }, - computed: { - lastActivityRelative () { - return OC.Util.relativeModifiedDate(this.token.lastActivity * 1000); - }, - lastActivity () { - return OC.Util.formatDate(this.token.lastActivity * 1000, 'LLL'); - }, - iconName () { - // pretty format sync client user agent - let matches = this.token.name.match(/Mozilla\/5\.0 \((\w+)\) (?:mirall|csyncoC)\/(\d+\.\d+\.\d+)/); - - let icon = ''; - if (matches) { - this.token.name = t('settings', 'Sync client - {os}', { - os: matches[1], - version: matches[2] - }); - icon = 'icon-desktop'; - } - - // preserve title for cases where we format it further - const title = this.token.name; - let name = this.token.name; - for (let client in userAgentMap) { - if (matches = title.match(userAgentMap[client])) { - if (matches[2] && matches[1]) { // version number and os - name = nameMap[client] + ' ' + matches[2] + ' - ' + matches[1]; - } else if (matches[1]) { // only version number - name = nameMap[client] + ' ' + matches[1]; - } else { - name = nameMap[client]; - } - - icon = iconMap[client]; - } - } - if (this.token.current) { - name = t('settings', 'This session'); - } - - return { - icon, - name, - }; - }, - wiping() { - return this.token.type === 2; - } - }, - data () { + data() { return { showMore: this.token.canScope || this.token.canDelete, renaming: false, newName: '', - actionOpen: false, - }; + actionOpen: false + } + }, + computed: { + lastActivityRelative() { + return OC.Util.relativeModifiedDate(this.token.lastActivity * 1000) + }, + lastActivity() { + return OC.Util.formatDate(this.token.lastActivity * 1000, 'LLL') + }, + iconName() { + // pretty format sync client user agent + let matches = this.token.name.match(/Mozilla\/5\.0 \((\w+)\) (?:mirall|csyncoC)\/(\d+\.\d+\.\d+)/) + + let icon = '' + if (matches) { + /* eslint-disable-next-line */ + this.token.name = t('settings', 'Sync client - {os}', { + os: matches[1], + version: matches[2] + }) + icon = 'icon-desktop' + } + + // preserve title for cases where we format it further + const title = this.token.name + let name = this.token.name + for (let client in userAgentMap) { + const matches = title.match(userAgentMap[client]) + if (matches) { + if (matches[2] && matches[1]) { // version number and os + name = nameMap[client] + ' ' + matches[2] + ' - ' + matches[1] + } else if (matches[1]) { // only version number + name = nameMap[client] + ' ' + matches[1] + } else { + name = nameMap[client] + } + + icon = iconMap[client] + } + } + if (this.token.current) { + name = t('settings', 'This session') + } + + return { + icon, + name + } + }, + wiping() { + return this.token.type === 2 + } }, methods: { startRename() { // Close action (popover menu) - this.actionOpen = false; + this.actionOpen = false - this.newName = this.token.name; - this.renaming = true; + this.newName = this.token.name + this.renaming = true this.$nextTick(() => { - this.$refs.input.select(); - }); + this.$refs.input.select() + }) }, cancelRename() { - this.renaming = false; + this.renaming = false }, revoke() { - this.actionOpen = false; + this.actionOpen = false this.$emit('delete', this.token) }, rename() { - this.renaming = false; - this.$emit('rename', this.token, this.newName); + this.renaming = false + this.$emit('rename', this.token, this.newName) }, wipe() { - this.actionOpen = false; - this.$emit('wipe', this.token); + this.actionOpen = false + this.$emit('wipe', this.token) } } } diff --git a/apps/settings/src/components/AuthTokenList.vue b/apps/settings/src/components/AuthTokenList.vue index a7c0faf1b7..65f42197ed 100644 --- a/apps/settings/src/components/AuthTokenList.vue +++ b/apps/settings/src/components/AuthTokenList.vue @@ -22,67 +22,67 @@ + diff --git a/apps/updatenotification/src/components/root.vue b/apps/updatenotification/src/components/root.vue deleted file mode 100644 index 0f6a427bb3..0000000000 --- a/apps/updatenotification/src/components/root.vue +++ /dev/null @@ -1,508 +0,0 @@ - - - - - - diff --git a/apps/updatenotification/src/init.js b/apps/updatenotification/src/init.js index d874cb67f3..19782799db 100644 --- a/apps/updatenotification/src/init.js +++ b/apps/updatenotification/src/init.js @@ -18,23 +18,22 @@ * */ -/* global define, $ */ -import Vue from 'vue'; -import Root from './components/root' +import Vue from 'vue' +import Root from './components/UpdateNotification' Vue.mixin({ methods: { t: function(app, text, vars, count, options) { - return OC.L10N.translate(app, text, vars, count, options); + return OC.L10N.translate(app, text, vars, count, options) }, n: function(app, textSingular, textPlural, count, vars, options) { - return OC.L10N.translatePlural(app, textSingular, textPlural, count, vars, options); + return OC.L10N.translatePlural(app, textSingular, textPlural, count, vars, options) } } -}); +}) -const vm = new Vue({ +// eslint-disable-next-line no-new +new Vue({ + el: '#updatenotification', render: h => h(Root) -}).$mount('#updatenotification'); - - +}) diff --git a/apps/user_ldap/js/wizard/wizardTabGeneric.js b/apps/user_ldap/js/wizard/wizardTabGeneric.js index 7b0df4992d..f24c520c1f 100644 --- a/apps/user_ldap/js/wizard/wizardTabGeneric.js +++ b/apps/user_ldap/js/wizard/wizardTabGeneric.js @@ -392,9 +392,9 @@ OCA = OCA || {}; /** * @typedef {object} viewSaveInfo - * @property {function} val - * @property {function} attr - * @property {function} is + * @property {Function} val + * @property {Function} attr + * @property {Function} is */ /** diff --git a/apps/workflowengine/js/workflowengine.js b/apps/workflowengine/js/workflowengine.js index 2143a2afe6..ff40c80118 100644 Binary files a/apps/workflowengine/js/workflowengine.js and b/apps/workflowengine/js/workflowengine.js differ diff --git a/apps/workflowengine/js/workflowengine.js.map b/apps/workflowengine/js/workflowengine.js.map index 16c62805db..db7d112b8d 100644 Binary files a/apps/workflowengine/js/workflowengine.js.map and b/apps/workflowengine/js/workflowengine.js.map differ diff --git a/apps/workflowengine/src/components/Check.vue b/apps/workflowengine/src/components/Check.vue index 06667b1a7e..4f68e39449 100644 --- a/apps/workflowengine/src/components/Check.vue +++ b/apps/workflowengine/src/components/Check.vue @@ -1,19 +1,36 @@ diff --git a/apps/workflowengine/src/components/Checks/FileSystemTag.vue b/apps/workflowengine/src/components/Checks/FileSystemTag.vue index e2f66b30a4..d3fd440f1b 100644 --- a/apps/workflowengine/src/components/Checks/FileSystemTag.vue +++ b/apps/workflowengine/src/components/Checks/FileSystemTag.vue @@ -21,7 +21,8 @@ --> diff --git a/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue b/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue index 88b56a1d4e..020ed95873 100644 --- a/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue +++ b/apps/workflowengine/src/components/Checks/MultiselectTag/MultiselectTag.vue @@ -22,13 +22,17 @@ diff --git a/apps/workflowengine/src/components/Checks/RequestUserGroup.vue b/apps/workflowengine/src/components/Checks/RequestUserGroup.vue index 843bbf127e..ccd556c99c 100644 --- a/apps/workflowengine/src/components/Checks/RequestUserGroup.vue +++ b/apps/workflowengine/src/components/Checks/RequestUserGroup.vue @@ -23,9 +23,11 @@ diff --git a/apps/workflowengine/src/components/Event.vue b/apps/workflowengine/src/components/Event.vue index ea153758c7..a06835f5f8 100644 --- a/apps/workflowengine/src/components/Event.vue +++ b/apps/workflowengine/src/components/Event.vue @@ -4,9 +4,14 @@ {{ operation.triggerHint }}
    - +